install npm 到某個文件下執行_你可能不知道的 npm 依賴管理那些事

a3a71ee6496f78f64b806c1895e8793c.png

點擊上方藍字關注我們

npm 是 Node.js 默認的、以 JavaScript 編寫的包管理工具,如今,它已經成為世界上最大的包管理工具,是每個前端開發者必備的工具。不知你是否遇到過下面問題:

哎?我本地明明是好的,線上的依賴怎么就報錯不行了呢?一言不合就刪除整個node_modules目錄然后重新npm install

今天我們聊聊npm模塊相關的東西。

semver

npm 依賴管理的一個重要特性是采用了語義化版本 (semver)?規范,作為依賴版本管理方案。

semver規定的模塊版本號格式為:MAJOR.MINOR.PATCH,即主版本號.次版本號.修訂號。版本號遞增規則如下:

  1. 主版本號:當你做了不兼容的 API 修改,例如新增了breaking change。

  2. 次版本號:當你做了向下兼容的功能性新增,例如新增feature。

  3. 修訂號:當你做了向下兼容的問題,例如修復bug。

對于npm包的引用者來說,經常會在package.json文件里面看到使用semver約定的semver range來指定所需的依賴包版本號和版本范圍。常用的規則如下表:

6f4e97e4ed1719b275a2ef3ebd66851d.png

此外,任意兩條規則,用空格連接起來,表示“與”邏輯,即兩條規則的交集: 如?>=2.3.1 <=2.8.0?可以解讀為:?>=2.3.1?且?<=2.8.0

任意兩條規則,通過?||?連接起來,表示“或”邏輯,即兩條規則的并集: 如?^2 >=2.3.1 || ^3 >3.2

在修訂版本號的后面可以加上其他信息,用-連接,比如:

  • X.Y.Z-Alpha: 內測版

  • X.Y.Z-Beta: 公測版

  • X.Y.Z-Stable: 穩定版

從 npm install 說起

npm install 命令用來安裝模塊到 node_modules 目錄。npm install 的具體原理是什么呢?

執行工程自身 preinstall

確定首層依賴模塊

首層依賴是 package.json 中 dependencies 和 devDependencies 字段直接指定的模塊。每一個首層依賴模塊都是模塊依賴樹根節點下面的一顆子樹。

獲取模塊

獲取模塊是一個遞歸的過程,分為以下幾步:

  1. 獲取模塊信息。在下載一個模塊之前,首先要確定其版本,這是因為?package.json?中的模塊版本往往是 semantic version。此時根據package.json和版本描述文件(npm-shrinkwrap.json?或?package-lock.json不同npm版本的策略不同,后續我們會詳細介紹)。如?package.json?中某個包的版本是?^1.1.0,npm 就會去倉庫中獲取符合1.x.x形式的最新版本。

  2. 獲取模塊實體。上一步會獲取到模塊的壓縮包地址(resolved 字段),npm 會用此地址檢查本地緩存,緩存中有就直接拿,如果沒有則從倉庫下載。

  3. 查找該模塊依賴,如果有依賴則回到第1步,如果沒有則停止。

模塊扁平化 (npm3 后支持)

上一步獲取到的是一顆完整的依賴樹,下面會根據依賴樹安裝模塊。模塊安裝機制有兩種:嵌套式安裝機制?和?扁平式安裝機制。

例如某工程下直接依賴了A和B兩個包,且他們同時依賴了C包。

  • 嵌套式

57e9364be0a6acc9b8172f5b6fd22fde.png

npm3之前使用的是嵌套式安裝機制,嚴格按照依賴樹的結構進行安裝,這可能會造成相同模塊大量冗余的問題。

  • 扁平式

3944923c4b938d3be4bbdbf797a71bcd.png

npm3之后使用的扁平式安裝機制,但是需要考慮一個問題:

工程同時依賴一個模塊不同版本該如何解決?

npm3 引入了 dedupe 過程來解決這個問題。它會遍歷所有節點,逐個將模塊放在根節點下面,也就是 node-modules 的第一層。當發現有重復模塊時,則將其丟棄。

重復模塊:semver兼容的相同模塊。例如lodash ^1.2.0lodash ^1.4.0。如果工程的兩個模塊版本范圍存在交集,就可以得到一個?兼容版本,不必版本號完全一致,這可以使得更多冗余模塊在dedupe過程中被去掉。

上例中如果A包依賴C@1.0.0,B包依賴C@2.0.0,此時兩個版本并不兼容,則后面的版本仍會保留在依賴書中。如下圖所示:

24f9cf736d75e06ca48331c78183f8bc.png

實際上,npm3仍然可能出現模塊冗余的情況,如下圖,因為一級目錄下已經有C@1.0.0,所以所有的C@2.0.0只能作為二級依賴模塊被安裝:

64bb63a83b0fbf3ad66131873b7744b4.png

npm提供了?npm dedupe?指令來優化依賴樹結構。這個命令會去搜索本地的node_modules中的包,并且通過移動相同的依賴包到外層目錄去盡量簡化這種依賴樹的結構,讓公用包更加有效被引用。

安裝模塊

將會更新工程中的?node_modules,并執行模塊中的生命周期函數(按照?preinstall、install、postinstall?的順序)

執行工程自身生命周期

當前 npm 工程如果定義了鉤子此時會被執行(按照?install、postinstall、prepublish、prepare?的順序)。最后生成或者更新版本描述文件。

鎖定npm依賴版本
你是否遇到過本地開發時一切正常,發布線上代碼時因為安裝依賴的錯誤導致服務不可用?如果是的話,你要一份版本描述文件。

簡單的寫死當前工程依賴模塊的版本并不能真正鎖定依賴版本,因為你無法控制間接依賴,如果間接依賴更新了有問題的模塊,你的系統還是可能會有宕機的風險。

lock 文件是當前依賴關系樹的快照,允許不同機器間的重復構建。其實 npm5 之前已經提供了lock文件——?npm-shrinkwrap.json。但是在 npm5 發布的時候創建了新的lock文件——?package-lock.json,其主要目的是希望能更好的傳達一個消息,npm真正支持了locking機制。不過二者還是有一些區別點:

  1. ?發布npm包時,package-lock.json?不會被發布, 即使你將其顯式添加到軟件包的?files?屬性中,它也不會是已發布軟件包的一部分。npm-shrinkwrap.json?可以被發布。

  2. npm-shrinkwrap.json向后兼容npm2、3、4版本,package-lock.json 只有 npm5 以上支持。

  3. 可以通過npm shrinkwrap命令將package-lock.json轉換成npm-shrinkwrap.json, 因為文件的格式是完全一樣的。

曲折的package-lock.json

查閱資料得知,自npm 5.0版本發布以來,package-lock.json的規則發生了三次變化。

  1. npm 5.0.x版本,不管 package.json 怎么變,npm install都會根據lock文件下載。npm/npm#16866 控訴了這個問題,我明明手動改了 package.json ,為啥不給我升包!然后就導致5.1.0的問題(是個bug)

  2. npm 5.1.0 - 5.4.1版本,npm insall會無視lock文件,去下載semver兼容的最新的包。導致lock文件并不能完全鎖住依賴樹。詳情見npm/npm#17979

  3. npm 5.4.2版本之后,如果手動改了package.json,且package.json和lock文件不同,那么執行npm install時 npm 會根據 package 中的版本號和語義含義去下載最新的包,并更新至 lock。

    如果兩者是同一狀態,那么執行?npm install都會根據 lock 下載,不會理會 package 實際包的版本是否更新。

好的依賴管理方案

  • 使用 npm: >=5.4.2 版本, 保持?package-lock.json?文件默認開啟配置

  • 初始化:第一作者初始化項目時使用?npm install ?安裝依賴包, 默認保存?^X.Y.Z?依賴 range 到 package.json 中; 提交?package.json,?package-lock.json,?不要提交?node_modules?目錄

  • 初始化:項目成員首次 checkout/clone 項目代碼后,執行一次?npm install?安裝依賴包

  • 升級依賴包:

    • 升級小版本: 本地執行?npm update?升級到新的小版本

    • 升級大版本: 本地執行?

npm install @
  • 升級到新的大版本

  • 也可手動修改 package.json 中版本號為要升級的版本(大于現有版本號)并指定所需的 semver, 然后執行?npm install

  • 本地驗證升級后新版本無問題后,提交新的?package.json,?package-lock.json?文件

降級依賴包:

正確:?

 npm install @

驗證無問題后,提交?package.json 和 package-lock.json 文件

刪除依賴包:

  • Plan A:?

npm uninstall 

????并提交?package.json?和?package-lock.json

  • Plan B: 把要卸載的包從 package.json 中 dependencies 字段刪除, 然后執行?npm install?并提交?package.json?和?package-lock.json

任何時候有人提交了?package.json,?package-lock.json?更新后,團隊其他成員應在?svn update/git pull?拉取更新后執行?npm install?腳本安裝更新后的依賴包

不要手動修改 package-lock.json

當 package-lock.json 出現沖突時,這種是非常棘手的情況,最好不要手動解決沖突,如果有一處沖突解決不正確可能會導致線上事故。
建議的做法:將本地的 package-lock.json文件刪除,引入遠程的 package-lock.json 文件,再執行npm install命令更新package-lock.json文件。

(這種做法能保證未修改的依賴不變,會存在一個風險:在執行npm install的時候,可能有些間接依賴包升級,根據semver兼容原則導致本次安裝的和開發時的package-lock.json文件不同。這種情況就需要驗證依賴包升級是否有影響)

部署安裝依賴時,執行npm install命令。不要執行

npm install

命令,因為這會導致 package-lock.json 文件同時被更新。

問題來了

上述最佳實踐提到了當團隊中有成員提交了?package.json,?package-lock.json?更新后,其他成員需要執行?npm install 來保證本地依賴的及時性,那么能否寫一個插件將這個手動的環節自動化呢?答案是可以的,我們只需要在 git post-merge 鉤子中檢查
git diff files(git diff-tree -r --name-only --no-commit-id HEAD@{1} HEAD)

是否包含了 package.json 文件,如果包含了該文件,則執行npm install命令。我們暫且給這個插件取名為 hawkeye 。當然,這個插件能干的事情不僅于此。

不知作為讀者的你聽到上述場景描述后,是否有種似曾相識的感覺?沒錯,lint-staged。

lint-staged,從git staged files變化中匹配你想要的文件,再執行你配置的commands。

Hawkeye,從git diff files變化中匹配你想要的文件,再執行你配置的commands。

需要注意的是,他們都依賴于husky改造git hooks的能力。

實現方案

1f63c45af522d3358c75fc3efe292c0d.png

例子

假設有一個已經安裝了 hawkeye 和 husky 的項目, package.json 如下:

{  "name": "My project",  "version": "0.1.0",  "scripts": {  },  "husky": {    "hooks": {      "post-merge": "hawkeye"    }  },  "hawkeye": {    "package.json": ["npm install"]  }}
相關鏈接
  • semver 語義化版本?

    https://semver.org/lang/zh-CN/?spm=ata.13261165.0.0.552e2688ZKTpgz

  • semver(1) -- The semantic versioner for npm

    https://github.com/npm/node-semver?spm=ata.13261165.0.0.552e2688ZKTpgz

  • 2018 年了,你還是只會 npm install 嗎?

    https://juejin.im/post/5ab3f77df265da2392364341?spm=ata.13261165.0.0.552e2688ZKTpgz

  • npm install algorithm

    https://docs.npmjs.com/cli/install?spm=ata.13261165.0.0.552e2688ZKTpgz#algorithm

  • npm dedupe

    https://docs.npmjs.com/cli/dedupe.html?spm=ata.13261165.0.0.552e2688ZKTpg

  • npm install的實現原理

    https://www.zhihu.com/question/66629910?spm=ata.13261165.0.0.552e2688ZKTpgz

  • [譯] 理解 NPM 5 中的 lock 文件

    https://juejin.im/post/5943849aac502e006b84ce07?spm=ata.13261165.0.0.552e2688ZKTpgz

  • package-lock.json file not updated after package.json file is changed

    https://github.com/npm/npm/issues/16866?spm=ata.13261165.0.0.552e2688ZKTpgz

  • why is package-lock being ignored?

    https://github.com/npm/npm/issues/17979?spm=ata.13261165.0.0.552e2688ZKTpgz

  • lint-staged

    https://github.com/okonet/lint-staged?spm=ata.13261165.0.0.552e2688ZKTpgz

  • hawkeye

    https://github.com/stormqx/hawkeye?spm=ata.13261165.0.0.552e2688ZKTpgz

推薦閱讀

我的公眾號能帶來什么價值?(文末有送書規則,一定要看)每個前端工程師都應該了解的圖片知識(長文建議收藏)為什么現在面試總是面試造火箭?

41f1485158585b0348083295ca394f4b.png

7b39f00788b49b357a074cd34c977888.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385966.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385966.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385966.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

萬字總結!騰訊、字節跳動面經已發

二、常見的并發問題 1、臟讀 一個事務讀取了另一個事務未提交的數據 2、不可重復讀 一個事務對同一數據的讀取結果前后不一致。兩次讀取中間被其他事務修改了 3、幻讀 幻讀是指事務讀取某個范圍的數據時&#xff0c;因為其他事務的操作導致前后兩次讀取的結果不一致。幻讀…

ncbi查找目的基因序列_NCBI大搜索之目的基因尋蹤

NCBI大搜索之目的基因尋蹤最近經常碰到查找目的基因的問題&#xff0c;那今天就講一下如何利用NCBI數據庫查找目的基因&#xff01;NCBI(National Center For Biotechnology Information),美國國家生物技術信息中心&#xff0c;分子生物學&#xff0c;生物化學及遺傳學領域常用…

萬字長文!2020-2021京東Java面試真題解析

我整理的spring學習筆記&#xff1a; 像spring這種知識點我們不能盲目的學習&#xff0c;首先我們得有一套學習路線&#xff0c;我總結了一套spring的學習思維導圖&#xff0c;今天通過我整理的Spring學習路線.xmind給大家分析spring需要掌握的一些核心知識點。 spring的特點&…

echarts label固定位置_ECharts+百度地圖網絡拓撲應用

前一篇談及到了ECharts整合HT for Web的網絡拓撲圖應用&#xff0c;后來在ECharts的Demo中看到了有關空氣質量的相關報表應用&#xff0c;就想將百度地圖、ECharts和HT for Web三者結合起來也做一個類似空氣質量報告的報表拓撲圖應用&#xff0c;于是有了下面的Demo&#xff1a…

三年Java開發,你連基礎的JVM運行時內存布局都忘了

面&#xff1a;為什么要使用雙親委派機制去加載類&#xff1f; 答&#xff1a;避免多份同樣字節碼的加載&#xff0c;浪費內存。 類的加載方式 隱式加載&#xff1a;new顯示加載&#xff1a;loadClass、forName等 類的裝載過程如下圖&#xff1a; 面&#xff1a;loadClass和…

vue實現可編輯的文字_蘋果還自帶文字轉語音,只要一鍵按下便可實現,今天分享給大家...

如果想將文字轉成語音&#xff0c;那大家平時都是怎么操作&#xff1f;下面小編就為大家介紹手機&#xff0c;電腦上都可以使用的方法&#xff0c;讓我們一起來看看吧&#xff01;一、手機端操作1、蘋果手機其實蘋果手機就自帶了文字轉語音功能&#xff0c;只要打開手機&#x…

三面美團Java崗,面試竟然被這31道Java基礎題難倒了

01 分布式限流&#xff1a;NginxZooKeeper 1.1 分布式限流之Nginx 請解釋一下什么是 Nginx? 請列舉 x Nginx 的一些特性。 請列舉 x Nginx 和 和 Apache 之間的不同點 請解釋 x Nginx 如何處理 P HTTP 請求。 在 x Nginx 中&#xff0c;如何使用未定義的服務器名稱來阻止…

海龜繪圖小動物_震驚!被塑料繩勒成兩半的海龜

海洋&#xff0c;其實離人類很近&#xff0c;我們在追逐沙灘和日落&#xff0c;享受美味的海鮮的時候&#xff0c;可曾想到我們平時的一些很隨意的行為&#xff0c;會給一些海洋生物帶來無法恢復的傷害&#xff0c;甚至奪取它們的生命。或許人們的冷漠無知尚未得到懲罰&#xf…

上海大廠Java面試經歷:初步理解類加載運行機制和類加載過程

volatile相關經典面試題 談談volatile的特性volatile的內存語義說說并發編程的3大特性什么是內存可見性&#xff0c;什么是指令重排序&#xff1f;volatile是如何解決java并發中可見性的問題volatile如何防止指令重排volatile可以解決原子性嘛&#xff1f;為什么&#xff1f;v…

python生成泊松分布隨機數_泊松分布隨機數

一、功能產生泊松分布的隨機數。二、方法簡介泊松分布的概率密度函數為\[f(x)\frac{\lambda ^{x}e^{-\lambda }}{x!} \qquad x\in \left \{ 0,1,...,\lambda \right \}\]用\(P(\lambda)\)表示。泊松分布的均值為\(\lambda\)&#xff0c;方差為\(\lambda\)。定理 若\(\lambda &g…

mysql數據庫優化面試

前言 現在Java程序員面試都是因為沒有豐富的工作經驗和自己過硬的技術&#xff0c;所有都不知道一般互聯網應該會問什么技術問題&#xff0c;加上自己可能去面試的時候沒有準備的太充分&#xff0c;一面試剛跟面試官扯幾個面試題就不知道自己在哪里了&#xff0c;被懟的體無完…

leetcode中文版python_Python版LeetCode1.兩數之和

啦啦啦&#xff0c;歡迎開啟LeetCode刷題的旅程&#xff0c;這將是一段漫長而又艱辛的旅程。這道Two Sum的題目作為LeetCode的開篇之題&#xff0c;乃是經典中的經典&#xff0c;正所謂‘平生不識TwoSum&#xff0c;刷盡LeetCode也枉然’&#xff0c;就像英語單詞書的第一個單詞…

mysql數據庫備份方式,跳槽大廠必看!

NO1&#xff1a;說說zookeeper是什么&#xff1f; ZooKeeper是一個分布式的&#xff0c;開放源碼的分布式應用程序協調服務&#xff0c;是Google的Chubby一個開源的實現&#xff08;Chubby是不開源的&#xff09;&#xff0c;它是集群的管理者&#xff0c;監視著集群中各個節點…

python淺藍色對應的代碼_淺藍色Python模塊不在m上工作

我正在嘗試通過macosx10.7.2上的Python連接到wiimote。在為此我試著用淺藍色。運行時&#xff1a;import lightbluePython會給我這個錯誤。在>>> import lightblueTraceback (most recent call last):File "", line 1, in File "/Library/Frameworks/P…

mysql數據庫安裝教程32位,看這一篇就夠了!

字節跳動 ?試前?????結 ?試前 頭條的?試是三家?最專業的&#xff0c;每次?試前有專?的HR和你約時間&#xff0c;確定OK后再進??試。每次都是通過視頻?試&#xff0c;因為都是之前都是電話?或現場?&#xff0c;所以視頻?試還是有點不?然。也有?覺得視頻?試…

java cron工具類_Java工具類之:包裝類

我們都知道&#xff0c;JDK 其實給我們提供了很多很多 Java 開發者已經寫好的現成的類&#xff0c;他們其實都可以理解成工具類&#xff0c;比如我們常見的集合類&#xff0c;日期相關的類&#xff0c;數學相關的類等等&#xff0c;有了這些工具類&#xff0c;你會發現它能很大…

mysql數據庫安裝,真香!

Spring Security觀后感——手繪思維腦(供參考) 手繪的思維導圖&#xff0c;是我自己根據自身的情況讀完這套阿里出品的Spring Security王者晉級文檔之后所繪的&#xff0c;相當于是一個知識的總結與梳理&#xff0c;我將其分為“核心組件”與“工作原理/認證流程”。 Spring Se…

python列表代碼_8種高級的Python列表使用技巧,都給你整理好啦(附實操代碼)...

Python中的列表是我們很常見的數據結構之一&#xff0c;也是很強大的數據結構之一!Python列表功能非常豐富&#xff0c;并且具有很多隱藏的技巧沒有被發現。一、使用Python過濾列表1.使用Filter()函數filter()函數采用兩個參數&#xff1a;函數和可迭代項。 在這種情況下&#…

mysql數據庫實用教程答案

前言 數據庫相關的面試題早已成為了一線互聯網大廠面試的家常菜&#xff0c;如果你對數據庫不太熟悉&#xff0c;我勸你不要輕易面試大廠。那么&#xff0c;為什么數據庫成了大廠面試的家常菜呢&#xff1f;主要原因當然還是海量數據。 無論對于剛入行的小白還是有幾年Java開…

在idea中新建的text文件_開發屬于自己的第一款 IDEA 插件!

往期熱門文章&#xff1a;1、《往期精選優秀博文都在這里了&#xff01;》2、又一個程序員跑路刪庫跑路被抓了&#xff0c;導致服務器癱瘓 36 個小時!3、恕我直言&#xff0c;有了這款 IDEA 插件&#xff0c;你可能只需要寫 30% 的代碼。。。4、Java8 的 Stream API 的確牛X&am…