52

Whenever I run npm install <package> it installs the package alright, but then it automatically runs the prepare script.

It's worth mentioning that I've already checked that there is no postinstall script in the package.json.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Alex Zak
  • 1,924
  • 2
  • 18
  • 26
  • 1
    Mind showing us some info in the package.json and show us the terminal when you run the command? It's hard to tell when we have nothing to go off of. – Andrew Li Jun 12 '17 at 12:51
  • 1
    Possible duplicate of [npm: disable postinstall script for package](https://stackoverflow.com/questions/23505318/npm-disable-postinstall-script-for-package) – user7610 Nov 27 '19 at 13:11
  • Why do you want to stop it? Packages that have a prepare script usually expect it to be run to work properly. – Cameron Tacklind May 03 '22 at 21:32

4 Answers4

36

From https://docs.npmjs.com/misc/scripts:

prepare: Run both BEFORE the package is packed and published, and on local npm install without any arguments (See below). This is run AFTER prepublish, but BEFORE prepublishOnly.

Since NPM v5, prepare script is executed when you run npm install

Yasha
  • 1,017
  • 11
  • 21
  • 2
    "local npm install" is when you `git clone ` and then do `cd thepackage` and run `npm install`, as opposed to when you install the package from the registry with `npm install ` – Boris Verkhovskiy Mar 30 '22 at 20:59
  • Hey @boris! I understand the confusion - I believe the updated NPM docs are more clear about this now - https://docs.npmjs.com/cli/v8/commands/npm-install Specifically "If the package being installed contains a prepare script, its dependencies and devDependencies will be installed, and the prepare script will be run, before the package is packaged and installed." – Yasha Mar 31 '22 at 16:26
31

The other answers are fine, but for some additional context, this is to support a workflow where you can use devDependencies to build assets or other generated content for your project.

For example, say you want to use node-sass (CSS preprocessor). You add "node-sass" as a devDependency, then you run the sass command in your "prepare" script, which generates your CSS.

So, when you run npm install, the following happens:

  • dependencies and devDependencies get installed
  • your "prepare" script generates your CSS
  • your project is ready to go with all necessary CSS

And when you run npm publish, something similar happens:

  • your "prepare" script generates your CSS
  • your code and generated CSS are published to the npm repo

So now when someone comes along and installs your package, they don't need node-sass or any of your devDependencies. They only need to runtime deps.

Rich Remer
  • 2,123
  • 1
  • 21
  • 22
  • 2
    This the only answer here which actually understands and answers the question – OoDeLally Jan 07 '22 at 15:07
  • So this appears to not have a solution than and npm messed this up? Cause this work flawlessly in yarn . – Nick Feb 24 '22 at 22:38
  • Is there anything like prepare that only runs on `npm install` local / relative and not packages which consume the dependency? – Nick Feb 24 '22 at 22:39
  • @Nick if yarn isn't behaving as described here, then yarn is broken. – Rich Remer Mar 12 '22 at 18:36
  • @Nick, if I'm understanding you correctly, `npm install` and "prepare" already does what you describe. "prepare" scripts aren't executed for dependencies because it's expected they were run at time of publish. – Rich Remer Apr 14 '22 at 00:10
  • It’s doesn’t work npm install runs prepare under the hood for all sub dependencies as well on post install. – Nick Apr 15 '22 at 01:20
  • That’s not what I observe in npm maybe it’s a bug in 7.x , haven’t gone to 8 yet thinking about going back to 6 or to pnpm. – Nick Apr 15 '22 at 01:23
  • Wrote this for the exact problem as a work around https://github.com/nmccready/skip-npm-task – Nick Apr 15 '22 at 01:23
25

The prepare script runs on local install and when installing git dependencies:

prepare: Run both BEFORE the package is packed and published, on local npm install without any arguments, and when installing git dependencies (See below). This is run AFTER prepublish, but BEFORE prepublishOnly.

https://docs.npmjs.com/misc/scripts

You can avoid it with the --ignore-scripts flag:

$ npm install <package> --ignore-scripts

source: https://docs.npmjs.com/cli/install

Aleksi
  • 4,483
  • 33
  • 45
Raschid JFR
  • 580
  • 8
  • 15
  • 3
    This can cause other problems. Some packages expect scripts to be run to be usable. This globally disables all scripts, just for this run, and can cause other issues. Be careful! – Cameron Tacklind May 03 '22 at 21:31
6

From the doc https://docs.npmjs.com/misc/scripts

prepare: Run both BEFORE the package is packed and published, and on local npm install without any arguments (See below). This is run AFTER prepublish, but BEFORE prepublishOnly.

prepare script run before publishing and after npm install.

Now if you make an npm install and one of the packages has a prepare script, like for building, and it fails the whole install will fail.

We have two options:

Ignore scripts

npm install --ignore-scripts

That will run the ignore to all packages, which might be not the desired behavior. Imagine a third party package that needs to run prepare and build. If you run with --ignore-scripts this will get skipped.

Make the script optional (better option)

Add a package to the optionalDependencies:

{
   optionalDependencies: {
       "myPackage": "^1.0.0"
   }
}

If a dependency can be used, but you would like npm to proceed if it cannot be found or fails to install, then you may put it in the optionalDependencies object. This is a map of package name to version or url, just like the dependencies object. The difference is that build failures do not cause installation to fail.

Entries in optionalDependencies will override entries of the same name in dependencies, so it's usually best to only put in one place.

Check the doc:

https://docs.npmjs.com/cli/v7/configuring-npm/package-json#optionaldependencies

Note: With this, only the chosen package is concerned. And if it fails the installation will continue. That's usually what you want.

Go with optionalDependencies

As per this answer in this thread:

https://github.com/npm/npm/issues/2817#issuecomment-368661749

the problem with --ignore-scripts is that is ignores all scripts. I just need to be able to ignore a script(s) for a particular package (the one where a build fails to compile on certain platforms). This option usually breaks my code because it has ignored ALL scripts in other packages that actually do need to run.

Anyway, to make this work like the OP I make the offending package optional. Then do a regular install, then a second install with --ignore-scripts. That way I get the scripts of other packages run first before ignoring them all (including the intended) the second time which then "fetches" the source of that package.

It's generally better to go with optionalDependencies. That will most likely suit your needs.

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257
Mohamed Allal
  • 17,920
  • 5
  • 94
  • 97