2

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

  • node 4.x and older -> websockets 1.0.24
  • all other node versions -> websockets 1.0.31

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.

CoryCoolguy
  • 1,065
  • 8
  • 18
vidstige
  • 12,492
  • 9
  • 66
  • 110
  • 1
    Not that I'm aware of, but also is Node 4 or earlier worth supporting? Node 10 is the oldest that's still getting support and updates: https://nodejs.org/en/about/releases/ – jonrsharpe Mar 07 '20 at 15:23

1 Answers1

1

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 websocket@x.x.x 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 websocket@x.x.x 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.

RobC
  • 22,977
  • 20
  • 73
  • 80
  • Also because this is essentially a workaround (for want of a better word) for NPM not having a specific built-in feature to install different packages depending on node version, then any reporting tools, such as [this](https://npm.anvaka.com/#/) or [www.npmjs.com](https://www.npmjs.com/) itself will not formally show/list `websocket` as a dependency - simply because it's not going to be listed in your project's _package.json_ file. – RobC Mar 09 '20 at 15:09