溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

node.js npm的包管理機(jī)制是什么

發(fā)布時間:2022-08-09 11:20:33 來源:億速云 閱讀:123 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“node.js npm的包管理機(jī)制是什么”的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“node.js npm的包管理機(jī)制是什么”文章能幫助大家解決問題。

node.js npm的包管理機(jī)制是什么

一、剖析 package.json

Node.js 中,模塊是一個庫或框架,也是一個 Node.js 項(xiàng)目。Node.js 項(xiàng)目遵循模塊化的架構(gòu),當(dāng)我們創(chuàng)建了一個 Node.js 項(xiàng)目,意味著創(chuàng)建了一個模塊,這個模塊必須有一個描述文件,即 package.json。它是我們最常見的配置文件,但是它里面的配置你真的有詳細(xì)了解過嗎?配置一個合理的 package.json 文件直接決定著我們項(xiàng)目的質(zhì)量,所以首先帶大家分析下 package.json 的各項(xiàng)詳細(xì)配置。

1.1 必備屬性

package.json 中有非常多的屬性,其中必須填寫的只有兩個:nameversion ,這兩個屬性組成一個 npm 模塊的唯一標(biāo)識。

npm包命名規(guī)則

name 即模塊名稱,其命名時需要遵循官方的一些規(guī)范和建議:

  • 包名會成為模塊url、命令行中的一個參數(shù)或者一個文件夾名稱,任何非url安全的字符在包名中都不能使用,可以使用 validate-npm-package-name 包來檢測包名是否合法。

  • 語義化包名,可以幫助開發(fā)者更快的找到需要的包,并且避免意外獲取錯誤的包。

  • 若包名稱中存在一些符號,將符號去除后不得與現(xiàn)有包名重復(fù)

例如:由于react-native已經(jīng)存在,react.native、reactnative都不可以再創(chuàng)建。

  • 如果你的包名與現(xiàn)有的包名太相近導(dǎo)致你不能發(fā)布這個包,那么推薦將這個包發(fā)布到你的作用域下。

例如:用戶名 conard,那么作用域?yàn)?@conard,發(fā)布的包可以是@conard/react。

查看包是否被占用

name 是一個包的唯一標(biāo)識,不得和其他包名重復(fù),我們可以執(zhí)行 npm view packageName 查看包是否被占用,并可以查看它的一些基本信息:

node.js npm的包管理機(jī)制是什么

若包名稱從未被使用過,則會拋出 404 錯誤:

node.js npm的包管理機(jī)制是什么

另外,你還可以去 https://www.npmjs.com/ 查詢更多更詳細(xì)的包信息。

1.2描述信息

基本描述
{
  "description": "An enterprise-class UI design language and React components implementation",
  "keywords": [
    "ant",
    "component",
    "components",
    "design",
    "framework",
    "frontend",
    "react",
    "react-component",
    "ui"
  ]
}

description用于添加模塊的的描述信息,方便別人了解你的模塊。

keywords用于給你的模塊添加關(guān)鍵字。

當(dāng)然,他們的還有一個非常重要的作用,就是利于模塊檢索。當(dāng)你使用 npm search 檢索模塊時,會到descriptionkeywords 中進(jìn)行匹配。寫好 descriptionkeywords 有利于你的模塊獲得更多更精準(zhǔn)的曝光:

node.js npm的包管理機(jī)制是什么

開發(fā)人員

描述開發(fā)人員的字段有兩個:authorcontributorsauthor 指包的主要作者,一個 author 對應(yīng)一個人。 contributors 指貢獻(xiàn)者信息,一個 contributors 對應(yīng)多個貢獻(xiàn)者,值為數(shù)組,對人的描述可以是一個字符串,也可以是下面的結(jié)構(gòu):

{ 
    "name" : "ConardLi", 
    "email" : "lisqPersion@163.com", 
    "url" : "https://github.com/ConardLi"
}
地址
{
  "homepage": "http://ant.design/",
  "bugs": {
    "url": "https://github.com/ant-design/ant-design/issues"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/ant-design/ant-design"
  },
}

homepage 用于指定該模塊的主頁。

repository 用于指定模塊的代碼倉庫。

node.js npm的包管理機(jī)制是什么

bugs 指定一個地址或者一個郵箱,對你的模塊存在疑問的人可以到這里提出問題。

1.3 依賴配置

我們的項(xiàng)目可能依賴一個或多個外部依賴包,根據(jù)依賴包的不同用途,我們將他們配置在下面幾個屬性下:dependencies、devDependencies、peerDependencies、bundledDependencies、optionalDependencies。

配置規(guī)則

在介紹幾種依賴配置之前,首先我們來看一下依賴的配置規(guī)則,你看到的依賴包配置可能是下面這樣的:

 "dependencies": {
      "antd": "ant-design/ant-design#4.0.0-alpha.8",
      "axios": "^1.2.0",
      "test-js": "file:../test",
      "test2-js": "http://cdn.com/test2-js.tar.gz",
      "core-js": "^1.1.5",
 }

依賴配置遵循下面幾種配置規(guī)則:

  • 依賴包名稱:VERSION

    • VERSION是一個遵循SemVer規(guī)范的版本號配置,npm install 時將到npm服務(wù)器下載符合指定版本范圍的包。

  • 依賴包名稱:DWONLOAD_URL

    • DWONLOAD_URL 是一個可下載的tarball壓縮包地址,模塊安裝時會將這個.tar下載并安裝到本地。

  • 依賴包名稱:LOCAL_PATH

    • LOCAL_PATH 是一個本地的依賴包路徑,例如 file:../pacakges/pkgName。適用于你在本地測試一個npm包,不應(yīng)該將這種方法應(yīng)用于線上。

  • 依賴包名稱:GITHUB_URL

    • GITHUB_URLgithubusername/modulename 的寫法,例如:ant-design/ant-design,你還可以在后面指定 tagcommit id。

  • 依賴包名稱:GIT_URL

    • GIT_URL 即我們平時clone代碼庫的 git url,其遵循以下形式:

<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]

其中 protocal 可以是以下幾種形式:

  • git://github.com/user/project.git#commit-ish

  • git+ssh://user@hostname:project.git#commit-ish

  • git+ssh://user@hostname/project.git#commit-ish

  • git+http://user@hostname/project/blah.git#commit-ish

  • git+https://user@hostname/project/blah.git#commit-ish

dependencies

dependencies 指定了項(xiàng)目運(yùn)行所依賴的模塊,開發(fā)環(huán)境和生產(chǎn)環(huán)境的依賴模塊都可以配置到這里,例如

 "dependencies": {
      "lodash": "^4.17.13",
      "moment": "^2.24.0",
 }
devDependencies

有一些包有可能你只是在開發(fā)環(huán)境中用到,例如你用于檢測代碼規(guī)范的 eslint ,用于進(jìn)行測試的 jest ,用戶使用你的包時即使不安裝這些依賴也可以正常運(yùn)行,反而安裝他們會耗費(fèi)更多的時間和資源,所以你可以把這些依賴添加到 devDependencies 中,這些依賴照樣會在你本地進(jìn)行 npm install 時被安裝和管理,但是不會被安裝到生產(chǎn)環(huán)境:

 "devDependencies": {
      "jest": "^24.3.1",
      "eslint": "^6.1.0",
 }
peerDependencies

peerDependencies 用于指定你正在開發(fā)的模塊所依賴的版本以及用戶安裝的依賴包版本的兼容性。

上面的說法可能有點(diǎn)太抽象,我們直接拿 ant-design 來舉個例子,ant-designpackage.json 中有如下配置:

  "peerDependencies": {
    "react": ">=16.0.0",
    "react-dom": ">=16.0.0"
  }

當(dāng)你正在開發(fā)一個系統(tǒng),使用了 ant-design ,所以也肯定需要依賴 React。同時, ant-design 也是需要依賴 React 的,它要保持穩(wěn)定運(yùn)行所需要的 React 版本是16.0.0,而你開發(fā)時依賴的 React 版本是 15.x

這時,ant-design 要使用 React,并將其引入:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

這時取到的是宿主環(huán)境也就是你的環(huán)境中的 React 版本,這就可能造成一些問題。在 npm2 的時候,指定上面的 peerDependencies 將意味著強(qiáng)制宿主環(huán)境安裝 react@>=16.0.0和react-dom@>=16.0.0 的版本。

npm3 以后不會再要求 peerDependencies 所指定的依賴包被強(qiáng)制安裝,相反 npm3 會在安裝結(jié)束后檢查本次安裝是否正確,如果不正確會給用戶打印警告提示。

  "dependencies": {
    "react": "15.6.0",
    "antd": "^3.22.0"
  }

例如,我在項(xiàng)目中依賴了 antd 的最新版本,然后依賴了 react15.6.0版本,在進(jìn)行依賴安裝時將給出以下警告:

node.js npm的包管理機(jī)制是什么

optionalDependencies

某些場景下,依賴包可能不是強(qiáng)依賴的,這個依賴包的功能可有可無,當(dāng)這個依賴包無法被獲取到時,你希望 npm install 繼續(xù)運(yùn)行,而不會導(dǎo)致失敗,你可以將這個依賴放到 optionalDependencies 中,注意 optionalDependencies 中的配置將會覆蓋掉 dependencies 所以只需在一個地方進(jìn)行配置。

當(dāng)然,引用 optionalDependencies 中安裝的依賴時,一定要做好異常處理,否則在模塊獲取不到時會導(dǎo)致報(bào)錯。

bundledDependencies

和以上幾個不同,bundledDependencies 的值是一個數(shù)組,數(shù)組里可以指定一些模塊,這些模塊將在這個包發(fā)布時被一起打包。

  "bundledDependencies": ["package1" , "package2"]

1.4 協(xié)議

{
    "license": "MIT"
}

license 字段用于指定軟件的開源協(xié)議,開源協(xié)議里面詳盡表述了其他人獲得你代碼后擁有的權(quán)利,可以對你的的代碼進(jìn)行何種操作,何種操作又是被禁止的。同一款協(xié)議有很多變種,協(xié)議太寬松會導(dǎo)致作者喪失對作品的很多權(quán)利,太嚴(yán)格又不便于使用者使用及作品的傳播,所以開源作者要考慮自己對作品想保留哪些權(quán)利,放開哪些限制。

軟件協(xié)議可分為開源和商業(yè)兩類,對于商業(yè)協(xié)議,或者叫法律聲明、許可協(xié)議,每個軟件會有自己的一套行文,由軟件作者或?qū)iT律師撰寫,對于大多數(shù)人來說不必自己花時間和精力去寫繁長的許可協(xié)議,選擇一份廣為流傳的開源協(xié)議就是個不錯的選擇。

以下就是幾種主流的開源協(xié)議:

node.js npm的包管理機(jī)制是什么

  • MIT:只要用戶在項(xiàng)目副本中包含了版權(quán)聲明和許可聲明,他們就可以拿你的代碼做任何想做的事情,你也無需承擔(dān)任何責(zé)任。

  • Apache:類似于 MIT,同時還包含了貢獻(xiàn)者向用戶提供專利授權(quán)相關(guān)的條款。

  • GPL:修改項(xiàng)目代碼的用戶再次分發(fā)源碼或二進(jìn)制代碼時,必須公布他的相關(guān)修改。

如果你對開源協(xié)議有更詳細(xì)的要求,可以到 choosealicense.com/ 獲取更詳細(xì)的開源協(xié)議說明。

node.js npm的包管理機(jī)制是什么

1.5 目錄、文件相關(guān)

程序入口
{
  "main": "lib/index.js",
}

main 屬性可以指定程序的主入口文件,例如,上面 antd 指定的模塊入口 lib/index.js ,當(dāng)我們在代碼用引入 antd 時:import { notification } from 'antd'; 實(shí)際上引入的就是 lib/index.js 中暴露出去的模塊。

node.js npm的包管理機(jī)制是什么

命令行工具入口

當(dāng)你的模塊是一個命令行工具時,你需要為命令行工具指定一個入口,即指定你的命令名稱和本地可指定文件的對應(yīng)關(guān)系。如果是全局安裝,npm 將會使用符號鏈接把可執(zhí)行文件鏈接到 /usr/local/bin,如果是本地安裝,會鏈接到 ./node_modules/.bin/。

{
    "bin": {
    "conard": "./bin/index.js"
  }
}

例如上面的配置:當(dāng)你的包安裝到全局時:npm 會在 /usr/local/bin下創(chuàng)建一個以 conard 為名字的軟鏈接,指向全局安裝下來的 conard 包下面的 "./bin/index.js"。這時你在命令行執(zhí)行 conard 則會調(diào)用鏈接到的這個js文件。

這里不再過多展開,更多內(nèi)容在我后續(xù)的命令行工具文章中會進(jìn)行詳細(xì)講解。

發(fā)布文件配置
{
    "files": [
      "dist",
      "lib",
      "es"
    ]
}

files 屬性用于描述你 npm publish 后推送到 npm 服務(wù)器的文件列表,如果指定文件夾,則文件夾內(nèi)的所有內(nèi)容都會包含進(jìn)來。我們可以看到下載后的包是下面的目錄結(jié)構(gòu):

node.js npm的包管理機(jī)制是什么

另外,你還可以通過配置一個 .npmignore 文件來排除一些文件, 防止大量的垃圾文件推送到 npm, 規(guī)則上和你用的 .gitignore 是一樣的。.gitignore 文件也可以充當(dāng).npmignore 文件。

man

man 命令是 Linux 下的幫助指令,通過 man 指令可以查看 Linux 中的指令幫助、配置文件幫助和編程幫助等信息。

如果你的 node.js 模塊是一個全局的命令行工具,在 package.json 通過 man  屬性可以指定 man 命令查找的文檔地址。

man 文件必須以數(shù)字結(jié)尾,或者如果被壓縮了,以 .gz 結(jié)尾。數(shù)字表示文件將被安裝到 man 的哪個部分。如果 man 文件名稱不是以模塊名稱開頭的,安裝的時候會給加上模塊名稱前綴。

例如下面這段配置:

{ 
  "man" : [ 
    "/Users/isaacs/dev/npm/cli/man/man1/npm-access.1",
    "/Users/isaacs/dev/npm/cli/man/man1/npm-audit.1"
  ]
}

在命令行輸入 man npm-audit

node.js npm的包管理機(jī)制是什么

規(guī)范項(xiàng)目目錄

一個 node.js 模塊是基于 CommonJS 模塊化規(guī)范實(shí)現(xiàn)的,嚴(yán)格按照 CommonJS 規(guī)范,模塊目錄下除了必須包含包描述文件 package.json 以外,還需要包含以下目錄:

  • bin:存放可執(zhí)行二進(jìn)制文件的目錄

  • lib:存放js代碼的目錄

  • doc:存放文檔的目錄

  • test:存放單元測試用例代碼的目錄

  • ...

在模塊目錄中你可能沒有嚴(yán)格按照以上結(jié)構(gòu)組織或命名,你可以通過在 package.json 指定 directories 屬性來指定你的目錄結(jié)構(gòu)和上述的規(guī)范結(jié)構(gòu)的對應(yīng)情況。除此之外 directories 屬性暫時沒有其他應(yīng)用。

{
  "directories": {
    "lib": "src/lib/",
    "bin": "src/bin/",
    "man": "src/man/",
    "doc": "src/doc/",
    "example": "src/example/"
  }
}

不過官方文檔表示,雖然目前這個屬性沒有什么重要作用,未來可能會整出一些花樣出來,例如:doc 中存放的 markdown 文件、example 中存放的示例文件,可能會友好的展示出來。

1.6 腳本配置

script
{
  "scripts": {
    "test": "jest --config .jest.js --no-cache",
    "dist": "antd-tools run dist",
    "compile": "antd-tools run compile",
    "build": "npm run compile && npm run dist"
  }
}

scripts 用于配置一些腳本命令的縮寫,各個腳本可以互相組合使用,這些腳本可以覆蓋整個項(xiàng)目的生命周期,配置后可使用 npm run command 進(jìn)行調(diào)用。如果是 npm 關(guān)鍵字,則可以直接調(diào)用。例如,上面的配置制定了以下幾個命令:npm run test、npm run distnpm run compile、npm run build。

config

config 字段用于配置腳本中使用的環(huán)境變量,例如下面的配置,可以在腳本中使用process.env.npm_package_config_port進(jìn)行獲取。

{
  "config" : { "port" : "8080" }
}

1.7 發(fā)布配置

preferGlobal

如果你的 node.js 模塊主要用于安裝到全局的命令行工具,那么該值設(shè)置為 true ,當(dāng)用戶將該模塊安裝到本地時,將得到一個警告。這個配置并不會阻止用戶安裝,而是會提示用戶防止錯誤使用而引發(fā)一些問題。

private

如果將 private 屬性設(shè)置為 true,npm將拒絕發(fā)布它,這是為了防止一個私有模塊被無意間發(fā)布出去。

node.js npm的包管理機(jī)制是什么

publishConfig
  "publishConfig": {
    "registry": "https://registry.npmjs.org/"
  },

發(fā)布模塊時更詳細(xì)的配置,例如你可以配置只發(fā)布某個 tag、配置發(fā)布到的私有 npm 源。更詳細(xì)的配置可以參考 npm-config

os

假如你開發(fā)了一個模塊,只能跑在 darwin 系統(tǒng)下,你需要保證 windows 用戶不會安裝到你的模塊,從而避免發(fā)生不必要的錯誤。

使用 os 屬性可以幫助你完成以上的需求,你可以指定你的模塊只能被安裝在某些系統(tǒng)下,或者指定一個不能安裝的系統(tǒng)黑名單:

"os" : [ "darwin", "linux" ]
"os" : [ "!win32" ]

例如,我把一個測試模塊指定一個系統(tǒng)黑名單:"os" : [ "!darwin" ],當(dāng)我在此系統(tǒng)下安裝它時會爆出如下錯誤:

node.js npm的包管理機(jī)制是什么

在node環(huán)境下可以使用 process.platform 來判斷操作系統(tǒng)。

cpu

和上面的 os 類似,我們可以用 cpu 屬性更精準(zhǔn)的限制用戶安裝環(huán)境:

"cpu" : [ "x64", "ia32" ]
"cpu" : [ "!arm", "!mips" ]

在node環(huán)境下可以使用 process.arch 來判斷 cpu 架構(gòu)。

二、剖析包版本管理機(jī)制

Nodejs成功離不開 npm 優(yōu)秀的依賴管理系統(tǒng)。在介紹整個依賴系統(tǒng)之前,必須要了解 npm如何管理依賴包的版本,本章將介紹 npm包 的版本發(fā)布規(guī)范、如何管理各種依賴包的版本以及一些關(guān)于包版本的最佳實(shí)踐。

node.js npm的包管理機(jī)制是什么

2.1 查看npm包版本

你可以執(zhí)行 npm view package version 查看某個 package 的最新版本。

執(zhí)行 npm view conard versions 查看某個 package 在npm服務(wù)器上所有發(fā)布過的版本。

node.js npm的包管理機(jī)制是什么

執(zhí)行 npm ls 可查看當(dāng)前倉庫依賴樹上所有包的版本信息。

node.js npm的包管理機(jī)制是什么

2.2 SemVer規(guī)范

npm包 中的模塊版本都需要遵循 SemVer規(guī)范——由 Github 起草的一個具有指導(dǎo)意義的,統(tǒng)一的版本號表示規(guī)則。實(shí)際上就是 Semantic Version(語義化版本)的縮寫。

SemVer規(guī)范官網(wǎng): https://semver.org/

標(biāo)準(zhǔn)版本

SemVer規(guī)范的標(biāo)準(zhǔn)版本號采用 X.Y.Z 的格式,其中 X、Y 和 Z 為非負(fù)的整數(shù),且禁止在數(shù)字前方補(bǔ)零。X 是主版本號、Y 是次版本號、而 Z 為修訂號。每個元素必須以數(shù)值來遞增。

  • 主版本號(major):當(dāng)你做了不兼容的API 修改

  • 次版本號(minor):當(dāng)你做了向下兼容的功能性新增

  • 修訂號(patch):當(dāng)你做了向下兼容的問題修正。

例如:1.9.1 -> 1.10.0 -> 1.11.0

先行版本

當(dāng)某個版本改動比較大、并非穩(wěn)定而且可能無法滿足預(yù)期的兼容性需求時,你可能要先發(fā)布一個先行版本。

先行版本號可以加到“主版本號.次版本號.修訂號”的后面,先加上一個連接號再加上一連串以句點(diǎn)分隔的標(biāo)識符和版本編譯信息。

  • 內(nèi)部版本(alpha):

  • 公測版本(beta):

  • 正式版本的候選版本rc: 即 Release candiate

React的版本

下面我們來看看 React 的歷史版本:

node.js npm的包管理機(jī)制是什么

可見是嚴(yán)格按照 SemVer 規(guī)范來發(fā)版的:

  • 版本號嚴(yán)格按照 主版本號.次版本號.修訂號 格式命名

  • 版本是嚴(yán)格遞增的,:16.8.0 -> 16.8.1 -> 16.8.2

  • 發(fā)布重大版本或版本改動較大時,先發(fā)布alphabeta、rc等先行版本

發(fā)布版本

在修改 npm 包某些功能后通常需要發(fā)布一個新的版本,我們通常的做法是直接去修改 package.json 到指定版本。如果操作失誤,很容易造成版本號混亂,我們可以借助符合 Semver 規(guī)范的命令來完成這一操作:

  • npm version patch : 升級修訂版本號

  • npm version minor : 升級次版本號

  • npm version major : 升級主版本號

2.3 版本工具使用

在開發(fā)中肯定少不了對一些版本號的操作,如果這些版本號符合 SemVer規(guī)范 ,我們可以借助用于操作版本的npm包semver來幫助我們進(jìn)行比較版本大小、提取版本信息等操作。

Npm 也使用了該工具來處理版本相關(guān)的工作。

npm install semver
  • 比較版本號大小

semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
  • 判斷版本號是否符合規(guī)范,返回解析后符合規(guī)范的版本號。

semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
  • 將其他版本號強(qiáng)制轉(zhuǎn)換成semver版本號

semver.valid(semver.coerce('v2')) // '2.0.0'
semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'
  • 一些其他用法

semver.clean('  =v1.2.3   ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.minVersion('>=1.0.0') // '1.0.0'

以上都是semver最常見的用法,更多詳細(xì)內(nèi)容可以查看 semver文檔:https://github.com/npm/node-semver

2.4 依賴版本管理

我們經(jīng)常看到,在 package.json 中各種依賴的不同寫法:

  "dependencies": {
    "signale": "1.4.0",
    "figlet": "*",
    "react": "16.x",
    "table": "~5.4.6",
    "yargs": "^14.0.0"
  }

前面三個很容易理解:

  • "signale": "1.4.0": 固定版本號

  • "figlet": "*": 任意版本(>=0.0.0

  • "react": "16.x": 匹配主要版本(>=16.0.0 <17.0.0

  • "react": "16.3.x": 匹配主要版本和次要版本(>=16.3.0 <16.4.0

再來看看后面兩個,版本號中引用了 ~^ 符號:

  • ~: 當(dāng)安裝依賴時獲取到有新版本時,安裝到 x.y.zz 的最新的版本。即保持主版本號、次版本號不變的情況下,保持修訂號的最新版本。

  • ^: 當(dāng)安裝依賴時獲取到有新版本時,安裝到 x.y.zyz 都為最新版本。 即保持主版本號不變的情況下,保持次版本號、修訂版本號為最新版本。

package.json 文件中最常見的應(yīng)該是 "yargs": "^14.0.0" 這種格式的 依賴, 因?yàn)槲覀冊谑褂?npm install package 安裝包時,npm 默認(rèn)安裝當(dāng)前最新版本,然后在所安裝的版本號前加 ^ 號。

注意,當(dāng)主版本號為 0 的情況,會被認(rèn)為是一個不穩(wěn)定版本,情況與上面不同:

  • 主版本號和次版本號都為 0: ^0.0.z、~0.0.z 都被當(dāng)作固定版本,安裝依賴時均不會發(fā)生變化。

  • 主版本號為 0: ^0.y.z 表現(xiàn)和 ~0.y.z 相同,只保持修訂號為最新版本。

1.0.0 的版本號用于界定公共 API。當(dāng)你的軟件發(fā)布到了正式環(huán)境,或者有穩(wěn)定的API時,就可以發(fā)布1.0.0版本了。所以,當(dāng)你決定對外部發(fā)布一個正式版本的npm包時,把它的版本標(biāo)為1.0.0。

2.5 鎖定依賴版本

lock文件

實(shí)際開發(fā)中,經(jīng)常會因?yàn)楦鞣N依賴不一致而產(chǎn)生奇怪的問題,或者在某些場景下,我們不希望依賴被更新,建議在開發(fā)中使用 package-lock.json。

鎖定依賴版本意味著在我們不手動執(zhí)行更新的情況下,每次安裝依賴都會安裝固定版本。保證整個團(tuán)隊(duì)使用版本號一致的依賴。

每次安裝固定版本,無需計(jì)算依賴版本范圍,大部分場景下能大大加速依賴安裝時間。

使用 package-lock.json 要確保npm的版本在5.6以上,因?yàn)樵?.0 - 5.6中間,對 package-lock.json的處理邏輯進(jìn)行過幾次更新,5.6版本后處理邏輯逐漸穩(wěn)定。

關(guān)于 package-lock.json 詳細(xì)的結(jié)構(gòu),我們會在后面的章節(jié)進(jìn)行解析。

定期更新依賴

我們的目的是保證團(tuán)隊(duì)中使用的依賴一致或者穩(wěn)定,而不是永遠(yuǎn)不去更新這些依賴。實(shí)際開發(fā)場景下,我們雖然不需要每次都去安裝新的版本,仍然需要定時去升級依賴版本,來讓我們享受依賴包升級帶來的問題修復(fù)、性能提升、新特性更新。

node.js npm的包管理機(jī)制是什么

使用 npm outdated 可以幫助我們列出有哪些還沒有升級到最新版本的依賴:

  • 黃色表示不符合我們指定的語意化版本范圍 - 不需要升級

  • 紅色表示符合指定的語意化版本范圍 - 需要升級

執(zhí)行 npm update 會升級所有的紅色依賴。

2.6 依賴版本選擇的最佳實(shí)踐

版本發(fā)布
  • 對外部發(fā)布一個正式版本的npm包時,把它的版本標(biāo)為1.0.0。

  • 某個包版本發(fā)行后,任何修改都必須以新版本發(fā)行。

  • 版本號嚴(yán)格按照 主版本號.次版本號.修訂號 格式命名

  • 版本號發(fā)布必須是嚴(yán)格遞增的

  • 發(fā)布重大版本或版本改動較大時,先發(fā)布alpha、beta、rc等先行版本

依賴范圍選擇
  • 主工程依賴了很多子模塊,都是團(tuán)隊(duì)成員開發(fā)的npm包,此時建議把版本前綴改為~,如果鎖定的話每次子依賴更新都要對主工程的依賴進(jìn)行升級,非常繁瑣,如果對子依賴完全信任,直接開啟^每次升級到最新版本。

  • 主工程跑在docker線上,本地還在進(jìn)行子依賴開發(fā)和升級,在docker版本發(fā)布前要鎖定所有依賴版本,確保本地子依賴發(fā)布后線上不會出問題。

保持依賴一致
  • 確保npm的版本在5.6以上,確保默認(rèn)開啟 package-lock.json 文件。

  • 由初始化成員執(zhí)行 npm inatall 后,將 package-lock.json 提交到遠(yuǎn)程倉庫。不要直接提交 node_modules到遠(yuǎn)程倉庫。

  • 定期執(zhí)行 npm update 升級依賴,并提交 lock 文件確保其他成員同步更新依賴,不要手動更改 lock 文件。

依賴變更
  • 升級依賴: 修改 package.json文件的依賴版本,執(zhí)行 npm install

  • 降級依賴: 直接執(zhí)行 npm install package@version(改動package.json不會對依賴進(jìn)行降級)

  • 注意改動依賴后提交lock文件

三、剖析 npm install 原理

node.js npm的包管理機(jī)制是什么

npm install 大概會經(jīng)過上面的幾個流程,這一章就來講一講各個流程的實(shí)現(xiàn)細(xì)節(jié)、發(fā)展以及為何要這樣實(shí)現(xiàn)。

3.1 嵌套結(jié)構(gòu)

我們都知道,執(zhí)行 npm install 后,依賴包被安裝到了 node_modules ,下面我們來具體了解下,npm 將依賴包安裝到 node_modules 的具體機(jī)制是什么。

npm 的早期版本, npm 處理依賴的方式簡單粗暴,以遞歸的形式,嚴(yán)格按照 package.json 結(jié)構(gòu)以及子依賴包的 package.json 結(jié)構(gòu)將依賴安裝到他們各自的 node_modules 中。直到有子依賴包不在依賴其他模塊。

舉個例子,我們的模塊 my-app 現(xiàn)在依賴了兩個模塊:buffer、ignore

{
  "name": "my-app",
  "dependencies": {
    "buffer": "^5.4.3",
    "ignore": "^5.1.4",
  }
}

ignore是一個純 JS 模塊,不依賴任何其他模塊,而 buffer 又依賴了下面兩個模塊:base64-js 、 ieee754

{
  "name": "buffer",
  "dependencies": {
    "base64-js": "^1.0.2",
    "ieee754": "^1.1.4"
  }
}

那么,執(zhí)行 npm install 后,得到的 node_modules 中模塊目錄結(jié)構(gòu)就是下面這樣的:

node.js npm的包管理機(jī)制是什么

這樣的方式優(yōu)點(diǎn)很明顯, node_modules 的結(jié)構(gòu)和 package.json 結(jié)構(gòu)一一對應(yīng),層級結(jié)構(gòu)明顯,并且保證了每次安裝目錄結(jié)構(gòu)都是相同的。

但是,試想一下,如果你依賴的模塊非常之多,你的 node_modules 將非常龐大,嵌套層級非常之深:

node.js npm的包管理機(jī)制是什么

  • 在不同層級的依賴中,可能引用了同一個模塊,導(dǎo)致大量冗余。

  • Windows 系統(tǒng)中,文件路徑最大長度為260個字符,嵌套層級過深可能導(dǎo)致不可預(yù)知的問題。

3.2 扁平結(jié)構(gòu)

為了解決以上問題,NPM3.x 版本做了一次較大更新。其將早期的嵌套結(jié)構(gòu)改為扁平結(jié)構(gòu):

  • 安裝模塊時,不管其是直接依賴還是子依賴的依賴,優(yōu)先將其安裝在 node_modules 根目錄。

還是上面的依賴結(jié)構(gòu),我們在執(zhí)行 npm install 后將得到下面的目錄結(jié)構(gòu):

node.js npm的包管理機(jī)制是什么

node.js npm的包管理機(jī)制是什么

此時我們?nèi)粼谀K中又依賴了 base64-js@1.0.1 版本:

{
  "name": "my-app",
  "dependencies": {
    "buffer": "^5.4.3",
    "ignore": "^5.1.4",
    "base64-js": "1.0.1",
  }
}
  • 當(dāng)安裝到相同模塊時,判斷已安裝的模塊版本是否符合新模塊的版本范圍,如果符合則跳過,不符合則在當(dāng)前模塊的 node_modules 下安裝該模塊。

此時,我們在執(zhí)行 npm install 后將得到下面的目錄結(jié)構(gòu):

node.js npm的包管理機(jī)制是什么

node.js npm的包管理機(jī)制是什么

對應(yīng)的,如果我們在項(xiàng)目代碼中引用了一個模塊,模塊查找流程如下:

  • 在當(dāng)前模塊路徑下搜索

  • 在當(dāng)前模塊 node_modules 路徑下搜素

  • 在上級模塊的 node_modules 路徑下搜索

  • ...

  • 直到搜索到全局路徑中的 node_modules

假設(shè)我們又依賴了一個包 buffer2@^5.4.3,而它依賴了包 base64-js@1.0.3,則此時的安裝結(jié)構(gòu)是下面這樣的:

node.js npm的包管理機(jī)制是什么

所以 npm 3.x 版本并未完全解決老版本的模塊冗余問題,甚至還會帶來新的問題。

試想一下,你的APP假設(shè)沒有依賴 base64-js@1.0.1 版本,而你同時依賴了依賴不同 base64-js 版本的 bufferbuffer2。由于在執(zhí)行 npm install 的時候,按照 package.json 里依賴的順序依次解析,則 bufferbuffer2 在  package.json 的放置順序則決定了 node_modules 的依賴結(jié)構(gòu):

先依賴buffer2

node.js npm的包管理機(jī)制是什么

先依賴buffer

node.js npm的包管理機(jī)制是什么

另外,為了讓開發(fā)者在安全的前提下使用最新的依賴包,我們在 package.json 通常只會鎖定大版本,這意味著在某些依賴包小版本更新后,同樣可能造成依賴結(jié)構(gòu)的改動,依賴結(jié)構(gòu)的不確定性可能會給程序帶來不可預(yù)知的問題。

3.3 Lock文件

為了解決 npm install 的不確定性問題,在 npm 5.x 版本新增了 package-lock.json 文件,而安裝方式還沿用了 npm 3.x 的扁平化的方式。

package-lock.json 的作用是鎖定依賴結(jié)構(gòu),即只要你目錄下有 package-lock.json 文件,那么你每次執(zhí)行 npm install 后生成的 node_modules 目錄結(jié)構(gòu)一定是完全相同的。

例如,我們有如下的依賴結(jié)構(gòu):

{
  "name": "my-app",
  "dependencies": {
    "buffer": "^5.4.3",
    "ignore": "^5.1.4",
    "base64-js": "1.0.1",
  }
}

在執(zhí)行 npm install 后生成的 package-lock.json 如下:

{
  "name": "my-app",
  "version": "1.0.0",
  "dependencies": {
    "base64-js": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz",
      "integrity": "sha1-aSbRsZT7xze47tUTdW3i/Np+pAg="
    },
    "buffer": {
      "version": "5.4.3",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
      "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
      "requires": {
        "base64-js": "^1.0.2",
        "ieee754": "^1.1.4"
      },
      "dependencies": {
        "base64-js": {
          "version": "1.3.1",
          "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
          "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
        }
      }
    },
    "ieee754": {
      "version": "1.1.13",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
    },
    "ignore": {
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
      "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A=="
    }
  }
}

我們來具體看看上面的結(jié)構(gòu):

node.js npm的包管理機(jī)制是什么

最外面的兩個屬性 name 、versionpackage.json 中的 nameversion ,用于描述當(dāng)前包名稱和版本。

dependencies 是一個對象,對象和 node_modules 中的包結(jié)構(gòu)一一對應(yīng),對象的 key 為包名稱,值為包的一些描述信息:

  • version:包版本 —— 這個包當(dāng)前安裝在 node_modules 中的版本

  • resolved:包具體的安裝來源

  • integrity:包 hash 值,基于 Subresource Integrity 來驗(yàn)證已安裝的軟件包是否被改動過、是否已失效

  • requires:對應(yīng)子依賴的依賴,與子依賴的 package.jsondependencies的依賴項(xiàng)相同。

  • dependencies:結(jié)構(gòu)和外層的 dependencies 結(jié)構(gòu)相同,存儲安裝在子依賴 node_modules 中的依賴包。

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

例如,回顧下上面的依賴關(guān)系:

node.js npm的包管理機(jī)制是什么

我們在 my-app 中依賴的 base64-js@1.0.1 版本與 buffer 中依賴的 base64-js@^1.0.2 發(fā)生沖突,所以  base64-js@1.0.1  需要安裝在 buffer 包的 node_modules 中,對應(yīng)了 package-lock.jsonbufferdependencies 屬性。這也對應(yīng)了 npm 對依賴的扁平化處理方式。

所以,根據(jù)上面的分析, package-lock.json 文件 和 node_modules 目錄結(jié)構(gòu)是一一對應(yīng)的,即項(xiàng)目目錄下存在  package-lock.json 可以讓每次安裝生成的依賴目錄結(jié)構(gòu)保持相同。

另外,項(xiàng)目中使用了 package-lock.json 可以顯著加速依賴安裝時間。

我們使用 npm i --timing=true --loglevel=verbose 命令可以看到 npm install 的完整過程,下面我們來對比下使用 lock 文件和不使用 lock 文件的差別。在對比前先清理下npm 緩存。

不使用 lock 文件:

node.js npm的包管理機(jī)制是什么

使用 lock 文件:

node.js npm的包管理機(jī)制是什么

可見, package-lock.json 中已經(jīng)緩存了每個包的具體版本和下載鏈接,不需要再去遠(yuǎn)程倉庫進(jìn)行查詢,然后直接進(jìn)入文件完整性校驗(yàn)環(huán)節(jié),減少了大量網(wǎng)絡(luò)請求。

使用建議

開發(fā)系統(tǒng)應(yīng)用時,建議把 package-lock.json 文件提交到代碼版本倉庫,從而保證所有團(tuán)隊(duì)開發(fā)者以及 CI 環(huán)節(jié)可以在執(zhí)行 npm install 時安裝的依賴版本都是一致的。

在開發(fā)一個 npm包 時,你的 npm包 是需要被其他倉庫依賴的,由于上面我們講到的扁平安裝機(jī)制,如果你鎖定了依賴包版本,你的依賴包就不能和其他依賴包共享同一 semver 范圍內(nèi)的依賴包,這樣會造成不必要的冗余。所以我們不應(yīng)該把package-lock.json 文件發(fā)布出去( npm 默認(rèn)也不會把 package-lock.json 文件發(fā)布出去)。

3.4 緩存

在執(zhí)行 npm installnpm update命令下載依賴后,除了將依賴包安裝在node_modules 目錄下外,還會在本地的緩存目錄緩存一份。

通過 npm config get cache 命令可以查詢到:在 LinuxMac 默認(rèn)是用戶主目錄下的 .npm/_cacache 目錄。

在這個目錄下又存在兩個目錄:content-v2、index-v5content-v2 目錄用于存儲 tar包的緩存,而index-v5目錄用于存儲tar包的 hash

npm 在執(zhí)行安裝時,可以根據(jù) package-lock.json 中存儲的 integrity、version、name 生成一個唯一的 key 對應(yīng)到 index-v5 目錄下的緩存記錄,從而找到 tar包的 hash,然后根據(jù) hash 再去找緩存的 tar包直接使用。

我們可以找一個包在緩存目錄下搜索測試一下,在 index-v5 搜索一下包路徑:

grep "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz" -r index-v5

node.js npm的包管理機(jī)制是什么

然后我們將json格式化:

{
  "key": "pacote:version-manifest:https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz:sha1-aSbRsZT7xze47tUTdW3i/Np+pAg=",
  "integrity": "sha512-C2EkHXwXvLsbrucJTRS3xFHv7Mf/y9klmKDxPTE8yevCoH5h8Ae69Y+/lP+ahpW91crnzgO78elOk2E6APJfIQ==",
  "time": 1575554308857,
  "size": 1,
  "metadata": {
    "id": "base64-js@1.0.1",
    "manifest": {
      "name": "base64-js",
      "version": "1.0.1",
      "engines": {
        "node": ">= 0.4"
      },
      "dependencies": {},
      "optionalDependencies": {},
      "devDependencies": {
        "standard": "^5.2.2",
        "tape": "4.x"
      },
      "bundleDependencies": false,
      "peerDependencies": {},
      "deprecated": false,
      "_resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz",
      "_integrity": "sha1-aSbRsZT7xze47tUTdW3i/Np+pAg=",
      "_shasum": "6926d1b194fbc737b8eed513756de2fcda7ea408",
      "_shrinkwrap": null,
      "bin": null,
      "_id": "base64-js@1.0.1"
    },
    "type": "finalized-manifest"
  }
}

上面的 _shasum 屬性 6926d1b194fbc737b8eed513756de2fcda7ea408 即為 tar 包的 hash, hash的前幾位 6926 即為緩存的前兩層目錄,我們進(jìn)去這個目錄果然找到的壓縮后的依賴包:

node.js npm的包管理機(jī)制是什么

以上的緩存策略是從 npm v5 版本開始的,在 npm v5 版本之前,每個緩存的模塊在 ~/.npm 文件夾中以模塊名的形式直接存儲,儲存結(jié)構(gòu)是{cache}/{name}/{version}。

npm 提供了幾個命令來管理緩存數(shù)據(jù):

  • npm cache add:官方解釋說這個命令主要是 npm 內(nèi)部使用,但是也可以用來手動給一個指定的 package 添加緩存。

  • npm cache clean:刪除緩存目錄下的所有數(shù)據(jù),為了保證緩存數(shù)據(jù)的完整性,需要加上 --force 參數(shù)。

  • npm cache verify:驗(yàn)證緩存數(shù)據(jù)的有效性和完整性,清理垃圾數(shù)據(jù)。

基于緩存數(shù)據(jù),npm 提供了離線安裝模式,分別有以下幾種:

  • --prefer-offline: 優(yōu)先使用緩存數(shù)據(jù),如果沒有匹配的緩存數(shù)據(jù),則從遠(yuǎn)程倉庫下載。

  • --prefer-online: 優(yōu)先使用網(wǎng)絡(luò)數(shù)據(jù),如果網(wǎng)絡(luò)數(shù)據(jù)請求失敗,再去請求緩存數(shù)據(jù),這種模式可以及時獲取最新的模塊。

  • --offline: 不請求網(wǎng)絡(luò),直接使用緩存數(shù)據(jù),一旦緩存數(shù)據(jù)不存在,則安裝失敗。

3.5 文件完整性

上面我們多次提到了文件完整性,那么什么是文件完整性校驗(yàn)?zāi)兀?/p>

在下載依賴包之前,我們一般就能拿到 npm 對該依賴包計(jì)算的 hash 值,例如我們執(zhí)行 npm info 命令,緊跟 tarball(下載鏈接) 的就是 shasum(hash) :

node.js npm的包管理機(jī)制是什么

用戶下載依賴包到本地后,需要確定在下載過程中沒有出現(xiàn)錯誤,所以在下載完成之后需要在本地在計(jì)算一次文件的 hash 值,如果兩個 hash 值是相同的,則確保下載的依賴是完整的,如果不同,則進(jìn)行重新下載。

3.6 整體流程

好了,我們再來整體總結(jié)下上面的流程:

  • 檢查 .npmrc 文件:優(yōu)先級為:項(xiàng)目級的 .npmrc 文件 > 用戶級的 .npmrc 文件> 全局級的 .npmrc 文件 > npm 內(nèi)置的 .npmrc 文件

  • 檢查項(xiàng)目中有無 lock 文件。

  • lock 文件:

    • 不存在緩存:

    • 存在緩存:將緩存按照依賴結(jié)構(gòu)解壓到 node_modules

    • 將下載的包復(fù)制到 npm 緩存目錄

    • 將下載的包按照依賴結(jié)構(gòu)解壓到 node_modules

    • 重新下載

    • npm 遠(yuǎn)程倉庫下載包

    • 校驗(yàn)包的完整性

    • 校驗(yàn)不通過:

    • 校驗(yàn)通過:

    • 構(gòu)建依賴樹時,不管其是直接依賴還是子依賴的依賴,優(yōu)先將其放置在 node_modules 根目錄。

    • 當(dāng)遇到相同模塊時,判斷已放置在依賴樹的模塊版本是否符合新模塊的版本范圍,如果符合則跳過,不符合則在當(dāng)前模塊的 node_modules 下放置該模塊。

    • 注意這一步只是確定邏輯上的依賴樹,并非真正的安裝,后面會根據(jù)這個依賴結(jié)構(gòu)去下載或拿到緩存中的依賴包

    • npm 遠(yuǎn)程倉庫獲取包信息

    • 根據(jù) package.json 構(gòu)建依賴樹,構(gòu)建過程:

    • 在緩存中依次查找依賴樹中的每個包

    • 將包解壓到 node_modules

    • 生成 lock 文件

  • lock 文件:

    • 檢查 package.json 中的依賴版本是否和 package-lock.json 中的依賴有沖突。

    • 如果沒有沖突,直接跳過獲取包信息、構(gòu)建依賴樹過程,開始在緩存中查找包信息,后續(xù)過程相同

node.js npm的包管理機(jī)制是什么

上面的過程簡要描述了 npm install 的大概過程,這個過程還包含了一些其他的操作,例如執(zhí)行你定義的一些生命周期函數(shù),你可以執(zhí)行 npm install package --timing=true --loglevel=verbose 來查看某個包具體的安裝流程和細(xì)節(jié)。

3.7 yarn

node.js npm的包管理機(jī)制是什么

yarn 是在 2016 年發(fā)布的,那時 npm 還處于 V3 時期,那時候還沒有 package-lock.json 文件,就像上面我們提到的:不穩(wěn)定性、安裝速度慢等缺點(diǎn)經(jīng)常會受到廣大開發(fā)者吐槽。此時,yarn 誕生:

node.js npm的包管理機(jī)制是什么

上面是官網(wǎng)提到的 yarn 的優(yōu)點(diǎn),在那個時候還是非常吸引人的。當(dāng)然,后來 npm 也意識到了自己的問題,進(jìn)行了很多次優(yōu)化,在后面的優(yōu)化(lock文件、緩存、默認(rèn)-s...)中,我們多多少少能看到 yarn 的影子,可見 yarn 的設(shè)計(jì)還是非常優(yōu)秀的。

yarn 也是采用的是 npm v3 的扁平結(jié)構(gòu)來管理依賴,安裝依賴后默認(rèn)會生成一個 yarn.lock 文件,還是上面的依賴關(guān)系,我們看看 yarn.lock 的結(jié)構(gòu):

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


base64-js@1.0.1:
  version "1.0.1"
  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.1.tgz#6926d1b194fbc737b8eed513756de2fcda7ea408"
  integrity sha1-aSbRsZT7xze47tUTdW3i/Np+pAg=

base64-js@^1.0.2:
  version "1.3.1"
  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==

buffer@^5.4.3:
  version "5.4.3"
  resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
  integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
  dependencies:
    base64-js "^1.0.2"
    ieee754 "^1.1.4"

ieee754@^1.1.4:
  version "1.1.13"
  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==

ignore@^5.1.4:
  version "5.1.4"
  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
  integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==

可見其和 package-lock.json 文件還是比較類似的,還有一些區(qū)別就是:

  • package-lock.json 使用的是 json 格式,yarn.lock 使用的是一種自定義格式

  • yarn.lock 中子依賴的版本號不是固定的,意味著單獨(dú)又一個 yarn.lock 確定不了 node_modules 目錄結(jié)構(gòu),還需要和 package.json 文件進(jìn)行配合。而 package-lock.json 只需要一個文件即可確定。

yarn 的緩策略看起來和 npm v5 之前的很像,每個緩存的模塊被存放在獨(dú)立的文件夾,文件夾名稱包含了模塊名稱、版本號等信息。使用命令 yarn cache dir 可以查看緩存數(shù)據(jù)的目錄:

node.js npm的包管理機(jī)制是什么

yarn 默認(rèn)使用 prefer-online 模式,即優(yōu)先使用網(wǎng)絡(luò)數(shù)據(jù),如果網(wǎng)絡(luò)數(shù)據(jù)請求失敗,再去請求緩存數(shù)據(jù)。

關(guān)于“node.js npm的包管理機(jī)制是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI