Npm: Run postinstall script only when installed as dependency

Viewed 4539

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"
4 Answers
  • 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.

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\""

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.

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.

Related