I'm trying to create an npm module that has a postinstall
script that will modify the user's package.json
and re-install packages. I'm almost there, but the problem I'm having is that the npm CLI runs my postinstall
script too early.
Is there a way, maybe by using Node or system level trick, to wait for the whole npm install
process to exit before my script runs? Like when npm calls my postinstall
script, at that time I can register another script to run after npm install
finishes?
What do I mean by "too early"? For example, after yarn install
, the yarn.lock
file will not accurately reflect the package.json
if my script interferes with yarn install
. However, if my script waits for yarn install
to completely finish and then runs another yarn install
, the yarn.lock
file will be accurate and further yarn install
commands will output "Already up-to-date".
You can easily run scripts using npm by adding them to the "scripts" field in package. json and run them with npm run <script-name> . Run npm run to see available scripts. Binaries of locally install packages are made available in the PATH , so you can run them by name instead of pointing to node_modules/.
The working directory for the postInstall script is / (root), which means if you include a command like mkdir mylibrary to create a folder, when you later need to refer to that folder, it'll be available at /mylibrary .
The postinstall script creates the backout package using the information provided by the other scripts. Since the pkgmk and pkgtrans commands do not require the package database, they can be executed within a package installation.
Considering tampering directly with the package.json is bad practice, because Devs will no longer be in control of the packages they have installed, or even their project name.
Therefore, packages should instead request the Dev to change the package.json during installation and offer a method to enable Devs for a dry-run of the changes that will be made.
TLDR; make sure to give full consent to the Dev for any tampering of the package.json.
That's why I think alternative methods are better than using a postinstall script. The most minimal solution I have come up with:
myinstall.js
const exec = require('child_process').exec; exec('npm run install').on('exit', () => exec('npm run mypostinstall'));
package.json
"scripts": { "myinstall": "node myinstall.js", "mypostinstall": "echo \"myPostinstall called\"" },
Set the mypostinstall
script equal to the postinstall
.
Note: in the example above there is no error handling, no text is displayed and there is no actual write to the package.json. It is pure for illustration on how to do execute code after npm install
. The reason no text is being displayed is due calling exec
, for which a new process is called with it's "personal" stdout. Alternatively use fork
, more info can be found here at the node documentation.
I have attempted to call npm install
instead of npm run myinstall
by setting "install": "node myinstall.js"
. However now the exec('npm run install')
will recursively call itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With