`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:


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] }


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