19

I developed a npm package ("node_commons") which is included in my other project like this:

package.json (other project)

"node-commons": "git+ssh://git@stash.custom.domain.net:7999/npm/libs/node_commons.git"

The node_commons package is written in ES6 but this version is not supported later, therefore I use a postinstall script to transpile it with babel.

package.json (node_commons)

"postinstall": "babel src -d src"

This works fine. When the package is included as dependency in my project, the files are transpiled.

My problem: When I develop the node_commons package I use npm install to install the internal dependencies. But then I do not want to transpile it. I only want to transpile, when the package is installed as dependency (e.g. in my other project). Is there a way to do this?

Something like this:

package.json (node_commons)

"postinstall-as-dependency": "babel src -d src"
Kewitschka
  • 1,445
  • 1
  • 21
  • 35
  • 3
    I was wondering the same thing. This is ridiculous. There should be two different lifecycle hooks for these two scenarios because they are completely different tasks. – m4heshd Feb 03 '21 at 04:48

6 Answers6

7
  • Create .no-postinstall file in module root.
  • Mac & Linux: Add following to package.json: "postinstall": "if [ ! -e .no-postinstall ]; then babel src -d src; fi"
  • Windows: Add following to package.json: "postinstall": if exist .no-postinstall () else (babel src -d src)"
  • Cross Platform (more work): You can create a node script (i.e. ./my-script.js) and using fs module, check existence of .no-postinstall and execute babel src -d src using child_process.exec() as described in official doc here. Add your script to package.json: "postinstall": node my-script.js

Please note that I use Mac, so I can't verify Windows version.

Explanation

if [ ! -e .no-postinstall ] checks non-existence (with negation operator !) of given file. If file does not exist, it executes your script. Since you add .no-postinstall file to your module root, script does not get executed when you install your internal modules. On the other hand, modules installing your module as a dependency do not have .no-postinstall file in their root and your script get executed.

.no-postinstall is not a special name, you can use whatever name you choose.

özüm
  • 1,166
  • 11
  • 23
  • 2
    it's no use. because npm script always runs with package root as its CWD. https://docs.npmjs.com/cli/v6/commands/npm-run-script – Zim May 07 '21 at 09:32
  • 1
    Just add it to `.npmignore` then. It will work better like that than as originally posted. – GregRos Feb 06 '22 at 16:55
4

In my case, I had a postinstall script that I only wanted to run when the package was NOT installed as a dependency.

Here is the package.json script I used:

{
    [...]
    "scripts": {
        "@comment_postinstall": "Behavior of the node-js subscript below: if '.git' doesn't exist under my-lib, it's installed as a dep, so do nothing -- else, return error-code 1, causing patch-package to run.",
        "postinstall": "node -e \"let myLibAsDep = !require('fs').existsSync('.git'); if (!myLibAsDep) process.exit(1);\" || patch-package"
    },
    [...]
}

You can of course just reverse the if (!myLibAsDep) if you want your script to run only when installed as a dependency.

Venryx
  • 15,624
  • 10
  • 70
  • 96
3

If I understand correctly, you want your package to run a postinstall script only if user install it as a dependency (npm install node-common)?

When your postinstall script runs, it has the npm_config_save_dev available to it, which is 'true' when users install the package with the --save-dev flag:

"postinstall": "! [ $npm_config_save_dev ] && echo \"Installed as a dependency\" || \"Installed as a dev dependency\""
Derek Nguyen
  • 11,294
  • 1
  • 40
  • 64
2

I had the same issue, I had a postinstall script which I wanted to run only when the package is installed as a dependency.

At the top of my postinstall script I added:

if (!process.cwd().includes('node_modules')) {
 return;
}

and then it only ran when the module existed under a node_modules dir.

Amir Yonatan
  • 717
  • 1
  • 7
  • 14
  • Can work in most cases, but I assume some cases would fail. (eg. if there a dependency under the parent project as well as under your lib, and the versions are incompatible, then your lib will have its own `node_modules` folder for it, even when your lib is installed as a dependency) That said, you can modify the if-statement to check for a specific dependency of your lib that you know the parent project will never have, and that thus would only be under your lib when your lib is not installed as a dependency. – Venryx Aug 25 '21 at 00:26
  • I found an even better way: just check for the existence of a `.git` folder in your lib's directory. If it doesn't exist, it means your lib is installed as a dependency (well, assuming you're using git when developing your library -- which is nearly everyone I reckon). Full solution here: https://stackoverflow.com/a/68915638/2441655 – Venryx Aug 25 '21 at 01:08
2

This should do the trick:

if (process.env.INIT_CWD === process.cwd())
  process.exit()

Works with npm and pnpm. Don't know about yarn

https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices

wiwolavida
  • 81
  • 4
  • This is the best technique presented so far: it does not rely on any files in the package, doesn't rely on node_modules, doesn't rely on git. Will always work in all cases. – Achronos Aug 16 '23 at 11:41
0

I created a package to solve this problem, inspired by the answer from @venryx.

https://github.com/douglasjunior/ignore-dependency-scripts

Usage

Replace this:

  // package.json

  "name": "my-library",
  "scripts:" { 
    // "start", "test", "build", etc
    "postinstall/preinstall/prepare/etc": "your && scripts && here"
  },

With this:

  // package.json

  "name": "my-library",
  "scripts:" { 
    // "start", "test", "build", etc
    "postinstall/preinstall/prepare/etc": "npx --yes ignore-dependency-scripts \"your && scripts && here\""
  },

Replace your && scripts && here by any post/pre install script that you want, like husky install, npx pod-install or both.

Now, when you run yarn install or npm install in ./my-library the your && scripts && here will run normally.

But, when you install my-library as a dependency (aka yarn add url/to/my-library.git) in another repository, the your && scripts && here will be ignored.