TL;DR

确认node是否有修改源代码文件夹的权限;包括确认文件owner和文件修改权限。

过程 & 思路

日前在服务器上安装node-sass的过程中遇到了以下错误:

[root@VM_0_7_centos JerryChan31.github.io]# npm i

> node-sass@4.14.1 install /root/JerryChan31.github.io/node_modules/node-sass
> node scripts/install.js

Unable to save binary /root/JerryChan31.github.io/node_modules/node-sass/vendor/linux-x64-72 : Error: EACCES: permission denied, mkdir '/root/JerryChan31.github.io/node_modules/node-sass/vendor'
    at Object.mkdirSync (fs.js:840:3)
    at sync (/root/JerryChan31.github.io/node_modules/mkdirp/index.js:72:13)
    at Function.sync (/root/JerryChan31.github.io/node_modules/mkdirp/index.js:78:24)
    at checkAndDownloadBinary (/root/JerryChan31.github.io/node_modules/node-sass/scripts/install.js:114:11)
    at Object.<anonymous> (/root/JerryChan31.github.io/node_modules/node-sass/scripts/install.js:157:1)
    at Module._compile (internal/modules/cjs/loader.js:1158:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
    at Module.load (internal/modules/cjs/loader.js:1002:32)
    at Function.Module._load (internal/modules/cjs/loader.js:901:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12) {
  errno: -13,
  syscall: 'mkdir',
  code: 'EACCES',
  path: '/root/JerryChan31.github.io/node_modules/node-sass/vendor'
}

> core-js@2.6.11 postinstall /root/JerryChan31.github.io/node_modules/core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> ejs@2.7.4 postinstall /root/JerryChan31.github.io/node_modules/ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)


> node-sass@4.14.1 postinstall /root/JerryChan31.github.io/node_modules/node-sass
> node scripts/build.js

Building: /usr/local/bin/node/bin/node /root/JerryChan31.github.io/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
gyp info it worked if it ends with ok
gyp verb cli [
gyp verb cli   '/usr/local/bin/node/bin/node',
gyp verb cli   '/root/JerryChan31.github.io/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@12.16.1 | linux | x64
gyp verb command rebuild []
gyp verb command clean []
gyp verb clean removing "build" directory
gyp verb command configure []
gyp verb check python checking for Python executable "python2" in the PATH
gyp verb `which` succeeded python2 /usr/bin/python2
gyp verb check python version `/usr/bin/python2 -c "import sys; print "2.7.5
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: 12.16.1
gyp verb command install [ '12.16.1' ]
gyp verb install input version string "12.16.1"
gyp verb install installing version: 12.16.1
gyp verb install --ensure was passed, so won't reinstall if already installed
gyp verb install version not already installed, continuing with install 12.16.1
gyp verb ensuring nodedir is created /root/.node-gyp/12.16.1
gyp WARN EACCES user "root" does not have permission to access the dev dir "/root/.node-gyp/12.16.1"
gyp WARN EACCES attempting to reinstall using temporary dev dir "/root/JerryChan31.github.io/node_modules/node-sass/.node-gyp"
gyp verb tmpdir == cwd automatically will remove dev files after to save disk space
gyp verb command install [ '--node_gyp_internal_noretry', '12.16.1' ]
gyp verb install input version string "12.16.1"
gyp verb install installing version: 12.16.1
gyp verb install --ensure was passed, so won't reinstall if already installed
gyp verb install version not already installed, continuing with install 12.16.1
gyp verb ensuring nodedir is created /root/JerryChan31.github.io/node_modules/node-sass/.node-gyp/12.16.1
gyp WARN install got an error, rolling back install
gyp verb command remove [ '12.16.1' ]
gyp verb remove using node-gyp dir: /root/JerryChan31.github.io/node_modules/node-sass/.node-gyp
gyp verb remove removing target version: 12.16.1
gyp verb remove removing development files for version: 12.16.1
gyp WARN install got an error, rolling back install
gyp verb command remove [ '12.16.1' ]
gyp verb remove using node-gyp dir: /root/JerryChan31.github.io/node_modules/node-sass/.node-gyp
gyp verb remove removing target version: 12.16.1
gyp verb remove removing development files for version: 12.16.1
gyp ERR! configure error
gyp ERR! stack Error: EACCES: permission denied, mkdir '/root/JerryChan31.github.io/node_modules/node-sass/.node-gyp'
gyp ERR! System Linux 3.10.0-1062.9.1.el7.x86_64
gyp ERR! command "/usr/local/bin/node/bin/node" "/root/JerryChan31.github.io/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
gyp ERR! cwd /root/JerryChan31.github.io/node_modules/node-sass
gyp ERR! node -v v12.16.1
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
Build failed with error code: 1
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! node-sass@4.14.1 postinstall: `node scripts/build.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the node-sass@4.14.1 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2021-04-27T09_42_26_856Z-debug.log

网上一查,查到node-sass的Github issue,里面只提到了没有权限,但是没有提到如何修复权限问题。

中文网络下的搜索结果大部分也只是让人使用npm i --unsafe-perm node-sass这样的命令来绕过问题。

下面是我解决这个问题的流程。

仔细看下这里的报错堆栈:

gyp ERR! configure error
gyp ERR! stack Error: EACCES: permission denied, mkdir '/root/JerryChan31.github.io/node_modules/node-sass/.node-gyp'
gyp ERR! System Linux 3.10.0-1062.9.1.el7.x86_64
gyp ERR! command "/usr/local/bin/node/bin/node" "/root/JerryChan31.github.io/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="

这里提到的错误是,没有权限在/root/JerryChan31.github.io/node_modules/node-sass/.node-gyp这个目录下创建这个文件夹。

首先要搞懂,是谁没有权限呢?下面的日志给出了答案:

gyp ERR! command "/usr/local/bin/node/bin/node" "/root/JerryChan31.github.io/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="

这里说明了,执行创建文件夹操作的程序是/usr/local/bin/node/bin/node,也就是node。

那为什么node会没有权限呢?linux 的权限系统可以简单分为两个层级:

  1. 文件所属用户与组;
  2. 用户对文件的权限;

我们cd/usr/local/bin,执行ll | grep node,可以看到:

drwxr-xr-x 6 1001 1001 4096 2月  18 2020 node

这里与文件权限相关的内容是前面的drwxr-xr-x,代表读、写、执行权限情况;

后面的1001 1001的含义分别是文件的拥有者所属的group;

再回来看我要执行npm i的目录:

[root@VM_0_7_centos ~]# ll | grep github
drwxrwxrwx 8    root root      4096 4月  27 17:42 JerryChan31.github.io

这说明我的这个文件夹,是归root用户所有的。那么执行chown -R 1001:1001 JerryChan31.github.io/,将文件拥有者修改为与node相同的1001,就意味着node有了该文件夹的权限。再重新执行npm install,问题解决。