聊聊NPM鏡像那些險象環生的坑

做者: JowayYoung
倉庫: GithubCodePen
博客: 掘金思否知乎簡書頭條CSDN
公衆號: IQ前端
聯繫我:關注公衆號後有個人 微信
特別聲明:原創不易,未經受權不得對此文章進行轉載或抄襲,不然按侵權處理,如需轉載或開通公衆號白名單可聯繫我,但願各位尊重原創的知識產權

前言

因爲國內網絡環境的緣由,在執行npm i安裝項目依賴過程當中,確定會趕上安裝過慢安裝失敗的狀況。有經驗的同窗一般會在安裝完Node時順便把NPM鏡像設置成國內的淘寶鏡像。前端

npm config set registry https://registry.npm.taobao.org/

這樣就能爽歪歪應付大部分npm i的安裝狀況了。固然,這只是解決了大部分的安裝過慢安裝失敗的狀況,隨着項目的深刻開發,確定還會趕上一些比較奇葩的狀況,這也是筆者爲何要寫本文的緣由。node

管理鏡像

你還可能會趕上這種狀況,開發項目時使用淘寶鏡像,可是發佈NPM第三方模塊時就必須使用原鏡像了。在着手解決那些奇葩狀況前,先推薦你們使用一個NPM鏡像管理工具python

  • 原鏡像https://registry.npmjs.org/
  • 淘寶鏡像https://registry.npm.taobao.org/

主角就是nrm,它是一個可隨時隨地自由切換NPM鏡像的管理工具。有了它,上面所說的什麼時候使用什麼鏡像的問題就迎刃而解了。下面對其進行安裝並簡單講解如何使用。git

安裝
npm i -g nrm
查看鏡像
nrm ls
增長鏡像
nrm add <name> <url>
移除鏡像
nrm del <name>
測試鏡像
nrm test <name>
使用鏡像
nrm use <name>
查看當前鏡像
nrm current

熟悉命令後一波操做以下,原鏡像淘寶鏡像之間隨意切換。固然,若是你記性好也不須要用這個工具了,哈哈。github

nrm操做

遇坑填坑

有了nrm切換到淘寶鏡像上,安裝速度會明顯加快,可是趕上安裝的模塊依賴了C++模塊那就坑爹了。在安裝過程當中會隱式安裝node-gypnode-gyp可編譯這些依賴C++模塊的模塊。sql

那麼問題來了,node-gyp在首次編譯時會依賴Node源碼,因此又悄悄去下載Node。雖然在前面已設置了淘寶鏡像,可是在這裏一點卵用都沒有。這樣又由於國內網絡環境的緣由,再次趕上安裝過慢安裝失敗的狀況。chrome

還好npm config提供了一個參數disturl,它可設置Node鏡像地址,固然仍是將其指向國內的淘寶鏡像。這樣又能爽歪歪安裝這些依賴C++模塊的模塊了。npm

npm config set disturl https://npm.taobao.org/mirrors/node/

問題一步一步解決,接下來又出現另外一個問題。日常你們都會使用node-sass做爲項目開發依賴,可是node-sass的安裝一直都是一個使人頭疼的問題。json

安裝node-sass時,在install階段會從Github上下載一個叫binding.node的文件,而GitHub Releases裏的文件都託管在s3.amazonaws.com上,這個網址被Q了,因此又安裝不了。segmentfault

然而辦法總比困難多,從node-sass的官方文檔中可找到一個叫sass_binary_site的參數,它可設置Sass鏡像地址,毫無疑問仍是將其指向國內的淘寶鏡像。這樣又能爽歪歪安裝node-sass了。

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/

其實還有好幾個相似的模塊,爲了方便,筆者仍是把它們源碼裏的鏡像參數和淘寶鏡像裏對應的鏡像地址扒出來,統一設置方便安裝。如下是筆者經常使用的幾個模塊鏡像地址配置,請收下!

分別是:SassSharpElectronPuppeteerPhantomSentrySqlitePython

鏡像地址配置

npm config set <name> <url>,趕忙一鍵複製,永久使用。特別注意,別漏了最後面的/

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm config set sharp_dist_base_url https://npm.taobao.org/mirrors/sharp-libvips/
npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
npm config set puppeteer_download_host https://npm.taobao.org/mirrors/
npm config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/
npm config set sentrycli_cdnurl https://npm.taobao.org/mirrors/sentry-cli/
npm config set sqlite3_binary_site https://npm.taobao.org/mirrors/sqlite3/
npm config set python_mirror https://npm.taobao.org/mirrors/python/

有了這波操做,再執行npm i安裝以上模塊時就能享受國內的速度了。若是有條件,建議把這些鏡像文件搬到本身或公司的服務器上,將鏡像地址指向本身的服務器便可。在公司內網搭建一個這樣的鏡像服務器,一直安裝一直爽,目前筆者所在的團隊就是如此處理。

npm config set electron_mirror https://xyz/mirrors/electron/

源碼分析

以常常卡住的node-sass爲例,下面是坑爹貨node-sass/lib/extensions.js源碼部分,可看出它會默認走GitHub Releases的託管地址,上面也分析過緣由,在這裏就不重複了。

function getBinaryUrl() {
  const site = getArgument("--sass-binary-site")
    || process.env.SASS_BINARY_SITE
    || process.env.npm_config_sass_binary_site
    || (pkg.nodeSassConfig && pkg.nodeSassConfig.binarySite)
    || "https://github.com/sass/node-sass/releases/download";
  const result = [site, "v" + pkg.version, getBinaryName()].join("/");
  return result;
}

而其餘模塊也有相似的代碼,例如puppeteer這個安裝Chronium源碼部分,有興趣的同窗都去扒一下源碼,一模一樣。

async function download() {
  await compileTypeScriptIfRequired();
  const downloadHost =
    process.env.PUPPETEER_DOWNLOAD_HOST
    || process.env.npm_config_puppeteer_download_host
    || process.env.npm_package_config_puppeteer_download_host;
  const puppeteer = require("./index");
  const product =
    process.env.PUPPETEER_PRODUCT
    || process.env.npm_config_puppeteer_product
    || process.env.npm_package_config_puppeteer_product
    || "chrome";
  const browserFetcher = puppeteer.createBrowserFetcher({
    product,
    host: downloadHost,
  });
  const revision = await getRevision();
  await fetchBinary(revision);
  // 還有不少
}

坑貨小結

因爲node-sass是你們常用的項目開發依賴,也是安裝時間較長和最多見到報錯的模塊,在這裏筆者就花點篇章分析和解決下可能會遇到的問題。

node-sass安裝失敗的緣由其實並不止上面提到的狀況,咱們可從安裝過程當中分析並獲取突破口來解決問題。根據npm i node-sass的輸出信息來分析,可獲得下面的過程。

  • 檢測項目node_modulesnode-sass是否存在且當前安裝版本是否一致

    • Yes:跳過,完成安裝過程
    • No:進入下一步
  • NPM上下載node-sass
  • 檢測全局緩存項目緩存中是否存在binding.node

    • Yes:跳過,完成安裝過程
    • No:進入下一步
  • Github Releases上下載binding.node並將其緩存到全局

    • Success:將版本信息寫入package-lock.json
    • Error:進入下一步
  • 嘗試本地編譯出binding.node

    • Success:將版本信息寫入package-lock.json
    • Error:輸出錯誤信息

不難看出,node-sass依賴了一個二進制文件binding.node,不只須要從NPM上下載本體還須要從Github Releases上下載binding.node


從實際狀況來看,node-sass出現安裝過慢安裝失敗的狀況可能有如下幾種:

NPM鏡像託管在國外服務器

上面有提到,在這裏再也不敘述,解決辦法以下。

nrm use taobao
安裝過程當中悄悄下載 node-gyp

上面有提到,在這裏再也不敘述,解決辦法以下。

npm config set disturl https://npm.taobao.org/mirrors/node/
binding.node文件託管在國外服務器

上面有提到,在這裏再也不敘述,解決辦法以下。

npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
Node版本與node-sass版本不兼容

node-sass版本兼容性好差,必須與Node版本對應使用才行,詳情請參考node-sass-version-association,複用官方文檔的版本對照表,以下。

NodeJS Minimum node-sass version Node Module
Node 14 4.14+ 83
Node 13 4.13+ 79
Node 12 4.12+ 72
Node 11 4.10+ 67
Node 10 4.9+ 64
Node 8 4.5.3+ 57

執行npm i安裝依賴前請確保當前的Node版本和node-sass版本已兼容。

全局緩存中的binding.node版本與Node版本不兼容

假如本地使用nvmn進行Node版本管理,而且已切換了Node版本,在安裝過程當中可能會出現Windows/OS X/Linux 64-bit with Node.js 12.x這樣的提示,這種狀況也是筆者常常趕上的狀況(筆者電腦裏安裝了30多個Node版本而且常常來回切換😂)。

這是由於node-sass版本和Node版本是關聯的(看上面的表格),修改Node版本後在全局緩存中匹配不到對應的binding.node文件而致使安裝失敗。根據錯誤提示,清理NPM緩存且從新安裝便可,解決辦法以下。

npm cache clean -f

npm rebuild node-sass

因此沒什麼事就別來回切換Node版本了,像筆者裝這麼多Node版本也是逼不得已,老項目太多了😂。

安裝失敗後從新安裝

有可能無權限刪除已安裝的內容,致使從新安裝時可能會產生某些問題,建議將node_modules所有刪除並從新安裝。

在Mac系統和Linux系統上刪除node_modules比較快,可是在Windows系統上刪除node_modules就比較慢了,推薦你們使用rimraf刪除node_modules,一個Node版的rm -rf工具。

npm i -g rimraf

在項目的package.json中加入npm scriptsrimraf常駐。三大操做系統通用,很是推薦使用。

{
  "scripts": {
    "reinstall": "rimraf node_modules && npm i"
  }
}

一有什麼安裝失敗從新安裝之類的操做,先執行npm run remove刪除node_modulesnpm i

npm run reinstall

終極總結

若是看得有點亂,那下面直接貼代碼操做順序,建議前端小白在安裝完Node後立馬處理這些NPM鏡像問題,防止後續產生沒必要要的麻煩(解決這些問題是須要花費時間的😂)。

# 查看Node版本和NPM版本確認已安裝Node環境
node -v
npm -v

# 安裝nrm並設置NPM的淘寶鏡像
npm i -g nrm
nrm use taobao

# 設置依賴安裝過程當中內部模塊下載Node的淘寶鏡像
npm config set disturl https://npm.taobao.org/mirrors/node/

# 設置經常使用模塊的淘寶鏡像
npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
npm config set sharp_dist_base_url https://npm.taobao.org/mirrors/sharp-libvips/
npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
npm config set puppeteer_download_host https://npm.taobao.org/mirrors/
npm config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/
npm config set sentrycli_cdnurl https://npm.taobao.org/mirrors/sentry-cli/
npm config set sqlite3_binary_site https://npm.taobao.org/mirrors/sqlite3/
npm config set python_mirror https://npm.taobao.org/mirrors/python/

針對node-sass的狀況:

# 安裝rimraf並設置package.json
npm i -g rimraf

# 安裝前請確保當前的Node版本和node-sass版本已兼容

# 安裝失敗
npm cache clean -f
npm rebuild node-sass 或 npm run reinstall

package.json中加入npm scripts

{
  "scripts": {
    "reinstall": "rimraf node_modules && npm i"
  }
}

總結

NPM鏡像問題的坑確實不少,歸根到底仍是網絡環境致使的。固然這些問題也阻礙不了樂於探索的咱們,辦法總比困難多,堅持下去始終能找到解決方式。

筆者總結出一個解決這種NPM鏡像問題的好方法,遇到一些上面沒有提到的模塊,可嘗試經過如下步驟去解決問題。

  • 執行npm i前設置淘寶鏡像,保證安裝項目依賴時都走國內網絡
  • 安裝不成功時,確定是在安裝過程當中該模塊內部又去下載了其餘國外服務器的文件
  • 在Github上克隆一份該模塊的源碼進行分析,搜索包含base、binary、cdn、config、dist、download、host、mirror、npm、site、url等這樣的關鍵詞(自行探索,一般mirror的匹配度最高)
  • 在搜查結果裏查找形態像鏡像地址的代碼塊,再分析該代碼塊的功能並提取最終的鏡像地址,例如node-sasssass_binary_site
  • 去淘寶鏡像官網、百度、谷歌等網站查找你須要的鏡像地址,若是實在找不到就規範上網把國外服務器的鏡像文件拉下來搬到本身或公司的服務器上
  • 設置模塊依賴的鏡像地址:npm config set <registry name> <taobao url / yourself url>
  • 從新執行npm i安裝項目依賴,大功告成

若是以上內容幫不了你或在解決NPM鏡像問題上還遇到其餘坑,歡迎添加筆者微信一塊兒交流。若有錯誤地方也歡迎指出,若有更好的解決方法也可提上建議。

另外筆者花了一些時間用Xmind整理了本文內容並生成一張知識點分佈圖,濃縮就是精華。因爲圖片太大沒法上傳就保存到公衆號裏,若有須要可關注IQ前端,掃描文章底部二維碼,後臺回覆NPM鏡像獲取該圖片,但願能幫助到你。

結語

❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更好的文章

關注公衆號IQ前端,一個專一於CSS/JS開發技巧的前端公衆號,更多前端小乾貨等着你喔

  • 關注後回覆關鍵詞免費領取視頻教程
  • 關注後添加我微信拉你進技術交流羣
  • 歡迎關注IQ前端,更多CSS/JS開發技巧只在公衆號推送

相關文章
相關標籤/搜索