<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          npm 依賴管理中被忽略的那些細(xì)節(jié)

          共 6700字,需瀏覽 14分鐘

           ·

          2020-08-28 14:08

          ???這是第?66?篇不摻水的原創(chuàng),想要了解更多,請戳上方藍(lán)色字體:政采云前端團(tuán)隊(duì)?關(guān)注我們吧~

          本文首發(fā)于政采云前端團(tuán)隊(duì)博客:npm 依賴管理中被忽略的那些細(xì)節(jié)

          https://www.zoo.team/article/npm-details


          前言

          提起 npm,大家第一個想到的應(yīng)該就是 npm install 了,但是 npm install 之后生成的 node_modules 大家有觀察過嗎?package-lock.json 文件的作用大家知道嗎?除了 dependencies 和 devDependencies,其他的依賴有什么作用呢?接下來,本文將針對 npm 中的你可能忽略的細(xì)節(jié)和大家分享一些經(jīng)驗(yàn)。

          npm 安裝機(jī)制

          A 和 B 同時依賴 C,C 這個包會被安裝在哪里呢?C 的版本相同和版本不同時安裝會有什么差異呢?package.json 中包的前后順序?qū)τ诎惭b時有什么影響嗎?這些問題平時大家可能沒有注意過,今天我們就來一起研究一下吧。

          A 和 B 同時依賴 C,這個包會被安裝在哪里呢?

          假如有 A 和 B 兩個包,兩個包都依賴 C 這個包,npm 2 會依次遞歸安裝 A 和 B 兩個包及其子依賴包到 node_modules 中。執(zhí)行完畢后,我們會看到 ./node_modules 這層目錄只含有這兩個子目錄:

          node_modules/
          ├─┬ A
          │ ├── C
          ├─┬ B
          │ └── C

          如果使用 npm 3 來進(jìn)行安裝的話,./node_modules 下的目錄將會包含三個子目錄:

          node_modules/
          ├─┬ A
          ├─┬ B
          ├─┬ C

          為什么會出現(xiàn)這樣的區(qū)別呢?這就要從 npm 的工作方式說起了:

          npm 2 和 npm 3 模塊安裝機(jī)制的差異

          雖然目前最新的 npm 版本是 npm 6,但 npm 2 到 npm 3 的版本變更中實(shí)現(xiàn)了目錄打平,與其他版本相比差別較大。因此,讓我們具體看下這兩個版本的差異。

          npm 2 在安裝依賴包時,采用簡單的遞歸安裝方法。執(zhí)行 npm install 后,npm 根據(jù) dependencies 和 devDependencies 屬性中指定的包來確定第一層依賴,npm 2 會根據(jù)第一層依賴的子依賴,遞歸安裝各個包到子依賴的 node_modules 中,直到子依賴不再依賴其他模塊。執(zhí)行完畢后,我們會看到 ./node_modules 這層目錄中包含有我們 package.json 文件中所有的依賴包,而這些依賴包的子依賴包都安裝在了自己的 node_modules 中 ,形成類似于下面的依賴樹:

          這樣的目錄有較為明顯的好處:

          1)層級結(jié)構(gòu)非常明顯,可以清楚的在第一層的 node_modules 中看到我們安裝的所有包的子目錄;

          2)在已知自己所需包的名字以及版本號時,可以復(fù)制粘貼相應(yīng)的文件到 node_modules 中,然后手動更改 package.json 中的配置;

          3)如果想要刪除某個包,只需要簡單的刪除 package.json 文件中相應(yīng)的某一行,然后刪除 node_modules 中該包的目錄;

          但是這樣的層級結(jié)構(gòu)也有較為明顯的缺陷,當(dāng)我的 A,B,C 三個包中有相同的依賴 D 時,執(zhí)行 npm install 后,D 會被重復(fù)下載三次,而隨著我們的項(xiàng)目越來越復(fù)雜,node_modules 中的依賴樹也會越來越復(fù)雜,像 D 這樣的包也會越來越多,造成了大量的冗余;在 windows 系統(tǒng)中,甚至?xí)驗(yàn)槟夸浀膶蛹壧顚?dǎo)致文件的路徑過長,觸發(fā)文件路徑不能超過 280 個字符的錯誤;

          為了解決以上問題,npm 3 的 node_modules 目錄改成了更為扁平狀的層級結(jié)構(gòu),盡量把依賴以及依賴的依賴平鋪在 node_modules 文件夾下共享使用。

          npm ?3 對于同一依賴的不同版本會怎么處理呢?

          npm 3 會遍歷所有的節(jié)點(diǎn),逐個將模塊放在 node_modules 的第一層,當(dāng)發(fā)現(xiàn)有重復(fù)模塊時,則丟棄, 如果遇到某些依賴版本不兼容的問題,則繼續(xù)采用 npm 2 的處理方式,前面的放在 node_modules 目錄中,后面的放在依賴樹中。舉個?:A,B,依賴 D(v 0.0.1),C 依賴 D(v 0.0.2):

          但是 npm 3 會帶來一個新的問題:由于在執(zhí)行 npm install 的時候,按照 package.json 里依賴的順序依次解析,上圖如果 C 的順序在 A,B 的前邊,node_modules 樹則會改變,會出現(xiàn)下邊的情況:

          由此可見,npm 3 并未完全解決冗余的問題,甚至還會帶來新的問題。

          為什么會出現(xiàn) package-lock.json 呢?

          為什么會有 package-lock.json 文件呢?這個我們就要先從 package.json 文件說起了。

          package.json 的不足之處

          npm install 執(zhí)行后,會生成一個 node_modules 樹,在理想情況下, 希望對于同一個 package.json 總是生成完全相同 node_modules 樹。在某些情況下,確實(shí)如此。但在多數(shù)情況下,npm 無法做到這一點(diǎn)。有以下兩個原因:

          1)某些依賴項(xiàng)自上次安裝以來,可能已發(fā)布了新版本 。比如:A 包在團(tuán)隊(duì)中第一個人安裝的時候是 1.0.5 版本,package.json 中的配置項(xiàng)為 A: '^1.0.5';團(tuán)隊(duì)中第二個人把代碼拉下來的時候,A 包的版本已經(jīng)升級成了 1.0.8,根據(jù) package.json 中的 semver-range version 規(guī)范,此時第二個人 npm install 后 A 的版本為 1.0.8;可能會造成因?yàn)橐蕾嚢姹静煌鴮?dǎo)致的 bug;

          2)針對 1)中的問題,可能有的小伙伴會是把 A 的版本號固定為 A: '1.0.5' 不就可以了嗎?但是這樣的做法其實(shí)并沒有解決問題, 比如 A 的某個依賴在第一個人下載的時候是 2.1.3 版本,但是第二個人下載的時候已經(jīng)升級到了 2.2.5 版本,此時生成的 node_modules 樹依舊不完全相同 ,固定版本只是固定來自身的版本,依賴的版本無法固定。

          針對 package.json 不足的解決方法

          為了解決上述問題以及 npm 3 的問題,在 npm 5.0 版本后,npm install 后都會自動生成一個 package-lock.json 文件 ,當(dāng)包中有 package-lock.json 文件時,npm install 執(zhí)行時,如果 package.json 和 package-lock.json 中的版本兼容,會根據(jù) package-lock.json 中的版本下載;如果不兼容,將會根據(jù) package.json 的版本,更新 package-lock.json 中的版本,已保證 package-lock.json 中的版本兼容 package.json。

          package-lock.json 文件的結(jié)構(gòu)

          package-lock.json 文件中的 name、version 與 package.json 中的 name、version 一樣,描述了當(dāng)前包的名字和版本,dependencies 是一個對象,該對象和 node_modules 中的包結(jié)構(gòu)一一對應(yīng),對象的 key 為包的名稱,值為包的一些描述信息, 根據(jù) package-lock-json官方文檔 (https://docs.npmjs.com/configuring-npm/package-lock-json.html#requires),主要的結(jié)構(gòu)如下:

          • version :包版本,即這個包當(dāng)前安裝在 node_modules 中的版本
          • resolved :包具體的安裝來源
          • integrity :包 hash 值,驗(yàn)證已安裝的軟件包是否被改動過、是否已失效
          • requires :對應(yīng)子依賴的依賴,與子依賴的 package.jsondependencies 的依賴項(xiàng)相同
          • dependencies :結(jié)構(gòu)和外層的 dependencies 結(jié)構(gòu)相同,存儲安裝在子依賴 node_modules 中的依賴包

          需要注意的是,并不是所有的子依賴都有 dependencies 屬性,只有子依賴的依賴和當(dāng)前已安裝在根目錄的 node_modules 中的依賴沖突之后,才會有這個屬性。

          package-lock.json 文件的作用

          • 在團(tuán)隊(duì)開發(fā)中,確保每個團(tuán)隊(duì)成員安裝的依賴版本是一致的,確定一棵唯一的 node_modules 樹;
          • node_modules 目錄本身是不會被提交到代碼庫的,但是 package-lock.json 可以提交到代碼庫,如果開發(fā)人員想要回溯到某一天的目錄狀態(tài),只需要把 package.json 和 package-lock.json 這兩個文件回退到那一天即可。
          • 由于 package-lock.json 和 node_modules 中的依賴嵌套完全一致,可以更加清楚的了解樹的結(jié)構(gòu)及其變化。
          • 在安裝時,npm 會比較 node_modules 已有的包,和 package-lock.json 進(jìn)行比較,如果重復(fù)的話,就跳過安裝 ,從而優(yōu)化了安裝的過程。

          依賴的區(qū)別與使用場景

          npm 目前支持以下幾類依賴包管理包括

          • dependencies
          • devDependencies
          • optionalDependencies 可選擇的依賴包
          • peerDependencies 同等依賴
          • bundledDependencies 捆綁依賴包

          下面我們來看一下這幾種依賴的區(qū)別以及各自的應(yīng)用場景:

          dependencies

          dependencies 是無論在開發(fā)環(huán)境還是在生產(chǎn)環(huán)境都必須使用的依賴,是我們最常用的依賴包管理對象,例如 React,Loadsh,Axios 等,通過 npm install XXX 下載的包都會默認(rèn)安裝在 dependencies 對象中,也可以使用 ?npm install XXX --save 下載 ?dependencies 中的包;

          devDependencies

          devDependencies 是指可以在開發(fā)環(huán)境使用的依賴,例如 eslint,debug 等,通過 npm install packageName --save-dev 下載的包都會在 devDependencies 對象中;

          dependencies 和 devDependencies 最大的區(qū)別是在打包運(yùn)行時,執(zhí)行 npm install 時默認(rèn)會把所有依賴全部安裝,但是如果使用 npm install --production 時就只會安裝 dependencies 中的依賴,如果是 node 服務(wù)項(xiàng)目,就可以采用這樣的方式用于服務(wù)運(yùn)行時安裝和打包,減少包大小。

          optionalDependencies

          optionalDependencies 指的是可以選擇的依賴,當(dāng)你希望某些依賴即使下載失敗或者沒有找到時,項(xiàng)目依然可以正常運(yùn)行或者 npm 繼續(xù)運(yùn)行的時,就可以把這些依賴放在 optionalDependencies 對象中,但是 optionalDependencies 會覆蓋 dependencies 中的同名依賴包,所以不要把一個包同時寫進(jìn)兩個對象中。

          optionalDependencies 就像是我們的代碼的一種保護(hù)機(jī)制一樣,如果包存在的話就走存在的邏輯,不存在的就走不存在的邏輯。

          try?{?
          ??var?axios?=?require('axios')?
          ??var?fooVersion?=?require('axios/package.json').version?
          }?catch?(er)?{?
          ??foo?=?null?
          }?
          //?..?then?later?in?your?program?..?
          if?(foo)?{?
          ??foo.doFooThings()?
          }?

          peerDependencies

          peerDependencies 用于指定你當(dāng)前的插件兼容的宿主必須要安裝的包的版本,這個是什么意思呢?舉個例子?:我們常用的 react 組件庫 [email protected]?的 package.json (https://github.com/ant-design/ant-design/blob/master/package.json#L37) 中的配置如下:

          "peerDependencies":?{?
          ??"react":?">=16.9.0",?
          ??"react-dom":?">=16.9.0"?
          ?},?

          假設(shè)我們創(chuàng)建了一個名為 project 的項(xiàng)目,在此項(xiàng)目中我們要使用 [email protected] 這個插件,此時我們的項(xiàng)目就必須先安裝 React >= 16.9.0React-dom >= 16.9.0 的版本。

          在 npm 2 中,當(dāng)我們下載 [email protected] 時,peerDependencies 中指定的依賴會隨著 [email protected] 一起被強(qiáng)制安裝,所以我們不需要在宿主項(xiàng)目的 package.json 文件中指定 peerDependencies 中的依賴,但是在 npm 3 中,不會再強(qiáng)制安裝 peerDependencies 中所指定的包,而是通過警告的方式來提示我們,此時就需要手動在 package.json 文件中手動添加依賴;

          bundledDependencies

          這個依賴項(xiàng)也可以記為 bundleDependencies,與其他幾種依賴項(xiàng)不同,他不是一個鍵值對的對象,而是一個數(shù)組,數(shù)組里是包名的字符串,例如:

          {?
          ??"name":?"project",?
          ??"version":?"1.0.0",?
          ??"bundleDependencies":?[?
          ????"axios",??
          ????"lodash"?
          ??]?
          }?

          當(dāng)使用 npm pack 的方式來打包時,上述的例子會生成一個 project-1.0.0.tgz 的文件,在使用了 bundledDependencies 后,打包時會把 Axios 和 Lodash 這兩個依賴一起放入包中,之后有人使用 npm install project-1.0.0.tgz 下載包時,Axios 和 Lodash 這兩個依賴也會被安裝。需要注意的是安裝之后 Axios 和 Lodash 這兩個包的信息在 dependencies 中,并且不包括版本信息。

          "bundleDependencies":?[?
          ????"axios",?
          ????"lodash"?
          ??],?
          ??"dependencies":?{?
          ????"axios":?"*",?
          ????"lodash":?"*"?
          ??},?

          如果我們使用常規(guī)的 npm publish 來發(fā)布的話,這個屬性是不會生效的,所以日常情況中使用的較少。

          總結(jié)

          本文介紹的是 npm 2,npm 3,package-lock.json 以及幾種依賴的區(qū)別和使用場景,希望能夠讓大家對 npm 的了解更加多一點(diǎn),有什么不清楚的地方或者不足之處歡迎大家在評論區(qū)留言。

          參考文獻(xiàn)

          package.json官方文檔 (https://docs.npmjs.com/files/package.json#peerdependencies)

          package-lock-json官方文檔 (https://docs.npmjs.com/configuring-npm/package-lock-json.html#requires)

          npm文檔總結(jié) (https://juejin.im/post/6844903582337237006#heading-0)

          npm-pack (https://www.npmjs.cn/cli/pack/)




          推薦閱讀




          我的公眾號能帶來什么價值?(文末有送書規(guī)則,一定要看)

          每個前端工程師都應(yīng)該了解的圖片知識(長文建議收藏)

          為什么現(xiàn)在面試總是面試造火箭?

          瀏覽 77
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产无码久 | 国产日本在线观看 | 99精品视频在线观看免费 | 91人妻人人澡人人爽 | 久热官网 |