7

Trying to bind a script called license-checker to npm commands following these instructions I came up with this snippet in my package.json

{
  "scripts": {
    "postinstall": "license-checker --json --out license-list.json",
    "poststart": "license-checker --json --out license-list.json"
  },

Doesn't work. Running the command manually does generate the licence-list.json file, but not when installing a package (npm i package-name --save). Why not?

Note: I'm trying to run this script when (1) installing a new package into the project, and also when (2) building the project for deployment. However there's nothing about build in the docs: can I use start or poststart for that as I tried to or if not, what can I use instead?

drake035
  • 3,955
  • 41
  • 119
  • 229
  • 1
    Regarding _"run this script when (1) installing a new package into the project"_ - unfortunately npm does provide a built-in feature to achieve this. If you're using _*nix_ then consider overriding the `npm install --save` command at the shell level, as explained in my answer [here](https://stackoverflow.com/questions/59934610/run-a-script-like-postinstall-after-npm-installing-a-single-package/60096171#60096171). – RobC Aug 10 '20 at 07:40

3 Answers3

0

As per the npm documentation (https://docs.npmjs.com/misc/scripts), the postinstall script is invoked when the package is installed so the postinstall script will invoke when you call

npm install

It won't be called when you invoke

npm i package-name --save

Maybe you can do the check once the package is installed.

Edit: If the purpose of this is to check what is being added to package.json maybe doing a pre-commit check/hooks will be a better idea aka using something like https://www.npmjs.com/package/husky

manishg
  • 9,520
  • 1
  • 16
  • 19
  • 1
    I want for Git hooks indeed, turns out Vue (my App is Vue-based) natively incorporates aversion of Husky – drake035 Aug 12 '20 at 09:15
0

You can try out hook-scripts.

From docs :

If you want to run a specific script at a specific lifecycle event for ALL packages, then you can use a hook script.

Place an executable file at node_modules/.hooks/{eventname}, and it’ll get run for all packages when they are going through that point in the package lifecycle for any packages installed in that root.

Hook scripts are run exactly the same way as package.json scripts. That is, they are in a separate child process, with the env described above.

Edit

Example:

I tried this on Windows 10, Node 12.18.0 and NPM 6.14.4

  1. I created a bat file at node_modules/.hooks/ having content:
call node -e "console.log('Hello, I got executed from .hooks folder.')"
  1. Then ran npm i ng-bootstrap --save

Hook script got executed. Check screenshot below. enter image description here

Note : As pointed by @RobC, This script will be executed for each of the transitive dependencies of the package being installed.

Smile
  • 3,832
  • 3
  • 25
  • 39
  • This won't run the script when installing new individual packages, if I understand correctly [this answer](https://stackoverflow.com/a/60096171/871404) by @RobC – drake035 Aug 10 '20 at 10:12
  • @drake035 No, it will run for installing individual packages also. I have edited my answer to show example which I tried. And the documentation clearly states `If you want to run a specific script at a specific lifecycle event for ALL packages, then you can use a hook script.`. – Smile Aug 10 '20 at 12:38
  • @Smile - I see that `ng-bootstrap` has nothing defined in the `dependencies` section of its [package.json](https://github.com/valor-software/ngx-bootstrap/blob/development/package.json), so presumably this is why your _postinstall_ script is invoked only once. However if you run; `npm i eslint --save` _(note: eslint does have packages listed in the `dependencies` section of its [package.json](https://github.com/eslint/eslint/blob/master/package.json))_ then presumably your _postinstall_ script is invoked multiple times, i.e. it's invoked for each and every transitive dependency installed too. – RobC Aug 10 '20 at 15:09
  • Does that mean that you were incorrect when stating that it's not possible to bind a script to the installation of individual packages @RobC? – drake035 Aug 10 '20 at 15:52
  • @drake035 - it depends on what you define as an "individual package". Let's say you install a single package, e.g. eslint by running `npm i eslint --save`. My understanding of your requirement is that when e.g. eslint (and all it's transitive dependencies) has installed you want your _postinstall_ script to run once on completion. However, as eslint has multiple transitive dependencies (as you can see [here](http://npm.anvaka.com/#!/view/2d/eslint)) your _postinstall_ script will be run multiple times, i.e. it will run after each and every single transitive dependency is installed. Try it! – RobC Aug 10 '20 at 16:14
  • @drake035 - In summary... as you can see [here](http://npm.anvaka.com/#!/view/2d/eslint) eslint (for example) has a total of 107 nodes, which is essentially a total of 107 x transitive dependencies which are required to be installed for eslint to work. So, when you run `npm i eslint --save` your _postinstall_ script (i.e. whatever executable is defined in `node_modules/.hooks/`) will be invoked 107 times throughout the installation of eslint, and _not_ invoked just once upon completion. Note: I use eslint as an example, however typically npm packages have multiple transitive dependencies. – RobC Aug 10 '20 at 16:43
  • @RobC That is indeed true, script will run for each of the transitive dependencies. Not sure but may be some solution to run the script only once can be found by using `process.env` variables. – Smile Aug 11 '20 at 05:04
  • @Smile - Yes, you can attempt to infer from the environment variables when the last pkg is installed in an effort to make the _postinstall_ hook logic run only once at the end. This [example postinstall](https://paste.ee/p/1o6mx) `.js` script demos this. However it has limitations, as noted in the _CAVEAT_ section at the bottom. Also, **1)** The script still has to be processed after each transitive dependency is installed, thus increasing install times. **2)** When someone runs just `npm install` the _postinstall_ hook logic still has to be processed. Personally, I'm not a fan of this method. – RobC Aug 11 '20 at 13:49
  • "I created a bat file at node_modules/.hooks/ having content:" What filename did you use? If I use the recommended "postinstall" (without extension), Windows doesn't know how to run the file, correct? – Venryx Mar 26 '21 at 15:03
  • @Venryx Yes windows might recognize that file, you can simply edit with any text editor and let node run it – Smile Mar 27 '21 at 04:25
0

I dont tryed but, you can use a build script there you can use your commands by the way you aimed. by using the && operator. For example:

"build": "npm run compile && npm run theme:build && npm run webpack:admin",

In your case like that:

"postinstall": "license-checker --json --out license-list.json",
"poststart": "license-checker --json --out license-list.json"
"build": "npm run poststart && npm run postinstall && npm run newpocket -save",

this is not exactly what you wanted but a manner for making it.

Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35