問(wèn)題思考:
1. package-lock.json的意義?
2. npm 拉包機(jī)制和源碼實(shí)現(xiàn) ?
3. yarn?
4. package-lock.json有沒(méi)有必要提交刑峡?
5.?npmrc?
6.?npx?
7. 還有 import 直接導(dǎo)入包的cnd地址 和 安裝到本地有啥區(qū)別:(打包時(shí)候的vender 大小 和 是否在緩存獲取的取舍)?
...
1. package-lock.json的意義?蹦到官網(wǎng)
This file is intended to be committed into source repositories, and serves various purposes:
1. Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies.
2. Provide a facility for users to "time-travel" to previous states of node_modules without having to commit the directory itself.
3. Facilitate greater visibility of tree changes through readable source control diffs.
4. Optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.
5.? As of npm v7, lockfiles include enough information to gain a complete picture of the package tree, reducing the need to read package.json files, and allowing for significant performance improvements.
該文件旨在提交到源存儲(chǔ)庫(kù)中,并具有多種用途:
1. 描述一個(gè)依賴(lài)關(guān)系樹(shù)的單一表示锄开,這樣可以確保隊(duì)友,部署和持續(xù)集成安裝完全相同的依賴(lài)關(guān)系弓熏。
2. 為用戶(hù)提供一種工具,使其可以“時(shí)間旅行”到以前的狀態(tài),?node_modules而不必提交目錄本身诚亚。
3. 通過(guò)可讀的源代碼控制差異,提高樹(shù)更改的可見(jiàn)性午乓。
4. 通過(guò)允許npm跳過(guò)先前安裝的程序包的重復(fù)元數(shù)據(jù)解析來(lái)優(yōu)化安裝過(guò)程站宗。
5. 從npm v7開(kāi)始,鎖定文件包含足夠的信息以獲取軟件包樹(shù)的完整圖片益愈,從而減少了讀取package.json?文件的需求并顯著提高了性能份乒。
? 2.?npm 拉包機(jī)制和源碼實(shí)現(xiàn)?來(lái)自拉勾教育,收費(fèi)的那種0.0
2.1 npm install 之后執(zhí)行了哪些步驟?
1.?檢查并獲取 npm 配置或辖,這里的優(yōu)先級(jí)為:項(xiàng)目級(jí)的 .npmrc 文件 > 用戶(hù)級(jí)的 .npmrc 文件> 全局級(jí)的 .npmrc 文件 > npm 內(nèi)置的 .npmrc 文件。
2.?檢查項(xiàng)目中是否有 package-lock.json 文件枣接。
3. 3.1 如果有颂暇,則檢查 package-lock.json 和 package.json 中聲明的依賴(lài)是否一致:
? ? ? ? ?a:?一致,直接使用 package-lock.json 中的信息但惶,從緩存或網(wǎng)絡(luò)資源中加載依賴(lài)耳鸯;
? ? ? ? ?b:?不一致,按照 npm 版本進(jìn)行處理(不同 npm 版本處理會(huì)有不同膀曾,具體處理方式如圖所示)县爬。
? ?3.2 如果沒(méi)有,則根據(jù) package.json 遞歸構(gòu)建依賴(lài)樹(shù)添谊。然后按照構(gòu)建好的依賴(lài)樹(shù)下載完整的依賴(lài)資源财喳,在下載時(shí)就會(huì)檢查是否存在相關(guān)資源緩存:
? ? ? ? a:?存在,則將緩存內(nèi)容解壓到 node_modules 中斩狱;
? ? ? ? b:?否則就先從 npm 遠(yuǎn)程倉(cāng)庫(kù)下載包耳高,校驗(yàn)包的完整性,并添加到緩存所踊,同時(shí)解壓到 node_modules泌枪。
4.?生成 package-lock.json。? ??
2.2 npm 緩存機(jī)制
1. 獲取配置緩存的根目錄:npm config get cache
2.?緩存目錄的內(nèi)容介紹:?打開(kāi)_cacache文件后秕岛,可以看到三個(gè)目錄content-v2,?index-v5,?tmp (空文件)碌燕。
? ? 2.1?content-v2 里面基本都是一些二進(jìn)制文件。為了使這些二進(jìn)制文件可讀继薛,我們把二進(jìn)制文件的擴(kuò)展名改為 .tgz修壕,然后進(jìn)行解壓,得到的結(jié)果其實(shí)就是我們的 npm 包資源惋增。
? ? 2.2?index-v5 文件中叠殷,這些內(nèi)容是 content-v2 里文件的索引。
3. 緩存如何被利用:?
? ?3.1 當(dāng) npm install 執(zhí)行時(shí)诈皿,通過(guò)pacote把相應(yīng)的包解壓在對(duì)應(yīng)的 node_modules 下面林束。npm 在下載依賴(lài)時(shí),先下載到緩存當(dāng)中稽亏,再解壓到項(xiàng)目 node_modules 下壶冒。pacote 依賴(lài)npm-registry-fetch來(lái)下載包,npm-registry-fetch 可以通過(guò)設(shè)置 cache 屬性截歉,在給定的路徑下根據(jù)IETF RFC 7234生成緩存數(shù)據(jù)胖腾。
????3.2 在每次安裝資源時(shí),根據(jù) package-lock.json 中存儲(chǔ)的 integrity、version咸作、name 信息生成一個(gè)唯一的 key锨阿,這個(gè) key 能夠?qū)?yīng)到 index-v5 目錄下的緩存記錄。如果發(fā)現(xiàn)有緩存資源记罚,就會(huì)找到 tar 包的 hash墅诡,根據(jù) hash 再去找緩存的 tar 包,并再次通過(guò)pacote把對(duì)應(yīng)的二進(jìn)制文件解壓到相應(yīng)的項(xiàng)目 node_modules 下面桐智,省去了網(wǎng)絡(luò)下載資源的開(kāi)銷(xiāo)末早。注意,這里提到的緩存策略是從 npm v5 版本開(kāi)始的说庭。在 npm v5 版本之前然磷,每個(gè)緩存的模塊在 ~/.npm 文件夾中以模塊名的形式直接存儲(chǔ),儲(chǔ)存結(jié)構(gòu)是:{cache}/{name}/{version}刊驴。
3. yarn?來(lái)自拉勾教育姿搜,收費(fèi)的那種0.0
3.1 yarn的介紹
????當(dāng) npm 還處在 v3 時(shí)期時(shí),一個(gè)叫作 Yarn 的包管理方案橫空出世缺脉。2016 年痪欲,npm 還沒(méi)有 package-lock.json 文件,安裝速度很慢攻礼,穩(wěn)定性也較差业踢,而 Yarn 的理念很好地解決了以下問(wèn)題。
1. 確定性:通過(guò) yarn.lock 等機(jī)制礁扮,保證了確定性知举。即不管安裝順序如何,相同的依賴(lài)關(guān)系在任何機(jī)器和環(huán)境下太伊,都可以以相同的方式被安裝雇锡。(在 npm v5 之前,沒(méi)有 package-lock.json 機(jī)制僚焦,只有默認(rèn)并不會(huì)使用的npm-shrinkwrap.json锰提。)
2. 采用模塊扁平安裝模式:將依賴(lài)包的不同版本,按照一定策略芳悲,歸結(jié)為單個(gè)版本立肘,以避免創(chuàng)建多個(gè)副本造成冗余(npm 目前也有相同的優(yōu)化)。
3. 網(wǎng)絡(luò)性能更好:Yarn 采用了請(qǐng)求排隊(duì)的理念名扛,類(lèi)似并發(fā)連接池谅年,能夠更好地利用網(wǎng)絡(luò)資源;同時(shí)引入了更好的安裝失敗時(shí)的重試機(jī)制肮韧。
4. 采用緩存機(jī)制融蹂,實(shí)現(xiàn)了離線(xiàn)模式(npm 目前也有類(lèi)似實(shí)現(xiàn))旺订。
3.2 yarn安裝機(jī)制和背后思想
Yarn 的安裝過(guò)程主要有以下 5 大步驟:檢測(cè)(checking)→ 解析包(Resolving Packages) → 獲取包(Fetching Packages)→ 鏈接包(Linking Packages)→ 構(gòu)建包(Building Packages)
1.?檢測(cè)包(checking):?這一步主要是檢測(cè)項(xiàng)目中是否存在一些 npm 相關(guān)文件,比如 package-lock.json 等超燃。如果有区拳,會(huì)提示用戶(hù)注意:這些文件的存在可能會(huì)導(dǎo)致沖突。在這一步驟中淋纲,也會(huì)檢查系統(tǒng) OS劳闹、CPU 等信息。
2.?解析包(Resolving Packages):這一步會(huì)解析依賴(lài)樹(shù)中每一個(gè)包的版本信息洽瞬。
? ? 2.1 首先獲取當(dāng)前項(xiàng)目中 package.json 定義的 dependencies、devDependencies业汰、optionalDependencies 的內(nèi)容伙窃,這屬于首層依賴(lài)。
? ? 2.2 接著采用遍歷首層依賴(lài)的方式獲取依賴(lài)包的版本信息样漆,以及遞歸查找每個(gè)依賴(lài)下嵌套依賴(lài)的版本信息为障,并將解析過(guò)和正在解析的包用一個(gè) Set 數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ),這樣就能保證同一個(gè)版本范圍內(nèi)的包不會(huì)被重復(fù)解析放祟。
? ? ? ? 2.2.1?對(duì)于沒(méi)有解析過(guò)的包 A鳍怨,首次嘗試從 yarn.lock 中獲取到版本信息,并標(biāo)記為已解析跪妥;
? ? ? ? 2.2.2?如果在 yarn.lock 中沒(méi)有找到包 A鞋喇,則向 Registry 發(fā)起請(qǐng)求獲取滿(mǎn)足版本范圍的已知最高版本的包信息,獲取后將當(dāng)前包標(biāo)記為已解析眉撵。
總之侦香,在經(jīng)過(guò)解析包這一步之后,我們就確定了所有依賴(lài)的具體版本信息以及下載地址纽疟。
3.?獲取包(Fetching Packages):首先需要檢查緩存中是否存在當(dāng)前的依賴(lài)包罐韩,同時(shí)將緩存中不存在的依賴(lài)包下載到緩存目錄。
如何判斷緩存中是否存在當(dāng)前的依賴(lài)包污朽?
? ??Yarn 會(huì)根據(jù) cacheFolder+slug+node_modules+pkg.name 生成一個(gè) path散吵,判斷系統(tǒng)中是否存在該 path,如果存在證明已經(jīng)有緩存蟆肆,不用重新下載矾睦。這個(gè) path 也就是依賴(lài)包緩存的具體路徑。
????對(duì)于沒(méi)有命中緩存的包颓芭,Yarn 會(huì)維護(hù)一個(gè) fetch 隊(duì)列顷锰,按照規(guī)則進(jìn)行網(wǎng)絡(luò)請(qǐng)求。如果下載包地址是一個(gè) file 協(xié)議亡问,或者是相對(duì)路徑官紫,就說(shuō)明其指向一個(gè)本地目錄肛宋,此時(shí)調(diào)用 Fetch From Local 從離線(xiàn)緩存中獲取包;否則調(diào)用 Fetch From External 獲取包束世。最終獲取結(jié)果使用 fs.createWriteStream 寫(xiě)入到緩存目錄下酝陈。
4.?鏈接包(Linking Packages):這一步是將項(xiàng)目中的依賴(lài)復(fù)制到項(xiàng)目 node_modules 下,同時(shí)遵循扁平化原則毁涉。在復(fù)制依賴(lài)前沉帮,Yarn 會(huì)先解析 peerDependencies,如果找不到符合 peerDependencies 的包贫堰,則進(jìn)行 warning 提示穆壕,并最終拷貝依賴(lài)到項(xiàng)目中。5.
5.?構(gòu)建包(Building Packages):如果依賴(lài)包中存在二進(jìn)制包需要進(jìn)行編譯其屏,會(huì)在這一步進(jìn)行喇勋。
3.3 扁平化安裝模式
舉個(gè)??: 項(xiàng)目中有A依賴(lài)v1.0, A又依賴(lài)Bv1.0偎行。
當(dāng)項(xiàng)目新添加了 C 依賴(lài)川背,而它依賴(lài)另一個(gè)版本的 B v2.0。這時(shí)候版本要求不一致導(dǎo)致沖突蛤袒,B v2.0 沒(méi)辦法放在項(xiàng)目平鋪目錄下的 node_moduls 文件當(dāng)中熄云,npm v3 會(huì)把 C 依賴(lài)的 B v2.0 安裝在 C 的 node_modules 下:
接下來(lái),在 npm v3 中妙真,假如我們的 App 現(xiàn)在還需要依賴(lài)一個(gè) D缴允,而 D 也依賴(lài) B v2.0 ,我們會(huì)得到如下結(jié)構(gòu):
為什么 B v1.0 出現(xiàn)在項(xiàng)目頂層 node_modules隐孽,而不是 B v2.0 出現(xiàn)在 node_modules 頂層呢癌椿?
假設(shè)這時(shí)候項(xiàng)目又添加了一個(gè)依賴(lài) E ,E 依賴(lài)了 B v1.0 菱阵,安裝 E 之后踢俄,我們會(huì)得到這樣一個(gè)結(jié)構(gòu):
如果我們想更新模塊 A 為 v2.0,而模塊 A v2.0 依賴(lài)了 B v2.0晴及,npm v3 會(huì)怎么處理呢都办?它的結(jié)構(gòu)如下:
為什么Bv1.0依然存在?
這時(shí)模塊 B v2.0 分別出現(xiàn)在了 A虑稼、C琳钉、D 模塊下——重復(fù)存在了。
通過(guò)這一系列操作我們可以看到:npm 包的安裝順序?qū)τ谝蕾?lài)樹(shù)的影響很大蛛倦。模塊安裝順序可能影響 node_modules 內(nèi)的文件數(shù)量歌懒。
這里一個(gè)更理想的依賴(lài)結(jié)構(gòu)理應(yīng)是:
過(guò)了一段時(shí)間,模塊 E v2.0 發(fā)布了溯壶,并且 E v2.0 也依賴(lài)了模塊 B v2.0 及皂,npm v3 更新 E 時(shí)會(huì)怎么做呢甫男?
此時(shí)頂層已經(jīng)有了B v2.0,如何刪除嵌套層多余的B v2.0?
1. 刪除node_modules, 重新安裝验烧。
2. npm dedupe命令
結(jié)構(gòu)如下:
實(shí)際上板驳,Yarn 在安裝依賴(lài)時(shí)會(huì)自動(dòng)執(zhí)行 dedupe 命令。整個(gè)優(yōu)化的安裝過(guò)程碍拆,就是扁平化安裝模式若治。
4.?package-lock.json有沒(méi)有必要提交?
看項(xiàng)目定位感混。
1. 如果開(kāi)發(fā)一個(gè)應(yīng)用端幼,我建議把 package-lock.json 文件提交到代碼版本倉(cāng)庫(kù)。這樣可以保證項(xiàng)目組成員弧满、運(yùn)維部署成員或者 CI 系統(tǒng)静暂,在執(zhí)行 npm install 后,能得到完全一致的依賴(lài)安裝內(nèi)容谱秽。
2.?如果你的目標(biāo)是開(kāi)發(fā)一個(gè)給外部使用的庫(kù),那就要謹(jǐn)慎考慮了摹迷,因?yàn)閹?kù)項(xiàng)目一般是被其他項(xiàng)目依賴(lài)的疟赊,在不使用 package-lock.json 的情況下,就可以復(fù)用主項(xiàng)目已經(jīng)加載過(guò)的包峡碉,減少依賴(lài)重復(fù)和體積近哟。
3.?如果我們開(kāi)發(fā)的庫(kù)依賴(lài)了一個(gè)精確版本號(hào)的模塊,那么提交 lockfiles 到倉(cāng)庫(kù)可能會(huì)造成同一個(gè)依賴(lài)不同版本都被下載的情況鲫寄。如果作為庫(kù)開(kāi)發(fā)者吉执,真的有使用某個(gè)特定版本依賴(lài)的需要,一個(gè)更好的方式是定義 peerDependencies地来。因此戳玫,一個(gè)推薦的做法是:把 package-lock.json 一起提交到代碼庫(kù)中,不需要 ignore未斑。但是執(zhí)行 npm publish 命令咕宿,發(fā)布一個(gè)庫(kù)的時(shí)候,它應(yīng)該被忽略而不是直接發(fā)布出去蜡秽。
補(bǔ)充: package-lock.json是無(wú)法發(fā)布
5. npmrc 蹦官網(wǎng)
npm 的配置文件
npm gets its config settings from the command line, environment variables, and?npmrc?files.
The four relevant files are:
? ? 1. per-project config file (/path/to/my/project/.npmrc)
? ? 2. per-user config file (~/.npmrc)
? ? 3. global config file ($PREFIX/etc/npmrc)
? ? 4. npm builtin config file (/path/to/npm/npmrc)
6. npx?
npm 從5.2版開(kāi)始府阀,增加了 npx 命令。Node 自帶 npm 模塊芽突,所以可以直接使用 npx 命令试浙。萬(wàn)一不能用,就要手動(dòng)安裝一下寞蚌。
npm install -g npx使用場(chǎng)景:?
1.?調(diào)用項(xiàng)目安裝的模塊田巴, (npx mocha --version)
2.?避免全局安裝模塊 (npx http-server)
3.?使用不同版本的 node (npx node@0.12.8 -v)
4.?執(zhí)行 GitHub 源碼 (npx github:piuccio/cowsay hello)
? ??注意钠糊,遠(yuǎn)程代碼必須是一個(gè)模塊,即必須包含package.json和入口腳本固额。
7. cdn vs local?
影響因素:
1. 離線(xiàn)開(kāi)發(fā)眠蚂?
2. cdn大文件,local小文件斗躏?
3. 預(yù)緩存保證逝慧?
4. 禁止訪(fǎng)問(wèn)(國(guó)家/地區(qū) 封鎖某些cdn服務(wù)的域或IP)
5. 兩點(diǎn)故障?(站點(diǎn)宕機(jī))
6. 安全性啄糙?(修改代碼笛臣,收集用戶(hù)系統(tǒng)數(shù)據(jù)。隧饼。沈堡。)
7. 失去控制權(quán)?(網(wǎng)站文件控制權(quán))
8. 訪(fǎng)問(wèn)速度燕雁?
參考:?