從安裝過(guò)程詳解node-sass

我們?cè)诎惭b依賴的時(shí)候,經(jīng)常會(huì)附帶安裝node-sass,而node-sass會(huì)經(jīng)常安裝報(bào)錯(cuò),一般都是gyp的error


image.png

我們來(lái)分析下安裝過(guò)程

安裝過(guò)程

  1. npm下載到node-sass這個(gè)包
  2. 觸發(fā)了node-sass這個(gè)包的install的鉤子,或者說(shuō)生命周期,然后執(zhí)行了install.js


    image.png
  3. install.js里會(huì)嘗試去手動(dòng)下載它的一個(gè)c++模塊,也就是一個(gè).node文件,他會(huì)先嘗試去環(huán)境里獲取這個(gè)c++模塊的鏡像地址,如果你配置了鏡像地址的話,優(yōu)先從你的鏡像地址下載


    image.png
  4. 而這個(gè)sass.getBinaryUrl方法里會(huì)嘗試用各種手段獲取鏡像
    比如
  • --sass-binary-site就是命令行里的參數(shù)
  • process.env.SASS_BINARY_SITE 就是環(huán)境變量里的
  • npm_config_sass_binary_site,就是.npmrc文件里的sass_binary_site,.npmrc里面的變量會(huì)自動(dòng)被注入到臨時(shí)環(huán)境變量里,轉(zhuǎn)換成以npm_config帶頭的變量名
  • pkg.nodeSassConfig或者pkg.nodeSassConfig.binarySite 則是寫在package.json中的鏡像地址
    image.png

所以我們?cè)诰W(wǎng)上經(jīng)常能搜到的解決方案就是安裝報(bào)錯(cuò)時(shí),去.npmrc文件中配置鏡像,使得該binary可以下載到,一般是這么配置

sass_binary_site=https://www.npmmirror.com/mirrors/node-sass

  1. 如果這些都沒(méi)有配置的話,就有一個(gè)默認(rèn)的github的下載地址 https://github.com/sass/node-sass/releases/download,這個(gè)地址現(xiàn)在點(diǎn)進(jìn)去看是不存在的,因?yàn)槁窂竭€沒(méi)拼完

  2. 從上方的圖里大概可以猜到,完整地址應(yīng)該是
    https://github.com/sass/node-sass/releases/download/v版本號(hào)/binary的名字
    現(xiàn)在我們?nèi)鄙侔姹咎?hào)和bindary名字

  3. 版本號(hào)很容易得知,就是安裝的node-sass的版本號(hào)

  4. 后面的binaryName,直接看下圖框起來(lái)的部分即可,因?yàn)檎G闆r下圖里其他的if條件都不會(huì)滿足,正常情況下不會(huì)特地去配這些變量

    image.png

  5. binaryName我們可以根據(jù)圖里的規(guī)則自己拼下,直接在自己電腦上獲取下, 輸入node -p [process.platform,process.arch,process.versions.modules].join('-')"

    image.png

  6. 所以完整下載地址,應(yīng)該是https://github.com/sass/node-sass/releases/download/v4.14.1/win32-x64-108_binding.node,也就是說(shuō)node-sass在安裝過(guò)程中會(huì)拼出這個(gè)地址來(lái),然后從這個(gè)地址去下載binary

  7. 但是會(huì)發(fā)現(xiàn),這個(gè)地址點(diǎn)進(jìn)去404了,不存在該下載地址

  8. 因?yàn)閚ode-sass,在4.14.1版本,沒(méi)有win32-x64-108這個(gè)型號(hào)的.node文件,我們?nèi)ニ黦ithub的release里找到這個(gè)4.14.1的版本號(hào),再往下找assets,會(huì)發(fā)現(xiàn),最多就到83,沒(méi)有到108的


    image.png
  9. 所以即便你配置了阿里云鏡像,也沒(méi)用,因?yàn)檫@個(gè)版本號(hào)對(duì)應(yīng)的.node文件就那么少

  1. 而下載不到.node文件時(shí),不會(huì)報(bào)錯(cuò),但是會(huì)觸發(fā)另一個(gè)hook,postinstall,這是完成安裝后觸發(fā)的


    image.png

    在這個(gè)build.js里他會(huì)去各種判斷binary是否存在,然后嘗試編譯一行sass語(yǔ)法,如果有任何報(bào)錯(cuò),都會(huì)嘗試重新本地build出這個(gè).node文件

image.png
  1. 而這個(gè)build函數(shù)里,我們會(huì)發(fā)現(xiàn),他需要用node-gyp編譯,而node-gyp需要python環(huán)境,沒(méi)安裝的時(shí)候就報(bào)錯(cuò)了


    image.png

    image.png
  1. 回到上面的話題,再往上翻,我們會(huì)發(fā)現(xiàn),只有v8.0.0版本的node-sass,才有到108的binary


    image.png
  2. 但是v8.0.0版本的node-sass,未必能和項(xiàng)目當(dāng)前的sass-loader能兼容,即便sass-loader能升上去,但項(xiàng)目里用的是webpack4,webpack4未必能和這么高版本的sass-loader兼容

  3. 所以我們需要把后面的數(shù)值降下去,把win32-x64-108后面的-108給降下去,這個(gè)和當(dāng)前的node版本有關(guān),我現(xiàn)在用的是node18,所以是win32-x64-108

  4. 使用nvm切換到node16版本,切換后我們?cè)僭囅聞偛诺拿?/p>

    image.png
  5. 可以看到已經(jīng)降到93了,93的最低要求版本是v6.0.0


    image.png
  6. 然后繼續(xù)安裝依賴,發(fā)現(xiàn)還是報(bào)錯(cuò),這.npmrc文件配置了鏡像,版本也對(duì)了,手動(dòng)去下載這個(gè).node文件也能下載到,為什么還報(bào)錯(cuò)??

  7. 于是手動(dòng)把node-sass的git倉(cāng)庫(kù)clone下來(lái),加了.npmrc,然后執(zhí)行npm i,發(fā)現(xiàn)是地址不對(duì),然后在關(guān)鍵位置打了log后發(fā)現(xiàn)


    image.png
  8. .npmrc里明明配置的是阿里云鏡像,為什么這邊獲取到的是淘寶鏡像??


    image.png
  1. 經(jīng)過(guò)排查發(fā)現(xiàn),是因?yàn)槲野凑課ode-sass的官方的readme文件,執(zhí)行了npm install -g mirror-config-china配置鏡像地址
    image.png

后面的--registry配置的是這個(gè)mirror-config-china的下載地址,而mirror-config-china下載到了后,都不用手動(dòng)執(zhí)行,直接自動(dòng)往用戶目錄下的全局.npmrc文件里寫入一堆的淘寶鏡像地址,這是寫死的

  1. 淘寶鏡像地址2024年證書已經(jīng)過(guò)期了,這個(gè)包寫入的全是錯(cuò)的,所以把用戶目錄下的.npmrc文件清空就行了

  2. 所以可以分析出,npm install過(guò)程中,會(huì)先讀取項(xiàng)目目錄下.npmrc的配置,并轉(zhuǎn)換成npm_config帶頭的變量,臨時(shí)寫入到shell的環(huán)境變量中,然后再讀取用戶目錄下的.npmrc文件,再轉(zhuǎn)臨時(shí)變量寫入shell,此時(shí)如果有兩個(gè)相同的臨時(shí)變量名,項(xiàng)目里.npmrc里的就會(huì)被覆蓋

  3. 清空該文件內(nèi)容


    image.png
  4. 然后安裝成功,安裝成功是clone下來(lái)的node-sass的git倉(cāng)庫(kù)安裝依賴成功了,并且postinstall也成功了,
    此時(shí)我們清掉緩存重新回到項(xiàng)目里安裝依賴,.node緩存有兩個(gè)位置,一個(gè)當(dāng)前項(xiàng)目里的vender文件夾里,還有一個(gè)是全局的


    image.png
  5. 清掉這兩個(gè)緩存后再回到項(xiàng)目里安裝,發(fā)現(xiàn)又報(bào)了個(gè)錯(cuò),此時(shí)懷疑不是node-sass的問(wèn)題,因?yàn)閱为?dú)把node-sass拎出來(lái)是可以的,而且報(bào)的錯(cuò)看著和node-sass沒(méi)啥關(guān)系


    企業(yè)微信截圖_17289748906132.png
9886 verbose stack Error: command failed
9886 verbose stack     at ChildProcess.<anonymous> (C:\Users\Administrator\AppData\Roaming\nvm\v16.18.1\node_modules\npm\node_modules\@npmcli\promise-spawn\lib\index.js:63:27)
9886 verbose stack     at ChildProcess.emit (node:events:513:28)
9886 verbose stack     at maybeClose (node:internal/child_process:1100:16)
9886 verbose stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5)
9887 verbose pkgid node-sass@6.0.1

報(bào)錯(cuò)后回到全局緩存目錄查看,發(fā)現(xiàn)node-sass的binary是已經(jīng)下載到了的,因?yàn)橹按_定把這些都清空了


image.png
  1. 改成pnpm安裝后成功,而npm安裝就是失敗

  2. 再仔細(xì)看報(bào)錯(cuò)位置,是執(zhí)行node-sass在執(zhí)行postinstall的時(shí)候,node build.js拋出的錯(cuò),所以仔細(xì)觀察build.js這個(gè)文件

  3. .node文件確定是已經(jīng)下載到了的,那么也就是說(shuō)可能是在這段代碼里執(zhí)行報(bào)錯(cuò)了


    image.png
  4. 但是再仔細(xì)想想也不對(duì),如果執(zhí)行報(bào)錯(cuò),會(huì)走到下面的catch,起碼會(huì)log輸出Binary has a problem或者Building the binary locally這兩句話來(lái),可npm error里并沒(méi)有這些log

  5. 所以只能是前面的代碼執(zhí)行有問(wèn)題


    image.png
  6. 先看第一行if里的options.force,然后找到options.force 是怎么來(lái)的,這下破案了


    image.png
  7. 也就是說(shuō),.npmrc里面如果有force=true,或者install 的命令后面跟著--force或者-f的話,直接會(huì)先用node-gyp強(qiáng)行build,而我這個(gè)項(xiàng)目里,因?yàn)楦鞣N依賴不對(duì)等導(dǎo)致安裝報(bào)錯(cuò),然后用了 npm install --force,想忽略依賴不對(duì)等問(wèn)題直接安裝,然后這個(gè)--force剛好被node-sass解析到,嘗試強(qiáng)行build一個(gè).node文件,因?yàn)闆](méi)有配置環(huán)境,就失敗了
    而pnpm安裝時(shí)沒(méi)有報(bào)錯(cuò),所以沒(méi)有加--force,單獨(dú)拉node-sass倉(cāng)庫(kù)install時(shí)也沒(méi)有加--force,所以這兩個(gè)情況下反而可以成功

  8. 知道是--force命令帶來(lái)的問(wèn)題就好辦了,把npm install --force 換成 npm install --legacy-peer-deps 即可

總結(jié)

  1. node-sass下載不到時(shí),.npmrc文件里面可以配置對(duì)應(yīng)的.node文件的地址,但是要注意node版本和對(duì)應(yīng)的node-sass版本必須匹配,否則即便配置了國(guó)內(nèi)鏡像地址也下載不到

  2. 千萬(wàn)別看node-sass的readme文件去執(zhí)行npm install -g mirror-config-china,這命令會(huì)往全局的.npmrc里寫入sass_binary_site為淘寶鏡像地址,這個(gè)配置會(huì)在運(yùn)行時(shí)覆蓋項(xiàng)目里的.npmrc,而淘寶鏡像的https證書過(guò)期了

  3. 有node-sass依賴的項(xiàng)目,install時(shí)別加--force,否則會(huì)強(qiáng)行本地編譯一個(gè).node文件,也會(huì)報(bào)錯(cuò)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容