又踩了 node-saas 和 node-gyp 的坑

2024-06-18

最近支援一个老项目,又遇到 node-gyp 报错的问题,花了几个小时才解决。我记得之前给 antd 贡献代码时,安装依赖也遇到这个问题,当时也花了不止一天的时间。

这次是一个 umi3 且 pnpm monorepo 的项目。我的环境是 macOS 14.5、pnpm@8、node v16.20.2。

clone 项目到本地后,执行 pnpm i 安装依赖时报错:

node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass: Running postinstall script, failed in 580ms
.../node_modules/node-sass postinstall$ node scripts/build.js
│ Building: /Users/zack/.nvm/versions/node/v16.20.2/bin/node /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/bin/nod
│ gyp info it worked if it ends with ok
│ gyp verb cli [
│ gyp verb cli   '/Users/zack/.nvm/versions/node/v16.20.2/bin/node',
│ gyp verb cli   '/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/bin/node-gyp.js',
│ gyp verb cli   'rebuild',
│ gyp verb cli   '--verbose',
│ gyp verb cli   '--libsass_ext=',
│ gyp verb cli   '--libsass_cflags=',
│ gyp verb cli   '--libsass_ldflags=',
│ gyp verb cli   '--libsass_library='
│ gyp verb cli ]
│ gyp info using node-gyp@3.8.0
│ gyp info using node@16.20.2 | darwin | arm64
│ gyp verb command rebuild []
│ gyp verb command clean []
│ gyp verb clean removing "build" directory
│ gyp verb command configure []
│ gyp verb download using dist-url https://npm.taobao.org/dist
│ gyp verb check python checking for Python executable "python2" in the PATH
│ gyp verb `which` succeeded python2 /Users/zack/.pyenv/shims/python2
│ gyp verb check python version `/Users/zack/.pyenv/shims/python2 -c "import sys; print "2.7.18
│ gyp verb check python version .%s.%s" % sys.version_info[:3];"` returned: %j
│ gyp verb get node dir no --target version specified, falling back to host node version: 16.20.2
│ gyp verb command install [ '16.20.2' ]
│ gyp verb download using dist-url https://npm.taobao.org/dist
│ gyp verb install input version string "16.20.2"
│ gyp verb install installing version: 16.20.2
│ gyp verb install --ensure was passed, so won't reinstall if already installed
│ gyp verb install version not already installed, continuing with install 16.20.2
│ gyp verb ensuring nodedir is created /Users/zack/.node-gyp/16.20.2
│ gyp verb created nodedir /Users/zack/.node-gyp/16.20.2
│ gyp http GET https://npm.taobao.org/dist/v16.20.2/node-v16.20.2-headers.tar.gz
│ gyp WARN install got an error, rolling back install
│ gyp verb command remove [ '16.20.2' ]
│ gyp verb remove using node-gyp dir: /Users/zack/.node-gyp
│ gyp verb remove removing target version: 16.20.2
│ gyp verb remove removing development files for version: 16.20.2
│ gyp ERR! configure error
│ gyp ERR! stack Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: npm.taobao.org. is not in the cert's altnames: DNS:*.tbcdn.cn, DNS:*.ta
│ gyp ERR! stack     at new NodeError (node:internal/errors:387:5)
│ gyp ERR! stack     at Object.checkServerIdentity (node:tls:354:12)
│ gyp ERR! stack     at TLSSocket.onConnectSecure (node:_tls_wrap:1549:27)
│ gyp ERR! stack     at TLSSocket.emit (node:events:513:28)
│ gyp ERR! stack     at TLSSocket._finishInit (node:_tls_wrap:953:8)
│ gyp ERR! stack     at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:734:12)
│ gyp ERR! System Darwin 23.5.0
│ gyp ERR! command "/Users/zack/.nvm/versions/node/v16.20.2/bin/node" "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-g
│ gyp ERR! cwd /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass
│ gyp ERR! node -v v16.20.2
│ gyp ERR! node-gyp -v v3.8.0
│ gyp ERR! not ok
│ Build failed with error code: 1
└─ Failed in 580ms at /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass
 ELIFECYCLE  Command failed with exit code 1.

如果在网上搜索 node-gyp 的报错,大部分的结论都是缺少 python 环境、缺少 C++ 开发环境等。我之前也因为环境导致失败过,不过这次失败并不是这些原因。

我还发现一个现象。使用不同的 node 版本安装依赖,得到的报错都是不同的,以下是我在 node v16 下的报错:

node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass: Running postinstall script, failed in 674ms
.../node_modules/node-sass postinstall$ node scripts/build.js
│ Building: /Users/zack/.nvm/versions/node/v18.19.1/bin/node /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/bin/nod
│ gyp info it worked if it ends with ok
│ gyp verb cli [
│ gyp verb cli   '/Users/zack/.nvm/versions/node/v18.19.1/bin/node',
│ gyp verb cli   '/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/bin/node-gyp.js',
│ gyp verb cli   'rebuild',
│ gyp verb cli   '--verbose',
│ gyp verb cli   '--libsass_ext=',
│ gyp verb cli   '--libsass_cflags=',
│ gyp verb cli   '--libsass_ldflags=',
│ gyp verb cli   '--libsass_library='
│ gyp verb cli ]
│ gyp info using node-gyp@3.8.0
│ gyp info using node@18.19.1 | darwin | arm64
│ gyp verb command rebuild []
│ gyp verb command clean []
│ gyp verb clean removing "build" directory
│ gyp verb command configure []
│ gyp verb download using dist-url https://npm.taobao.org/dist
│ gyp verb check python checking for Python executable "python2" in the PATH
│ gyp verb `which` succeeded python2 /Users/zack/.pyenv/shims/python2
│ gyp verb check python version `/Users/zack/.pyenv/shims/python2 -c "import sys; print "2.7.18
│ gyp verb check python version .%s.%s" % sys.version_info[:3];"` returned: %j
│ gyp verb get node dir no --target version specified, falling back to host node version: 18.19.1
│ gyp verb command install [ '18.19.1' ]
│ gyp verb download using dist-url https://npm.taobao.org/dist
│ gyp verb install input version string "18.19.1"
│ gyp verb install installing version: 18.19.1
│ gyp verb install --ensure was passed, so won't reinstall if already installed
│ gyp verb install version is already installed, need to check "installVersion"
│ gyp verb got "installVersion" 9
│ gyp verb needs "installVersion" 9
│ gyp verb install version is good
│ gyp verb get node dir target node version installed: 18.19.1
│ gyp verb build dir attempting to create "build" dir: /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/build
│ gyp verb build dir "build" dir needed to be created? /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/build
│ gyp verb build/config.gypi creating config file
│ gyp verb build/config.gypi writing out config file: /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/build/confi
│ (node:63573) [DEP0150] DeprecationWarning: Setting process.config is deprecated. In the future the property will be read-only.
│ (Use `node --trace-deprecation ...` to show where the warning was created)
│ gyp verb config.gypi checking for gypi file: /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/config.gypi
│ gyp verb common.gypi checking for gypi file: /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/common.gypi
│ gyp verb gyp gyp format was not specified; forcing "make"
│ gyp info spawn /Users/zack/.pyenv/shims/python2
│ gyp info spawn args [
│ gyp info spawn args   '/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/gyp_main.py',
│ gyp info spawn args   'binding.gyp',
│ gyp info spawn args   '-f',
│ gyp info spawn args   'make',
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass/build/config.gypi',
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/addon.gypi',
│ gyp info spawn args   '-I',
│ gyp info spawn args   '/Users/zack/.node-gyp/18.19.1/include/node/common.gypi',
│ gyp info spawn args   '-Dlibrary=shared_library',
│ gyp info spawn args   '-Dvisibility=default',
│ gyp info spawn args   '-Dnode_root_dir=/Users/zack/.node-gyp/18.19.1',
│ gyp info spawn args   '-Dnode_gyp_dir=/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp',
│ gyp info spawn args   '-Dnode_lib_file=/Users/zack/.node-gyp/18.19.1/<(target_arch)/node.lib',
│ gyp info spawn args   '-Dmodule_root_dir=/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass',
│ gyp info spawn args   '-Dnode_engine=v8',
│ gyp info spawn args   '--depth=.',
│ gyp info spawn args   '--no-parallel',
│ gyp info spawn args   '--generator-output',
│ gyp info spawn args   'build',
│ gyp info spawn args   '-Goutput_dir=.'
│ gyp info spawn args ]
│ Traceback (most recent call last):
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/gyp_main.py", line 16, in <module>
│     sys.exit(gyp.script_main())
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/__init__.py", line 545, in script_main
│     return main(sys.argv[1:])
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/__init__.py", line 538, in main
│     return gyp_main(args)
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/__init__.py", line 514, in gyp_main
│     options.duplicate_basename_check)
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/__init__.py", line 130, in Load
│     params['parallel'], params['root_targets'])
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 2783, in Load
│     variables, includes, depth, check, True)
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 399, in LoadTargetBuildFile
│     includes, True, check)
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 271, in LoadOneBuildFile
│     aux_data, includes, check)
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 308, in LoadBuildFileInclude
│     LoadOneBuildFile(include, data, aux_data, None, False, check),
│   File "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/gyp/pylib/gyp/input.py", line 251, in LoadOneBuildFile
│     None)
│   File "/Users/zack/.node-gyp/18.19.1/include/node/common.gypi", line 1
│     e_data_file_flag%': 1
│                         ^
│ SyntaxError: EOL while scanning string literal
│ gyp ERR! configure error
│ gyp ERR! stack Error: `gyp` failed with exit code: 1
│ gyp ERR! stack     at ChildProcess.onCpExit (/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-gyp/lib/configure.js:345:
│ gyp ERR! stack     at ChildProcess.emit (node:events:517:28)
│ gyp ERR! stack     at ChildProcess._handle.onexit (node:internal/child_process:292:12)
│ gyp ERR! System Darwin 23.5.0
│ gyp ERR! command "/Users/zack/.nvm/versions/node/v18.19.1/bin/node" "/Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-gyp@3.8.0/node_modules/node-g
│ gyp ERR! cwd /Users/zack/Desktop/program/test123/node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass
│ gyp ERR! node -v v18.19.1
│ gyp ERR! node-gyp -v v3.8.0
│ gyp ERR! not ok
│ Build failed with error code: 1

在 node16 下的报错貌似是网络问题,而在 node18 下是 python 程序执行错误的问题。从这两个报错中,最重要的信息是:

node_modules/.pnpm/registry.npmmirror.com+node-sass@4.14.1/node_modules/node-sass: Running postinstall script, failed in 674ms

意思是 这个项目依赖了node-sass,在 pnpm 安装完 node-sass 会执行它的 build 脚本,这个脚本执行失败了,导致了 pnpm i 失败,此时也可以排除网络问题,因为 node-saas 和 node-gyp 都成功下载到我的电脑中了。 在 node-saas 的github上看到它对 node 的支持如下: node-saas-version

解决方法

我的项目依赖的是node-sass@4.14.1,只有 node14 以下是支持这个版本的。于是我切换到 node14,重新执行pnpm i,结果成功了。