npm Community Forum (Archive)

The npm community forum has been discontinued.

To discuss usage of npm, visit the GitHub Support Community.

Cannot differentiate initiator in postinstall script

What I Wanted to Do

Determine which npm command caused the postinstall script to run.

What Happened Instead

Many commands run the postinstall script, and there’s no formal way to determine which. Some commands set npm_config_* environment variables, like npm_config_argv, which can be parsed to determine this. Some commands do not, like ci, install-ci-test, cit, install-test, etc.

Reproduction Steps

npm install, npm ci, with postinstall script


In this scenario, it seems postinstall is being used as part of a build/development workflow, where issuing npm install in the “top-level” package/module should also issue npm install in “nested” package/modules. Perhaps this is a poor usage of postinstall script and its intended use should be clarified.

Platform Info

$ npm --versions
{ npm: '6.8.0',
  ares: '1.15.0',
  cldr: '33.1',
  http_parser: '2.8.0',
  icu: '62.1',
  modules: '64',
  napi: '3',
  nghttp2: '1.34.0',
  node: '10.15.1',
  openssl: '1.1.0j',
  tz: '2018e',
  unicode: '11.0',
  uv: '1.23.2',
  v8: '',
  zlib: '1.2.11' }
$ node -p process.platform

See also:

(I have moved topic to #support to see what responses you get, as I don’t think this is a bug as such.)

I am not sure what your goal is. Do you want to know the calling context (npm command) because you want to change the commands you run in the postinstall based on the context?

Correct. Thank you for clarifying. i.e. npm ci in top-level package causes npm ci to be issued in the nested packages.

Not sure about how sensible your workflow is, but interested in the problem. :slight_smile:

Checking npm_config_argv looks like your best option (as you suggested). I do see this being set for npm install-test in a toy package, so wasn’t able to reproduce that part of your description.

However, I reproduced npm_config_argv missing for npm ci in npm 6.8.0 and 6.9.0 although was being set in 6.4.1.

With the extra information, I found this open bug. I suggest you vote on this:

I worked around this issue by not using preinstall and postinstall as part of the development process. Instead I created a separate script, npm run bootstrap and updated development documentation, which performs this function. It’s slightly less good in that a developer can’t simply run npm install, but I think that is fallible anyway.

The issue regarding npm config (environment vars) for ci/cit/… still stands, and the issue about preinstall and postinstall's documentation (when do these run, how are they expected to be used / not used) still stands (e.g. npm prune runs these *install lifecycle scripts…)

I’m not certain of the purpose of your script, but in general, postinstall is not the recommended lifecycle hook. As you noted, postinstall is run for lots of various commands, and should mostly be reserved for compilation of native code that is architecture-specific. (Or for fetching of assets that, for one reason or another, can’t be bundled with the published tarball.)

By far the most common lifecycle script that should be used is prepare, which is run before npm-pack (and therefore, also before npm-publish). It is also run for “bare”/“top-level” npm-installs. (ie after a git-clone, in the package itself). Notably, prepare is also run when your package is listed as a git dependency of another package. That is, when the script is used to generate assets that should be published and are necessary for operation (ie, the compilation of typescript into javascript). These assets are not committed to the git repo, so if installed as a git dependency, the compilation must occur during installation.

Can you provide some more insight into what exactly the script is doing?

Tangentially related, I have a script that is used to determine if a given installation is the result of a direct request for the package, or is being installed as a transitive dependency.

(For instance, say the package foo has an install script which needs to distinguish npm install foo from npm install bar where bar depends on foo.) It makes the distinction by checking if npm_config_argv (array of arguments that were passed to npm cli by the user) contains the package name.