內容來自:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/22html
輸入npm install命令並敲下回車後,會經歷以下幾個階段:node
當前npm工程若是定義了preinstall鉤子,此時會被執行react
首先,須要作的是肯定工程中的首層依賴,也就是dependencies和devDependencies屬性中直接指定的模塊(假設此時沒有添加npm install參數)git
工程自己是整棵依賴樹的根節點,每一個首層依賴模塊都是根節點下面的一棵子樹,npm會開啓多進程從每一個首層依賴模塊開始逐步尋找更深層級的節點。github
獲取模塊是一個遞歸的過程,分爲如下幾步:npm
上一步獲取到的是一棵完整的依賴樹,其中可能包含大量重複模塊。好比A模塊依賴於lodash,B模塊一樣依賴於lodash,在npm3之前會嚴格按照依賴樹的結構進行安裝,所以會形成模塊冗餘。json
從npm3開始默認加入了一個dedupe的過程。它會遍歷全部節點,逐個將模塊放在根節點下面,也就是node-modules下,foo模塊依賴lodash@^1.0.0,bar模塊依賴lodash@^1.1.0,則^1.1.0爲兼容版本。緩存
而當foo依賴lodash@^2.0.0,bar依賴lodash@^1.1.0,則根據semver的規則,兩者不存在兼容版本,將會一個版本放在node_modules裏,另外一個仍保留在依賴樹裏。網絡
舉個例子,假設一個依賴樹本來是這樣:socket
node_modules
-- foo
---- lodash@version1
-- bar
---- lodash@version2
假設version1和version2是兼容版本,則通過dedupe會成爲下面的形式:
node_module
-- foo
-- bar
-- lodash (保留的版本爲兼容版本)
假設version1和version2爲非兼容版本,則後面的版本保留在依賴樹中
node_modules
-- foo
-- lodash@version1
-- bar
---- lodash@version2
這一步將會更新工程中的node_modules,並執行模塊中的生命週期函數(按照preinstall、install、postinstall的順序)
當前npm工程若是定義了鉤子此時會被執行(按照install、postinstall、prepublish、prepare的順序)
最後一步以生成或更新版本描述文件,npm install過程完成。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
原文:http://www.ruanyifeng.com/blog/2016/01/npm-install.html
npm是Node的模塊管理器,功能極其強大。它是Node得到成功的重要緣由之一
本文介紹npm模塊安裝機制的細節,以及如何解決安裝速度慢的問題。
若是你但願,一個模塊不論是否安裝過,npm都要強制從新安裝,可使用-f或-force參數
npm install <packageName> --force
若是想更新已安裝模塊,就要用到npm update命令
npm update <packageName>
它會先到遠程倉庫查詢最新版本,而後查詢本地版本。若是本地版本不存在,或者遠程版本較新,就會安裝。
npm模塊倉庫提供了一個查詢服務,叫作registry。以npmjs.org爲例,它的查詢服務網址是https://registry.npmjs.org/
這個網址後面跟上模塊名,就會獲得一個JSON對象,裏面是該模塊全部版本的信息。好比訪問https://registry.npmjs.org/react,就會看到react模塊全部版本的信息
它跟下面命令的效果是同樣的
npm view react # npm view 的別名 npm info react npm show react npm v react
訪問https://registry.npmjs.org/react/v0.14.6就能夠看到React的0.14.6版。
返回的JSON對象裏面,有一個dist.tarball屬性,是該版本壓縮包的網址。
dist: { shasum:'2a57c2cf8747b483759ad8de0fa47fb0c5cf5c6a', tarball: 'http://registry.npmjs.org/react/-/react-0.14.6.tgz' }
到這個網址下載壓縮包,在本地解壓,就獲得了模塊的源碼。
npm install 或npm update命令,從registry下載壓縮包以後,都存放在本地的緩存目錄。
這個緩存目錄,在Linux或Mac默認是用戶主目錄下的.npm目錄,在Windows默認是%AppData%/npm-cache.
經過配置命令,能夠查看這個目錄的具體位置
npm config get cache
ls ~/.npm #或者 npm cache ls
你會看到裏面存放着大量的模塊,儲存結構是{cache}/{name}/{version}
$ npm cache ls react ~/.npm/react/react/0.14.6/ ~/.npm/react/react/0.14.6/package.tgz ~/.npm/react/react/0.14.6/package/ ~/.npm/react/react/0.14.6/package/package.json
rm -rf ~/.npm/*
或者
npm cache clean
總結一下,Node模塊的安裝過程是這樣的
1.發出npm install命令
2.npm向registry查詢模塊壓縮包的網址
3.下載壓縮包,存放在~/.npm目錄
4.解壓壓縮包到當前項目的node_modules
注意,一個模塊安裝之後,本地其實保存了兩份。一份是~/.npm目錄下的壓縮包。另外一份是node_modules目錄下解壓後的代碼。可是運行npm install的時候,只會檢查node_modules目錄,而不會檢查~/.npm目錄。也就是說,若是一個模塊在~/.npm下有壓縮包,可是沒有安裝在node_modules目錄中,npm依然會從遠程倉庫下載一次新的壓縮包。
這種行爲當然能夠保證老是取得最新的代碼,但有時並非咱們想要的。最大的問題是,它會極大地影響安裝速度。即便某個模塊的壓縮包就在緩存目錄中,也要去遠程倉庫下載,這怎麼可能不慢呢?
另外,有些場合沒有網絡,可是你想安裝的模塊,明明就在緩存目錄之中,這時也沒法安裝。
--cache-min參數
爲了解決這些問題,npm提供了一個--cache-min參數,用於從緩存目錄安裝模塊。
--cache-min參數指定一個時間(單位爲分鐘),只有超過這個時間的模塊,纔會從registry下載。
npm install --cache-min 999999 <package-name>
上面命令指定,只有超過999999分鐘的模塊才從registry下載。實際上就是指定,全部模塊都從緩存安裝,這樣就大大加快了下載速度。
它還有另外一種寫法
npm install --cache-min Infinity <package-name>
上面三個模塊的用法很相似,都是在本機起一個Registry服務,全部npm install命令都要經過這個服務代理。
npm-proxy-cache
npm --proxy http://localhost:8080\ --https-proxy http://localhost:8080\ --strict-ssl false\ install
local-npm
npm set registry http://127.0.0.1:5080
npm-lazy
npm --registry http://localhost:8080/ install socket.io
有了本機的Registry服務,就能徹底實現緩存安裝,能夠實現離線使用
若是可以改變npm install的行爲,就能實現緩存安裝。npm-cache工具就是這個思路。凡是使用npm install的地方,均可以使用npm-cache替代
npm-cache install
這個方案的思路是,不使用.npm緩存,而是使用項目的node_modules目錄做爲緩存。