`npm ci` does not compile native dependencies according to `.npmrc` configuration

(Scott Rippey) #1

What I Wanted to Do

I have an Electron application with several native/addon dependencies.
I have the following variables in my .npmrc file:

target=3.0.11
disturl=https://atom.io/download/electron
runtime=electron

When I run npm install, all my native dependencies are built for Electron, with the correct ABI version (v64, in this case).

Now, I want to replace npm install with the faster npm ci.

What Happened Instead

However, surprisingly, when I run npm ci, all my native dependencies are built for my local Node ABI version (v57 in this case), and then fail to load in Electron.

I know the .npmrc file is being observed; for example, I see env vars like npm_config_runtime=electron and npm_config_target=3.0.11. But all native dependencies, whether attempted to download via node-pre-gyp or compiled on-the-fly, are downloaded/compiled for Node, not Electron, ignoring my .npmrc configuration.

Reproduction Steps

  1. Create an .npmrc file with the above contents
  2. Create a package.json with a native dependency: npm init -y && npm i --save keytar
  3. Run npm install
  4. Verify that the keytar dependency was build for Electron, not Node. Two ways to test this:
    In Node (should error):
node -p "require('keytar')"
# Expected Error:
# Error: The module './node_modules/keytar/build/Release/keytar.node'
# was compiled against a different Node.js version using
# NODE_MODULE_VERSION 64. This version of Node.js requires
# NODE_MODULE_VERSION 57. Please try re-compiling or re-installing

In Electron (should work):

echo "require('keytar')" | npx electron@3 -i
# Should log:
# { getPassword: [Function: getPassword],
#   setPassword: [Function: setPassword],
#   deletePassword: [Function: deletePassword],
#   findPassword: [Function: findPassword],
#   findCredentials: [Function: findCredentials] }

Details

I know there are options like electron-rebuild, but rebuilding these dependencies takes several minutes, so it’s far more efficient to keep using npm install. It’s just very surprising that npm ci would behave so differently, regarding native modules.

Platform Info

$ npm --versions
{ test: '1.0.0',
  npm: '6.9.0',
  ares: '1.10.1-DEV',
  cldr: '32.0',
  http_parser: '2.8.0',
  icu: '60.1',
  modules: '57',
  napi: '3',
  nghttp2: '1.33.0',
  node: '8.15.0',
  openssl: '1.0.2q',
  tz: '2017c',
  unicode: '10.0',
  uv: '1.23.2',
  v8: '6.2.414.75',
  zlib: '1.2.11' }
$ node -p process.platform
darwin
(Christian Bundy) #2

I can reproduce this as well. The npm install command works fine but npm ci does not.

I’m using environment variables rather than an .npmrc, here’s the code I’m using: https://electronjs.org/docs/tutorial/using-native-node-modules#using-npm