48

I've got a project where we're trying to get Node up and running across multiple developers' machines. The problem is that not all of the developers are Node (or even JavaScript) developers, and we want to ensure that they have the Node version necessary to run a specific project (developers will have multiple Node projects on their machines).

I read about package.json's "engines" field, but I couldn't seem to find any way to get the version of Node installed that I needed. To test, I set my current node version to v0.10.29 via NVM, created a package.json specifying a necessary engine of v0.11.13, and tried to start Node via the node command as well as via a package.json-defined npm start command.

blackjack:node-engines-test sent1nel$ node -v
v0.10.29
blackjack:node-engines-test sent1nel$ cat package.json
{
  "name": "node-engines-test",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "engineStrict": true,
  "engines": {
    "node": "v0.11.13"
  },
  "start": "node index.js",
  "author": "",
  "license": "ISC"
}
blackjack:node-engines-test sent1nel$ cat index.js
console.log('Version: ' + process.version);
blackjack:node-engines-test sent1nel$ node index.js
Version: v0.10.29
blackjack:node-engines-test sent1nel$ npm start
blackjack:node-engines-test sent1nel$

npm install doesn't seem to care about the node engine version either.

blackjack:node-engines-test sent1nel$ npm install
npm WARN package.json node-engines-test@0.0.0 No description
npm WARN package.json node-engines-test@0.0.0 No repository field.
npm WARN package.json node-engines-test@0.0.0 No README data
blackjack:node-engines-test sent1nel$ node -v
v0.10.29

What gives?!

sent1nel
  • 1,580
  • 1
  • 15
  • 31
  • 1
    Where did you read that specifying `engines` installs, requires or uses a specific Node version? I'm pretty sure all it does it provide information about what version of node is expected - https://www.npmjs.org/doc/package.json.html#engines . If you want to force a version (for whatever reason), you can use `engineStrict` - https://www.npmjs.org/doc/package.json.html#engineStrict – Ian Jul 21 '14 at 16:32
  • As you can see in the above `package.json`, I actually did set the `engineStrict` flag. What I'd assumed would happen was that setting that flag would either install or provide a warning that the wrong version of Node was active which, as you can see from the logs, doesn't happen. – sent1nel Jul 21 '14 at 16:36
  • 1
    If you're using NVM then you need to set everyone's machine to the same version. The simplest way I can think of is to write a shell script that will do all the work. – Andy Jul 21 '14 at 16:40
  • 1
    I'm using `nvm` - I simply want to ensure a warning is displayed so if the developer needs to run `nvm install vx.y.z`, they know what to do. If nothing exists, I have code to write. – sent1nel Jul 21 '14 at 16:41
  • 2
    Fair enough, thanks (wtf is the point of the `engineStrict` flag if it's functionally useless?) – sent1nel Jul 21 '14 at 16:41
  • @sent1nel Sorry I'm blind, not sure how I missed your `engineStrict`. So does it matter if the specified engine node version (`"v0.11.13"`) has a "v" in it? – Ian Jul 21 '14 at 16:48
  • @sent1nel Nevermind, I just read here that a leading "v" will be stripped: https://www.npmjs.org/doc/misc/semver.html . Also, I can reproduce the problem you're seeing, where `engineStrict` doesn't do what it says it should... – Ian Jul 21 '14 at 16:52
  • Possible duplicate of [How can I specify the required Node.js version in packages.json?](https://stackoverflow.com/questions/29349684/how-can-i-specify-the-required-node-js-version-in-packages-json) – Ciro Santilli OurBigBook.com Feb 03 '19 at 21:18
  • lol, thank you all for the views over the years. i literally haven't checked in on this question basically since i asked it in 2014, when i was first messing with package.json! – sent1nel Feb 03 '21 at 04:01

4 Answers4

51

The npm registry includes a package called “node”. It is a regular npm package that contains only the Node.js binary.

So, in your directory in question run:

npm install node@your.desired.version --save-exact

Then, put a script in your package.json as follows:

"scripts": {
  "v": "node -v"
}

To verify, run node -v in your terminal in the root of the project and you should see the version you have set on your machine. Compare that by running npm run v and you should see the version you have set for the project. This way, you can seamlessly move about your file system and execute various builds without changing your global node configuration.

In principle, every executable file that arrives with an npm package is linked to the local binaries directory within the project. It means that when we install such a package, we could find a link for its executable file inside.

Note: set node engine to advise - "this field is advisory only and will only produce warnings when your package is installed as a dependency."

Luke Woodward
  • 511
  • 4
  • 6
40

NVM + .nvmrc

If you are using NVM like this, which you likely should, then you can indicate the nodejs version required for given project in a git-tracked .nvmrc file:

node --version > .nvmrc

or:

echo v10.15.1 > .nvmrc

This does not take effect automatically on cd, which is sane: the user must then do a:

nvm use

and now that version of node will be used for the current shell.

You can list the versions of node that you have with:

nvm list

.nvmrc is documented at: https://github.com/creationix/nvm/tree/02997b0753f66c9790c6016ed022ed2072c22603#nvmrc

Tested with NVM 0.33.11.

Heroku does respect package.json engines:

Worth mentioning, as documented here, Heroku does play it nice and obey the engines: entry e.g.:

  "engines": {
    "node": "14.17.0",
    "npm": "6.14.13"
  },

So you should Always, Always set that to what you are using locally.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
7

I believe that the engines and engineStrict are for when the package is being installed (via npm), not when you're trying to execute something with node. These options warn/prevent users from installing a package that is not designed to work (or compatible) with the node version they are currently using.

modulitos
  • 14,737
  • 16
  • 67
  • 110
mscdex
  • 104,356
  • 15
  • 192
  • 153
  • 2
    Actually, that seems reasonable. I just dug into npm, and what I found is that `npm install` passes the strict flag into a chained call to "npm-install-checks" (https://github.com/npm/npm/blob/master/lib/install.js :858) when installing individual modules. As you can see in npm-install-checks (https://github.com/npm/npm-install-checks/blob/master/index.js :12), a check is made to see if the module can run on the strictly specified engine. So there it is - certainly not what I expected. Thanks for pointing me in that direction! – sent1nel Jul 21 '14 at 18:00
  • Note that `engineStrict` was removed in npm 3.0.0: https://docs.npmjs.com/files/package.json#enginestrict – modulitos Jul 06 '17 at 19:15
6

I have two solutions for this problem ....

Soln #1: Use a node version manager that can download and install Node and NPM for a specific version (and x86/x64 architecture for Windows) and then allow developers to switch versions.

Windows:

Mac/Linux:

Soln #2: Use a Docker image to run dev code on a Linux VM with your selected Node version. Your developers now all get an identical development environment that will hopefully match your final deployment environment.

This example shows you how to Dockerize your web app for deployment. During development you want to replace the COPY . /src command use a volume to mounts code from your host filesystem to avoid doing image rebuilds as you update code. A trick is to create your base images and then derive development (./src is a volume) and deployment (copies ./src) images.

Finally you can also exploit Docker to do your CI testing

Refs:

Tony O'Hagan
  • 21,638
  • 3
  • 67
  • 78