vidstige
vidstige

Reputation: 13085

Install different packages depending on node version

I have a project that depends on the websocket package. However, for node 10.x, the latest version (1.0.31) of websocket works, while on node 4.x version 10.0.24 works but the 10.0.31 does not. Is it possible to specify different package (versions) per nodejs version to handle cases like this, e.g. like so

Preferable it should work in both npm and yarn, but if it only works in either that's fine as well.

The node 10 version is used in dev setups, while the node 4.x is used in a legacy embedded platform that cannot run docker or be upgraded.

Upvotes: 2

Views: 1189

Answers (1)

RobC
RobC

Reputation: 25042

Consider utilizing a postinstall script in the scripts section of your projects package.json. For instance:

package.json

"scripts": {
  "postinstall": "node install-websocket"
},

As you can see, the postinstall script invokes a nodejs script, arbitrarily named install-websocket.js.

install-websocket.js

const execSync = require('child_process').execSync;

const nodeMajorVersion = process.version.replace(/^v/, '').split('.')[0];
const websocketVersion = nodeMajorVersion <= '4' ? '1.0.24' : '1.0.31';

execSync('npm install websocket@' + websocketVersion, {
    cwd: __dirname,
    stdio: 'inherit'
});

The install-websocket.js script essentially performs the following tasks:

  1. Gets the version of node.js using process.version which returns a string, e.g. v13.10.1

    To obtain the Major version from that string (i.e. 13 in that aforementioned example) we use a combination of the replace() and split() methods.

  2. The conditional (ternary) operator ascertains which version of websocket to subsequently install - based on whether the value of nodeMajorVersion is <= 4.

  3. Finally we "shell out" the appropriate npm install [email protected] command using execSync.

    Note: If you're concerned about execSync being synchronous, then utilize the asynchronous exec instead.


Additional Notes:

  • Given the code shown above it assumes the install-websocket.js file resides in the root of your project directory, i.e. at the same level as package.json.

    my-project
    ├── package.json
    ├── install-websocket.js
    └── ...
    

    It's important for the install-websocket.js file to exist at this location for following two reasons:

    1. Primarily, and most importantly, because you'll have noticed that we specify __dirname for the value of execSync's cwd option. The value of __dirname in this context is the pathame to the parent directory of wherever the install-websocket.js file resides.

      Essentially by setting the cwd option to this specific pathname, (i.e. the path to the project directory), we ensure that when the npm install [email protected] command is run it gets installed in the same location as where your project resides - regardless of whether it's installed locally or globally.

    2. The postinstall script in package.json expects the install-websocket.js file to reside there too. Note how it currently runs; node install-websocket, and doesn't assume the file exists elsewhere, i.e. it's not running something like: node ./some/path/to/install-websocket

  • If consumers of your package have npm configured to ignore-scripts then websocket's simply will not be installed because the postinstall script will not be invoked.

Upvotes: 1

Related Questions