npm install 安裝包及其依賴。npm install: 默認情況下,安裝package.json文件中列出的所有依賴。加-P或--production后,只安裝dependencies列出的依賴,而不安裝devDependencies列出的依賴。npm install [<@scope>/]<name>,安裝包的最新版本,並記錄在package.json中的dependencies中,加-D或--save-dev,安裝包,並記錄到devDependencies 中
npm install react
npm install @babel/core -D
npm install [<@scope>/]<name>@<version>: 安裝指定版本的包
npm install react@16
npm install 安裝依賴到什么地方呢?默認情況下,它會安裝到當前包的根目錄下的node_modules中。比如redux,它有自己的依賴,安裝redux時,它的依賴就會安裝redux的根目錄下的node_modules中。
如果安裝依賴的地方並不在一個包下,比如,開始一個新項目,要安裝依賴,它只是一個普通的目錄,那就安裝到當前目錄下的node_modules中。如果安裝的依賴有scope,比如@babel/core, 它會安裝到node_modules下的@scope目錄下,相同的scope的包集中放到同一個目錄下。安裝完成后,可以通過require("packagename")來加載主模塊(packae.json中main指定的文件),或 require("packagename/lib/path/to/sub/module") 加載其它模塊。如果安裝包的是命令包,比如webpack-cli,它里面的bin目錄會鏈接到node_modules中的./bin目錄下,當在package.json中的script寫命令,然后使用npm run 執行時,npm 會找到相應的命令執行。其實,這里有一個小細節,當在一個目錄中安裝包時,npm會從當前目錄向上查找,看有沒有一個目錄包含package.json文件或node_modules目錄,如果有,它會在找到的目錄中安包,npm認為這是一個有意義的目錄。如果沒有,則在當前目錄安裝包。比如項目根目錄下,有packag.json, 你不小心 cd src中,此時在src目錄下安裝包,npm還是會把包安裝到根目錄。npm 安裝包的時候,先安裝到npm 的緩存中,然后再解壓到node_modules中。
項目的依賴都安裝到node_modules下,那node_modules的目錄結構是怎么樣的? npm 2版本的時候,以嵌套的方式安裝所有依賴,比如App項目依賴A,A依賴B,那么App的node_modules中有A, A的node_modules中的B。這就會導致依賴樹太深,並且安裝的包大多,冗余。為了解決這個問題,npm 3版本則試圖扁平化安裝。主依賴和二級依賴安裝到同級目錄,主依賴就是package.json中列出的依賴,二級依賴就是主依賴的依賴。還是以項目App為例,主依賴就是A,二級依賴就是B,npm 3安裝的時候,A和B在同一級目錄,都是在App的node_modules中。
項目開發時,又安裝了一個依賴C,C也依賴B,不過是2.0版本,如果是npm2安裝,直接安裝C依賴,C里面嵌套B。如果是npm3安裝,它就是安裝C,然后嘗試把B安裝到C同等級別的目錄,也就node_modules頂級目錄,但node_modules頂級目錄下面已經有了B 1.0依賴,不能再安裝B 2.0依賴,否則就沖突了,所以B2.0,只能安裝到C目錄下
在命令行窗口,它會如下顯示
你會發現,目錄結構沒有辦法顯示依賴關系, 可以使用npm ls 命令,列出依賴及其關系,列出主依賴,則是 npm ls --depth=0
假設再安裝依賴D,它也依賴Bv2.0,還是由於node_modules頂級目錄中安裝了B1.0, B2.0要安裝到D下面,注意,這里和以后的安裝都是npm3 了,
繼續依賴E,E依賴B1.0,此時只安裝E依賴,B依賴不用裝了,因為在頂級目錄中已經有了,
反應到命令行中就是
現在升級A 到2.0,正好它也依賴B2.0,首先是package.json 中A依賴的版本號從1.0 到2.0, 再在node_module中,刪除掉A1.0,安裝2.0,不能刪除B1.0 因為E在用,最后安裝B2.0
現在package.json中的依賴如下
"dependencies": { "mod-a": "^2.0.0", "mod-c": "^1.0.0", "mod-d": "^1.0.0", "mod-e": "^1.0.0" }
此時,你覺得項目初始化完成了,就提交了。同事拿到新代碼,就npm install,安裝所有依賴,你會發現他安裝的目錄如下
安裝順序起起到到了重要的作用,npm install 先安裝A2.0, 它依賴B2.0, 所以在node_modules頂級目錄中安裝了A2.0和B2.0,由於C和D都是依賴B2.0, 所以只在node_modules中安裝C和D主依賴就可以了,B2.0已經存在了,安裝E的時候,它由於依賴B1.0,所以在它的node_modules下面安裝了B1.0.
當npm install 一個依賴的時候,它會從當前目錄向上找,如果在祖先node_modules中找到符合的依賴,它就不會在本目錄下安裝,這也解決了循環依賴問題。但你會發現,你和你的同事的node_modules目錄結構不一致了。npm3 這種安裝依賴的方式,會導致一個問題,你的機器上的node_modules可能和你同事的node_modules 不一致,npm3 並不會已確定性的方式安裝node_modules。如果項目中只依賴主依賴,那是沒有影響的,如果有使用二級依賴,那就會有影響。比如 import {} from B, 你同事引用是B2.0, 而你引用的是B1.0. 怎么辦?把node_modules刪除了,重新安裝。這也導致package-lock.json 文件出現。如果一個項目中有package-lock.json文件,npm install的時候,就會照package-lock.json文件列出的依賴樹安裝依賴,package-lock.json文件會記錄項目開發時,依賴的安裝順序。比如A從1.0升級到2.0,package.json中只會把A升級到2.0,但package-lock.json 則會記錄
{ "dependencies": { "A": { "version": "2.0.0", "requires": { "B": "2.0.0" }, "dependencies": { "B": { "version": "2.0.0" } } }, "B": { "version": "1.0.0", }, "E": { "version": "1.0.0", "requires": { "B": "1.0.0", } } } }
可以清新地看到安裝順序,無論以后,誰按照package-lock.json文件安裝,安裝的目錄都是一樣的。
后面又出了yarn, yarn.lock文件,安裝包的依賴時,如果包中有package-lock.json或shrinkwrap.json或yarn.lock這些文件, 它會以這些文件為依據,安裝依賴。參考順序是npm-shrinkwrap.json,package-lock.json,yarn.lock。
在上圖的基礎上,假設你現在繼續開發,把E升級了,它依賴B2.0,npm 會刪除掉E1.0,安裝E2.0,刪除掉B1.0,因為沒有模塊依賴它了,安裝B2.0 到node_module頂級目錄。
這時,又有一個問題,模塊B2.0 在每一個目錄中,為了移除冗余,可以使用 npm deque, 這個命令找到依賴B2.0的模塊,然后,重定向到頂級目錄中的依賴,然后刪掉嵌套的依賴b2.0