npm 學習筆記


一、介紹


1、是什么

npm 全稱是 Node Package Manager,即 Node 包管理工具

但是發展到后來,並不僅是適用於 node.js 的包。

所以現在看 node_modules 這個名字實在有點偏頗,現在 npm 自己都說自己是通用的包管理,並不局限於 node,然而這名字卻不好改了。

npm 每周大約有 30 億次的下載量,包含超過 600000 個包。

2、歷史

npm 的發展是跟 Node.js 的發展相輔相成的。

Node.js 是由一個在德國工作的美國程序員 Ryan Dahl 寫的。他寫完了 Node.js,但是覺得缺少一個包管理器,於是他和 npm 的作者一拍即合、抱團取暖,最終 Node.js 內置了 npm。

3、包含什么

  • website
  • registry
  • 命令行工具 (CLI)

二、安裝


1、安裝

直接安裝 Node.js 即可。

安裝 Node.js 時,將自動安裝 npm。

但是,npm的更新頻率比Node.js的更新頻率高,

2、更新

npm install npm@latest -g.

3、查看版本

npm -v

寫本文時為 v6.13.0

4、Node.js 與 npm 的版本對應關系

可查閱:https://nodejs.org/zh-cn/download/releases/

其中一行如下:

Version LTS Date V8 npm
Node.js 13.1.0 2019-11-05 7.8.279.17 6.12.1

三、包


1、如何找包

  • 可以去官網直接搜索包名:https://www.npmjs.com/

  • google 一下

  • 找網上公開的精選清單

  • 看別的知名開源庫用的是什么

1.1、[拓展] 對比包

例如對比 react 和 vue:https://www.npmtrends.com/react-vs-vue

2、全局包

如果你想將包作為一個命令行工具,(比如 grunt CLI),那么你應該選擇全局安裝

(1)安裝

npm install -g <package_name>

(2)更新

查找需要更新的:

npm outdated -g

紅色表示小版本升級,可以無腦升級。

黃色表示大版本升級,升級可能會遇到兼容性問題。


直接更新:

npm update -g.

只會更新到 wanted (紅色),而不是 latest (黃色)。如果要指定其他版本的更新,請用 npm install 代替。

(3)查看已安裝

npm list

這里很詳細,但是嵌套太深,如果覺得冗余,可以用上面介紹的 npm outdated -g 查看。

(4)卸載

npm uninstall -g <package_name>

3、本地包

如果你自己的項目依賴於某個包,並通過 Node.js 的 require 加載,那么你應該選擇本地安裝


涉及概念:

  • /package.json文件

  • /package-lock.json文件

  • /node_modules文件夾

(1)package.json

npm init :在當前目錄新增 package.json 文件

npm init 是交互式的方式創建 package.json,

npm init -ynpm init --yes 可以靜默創建 package.json(自動識別你的項目信息)。

基本的 package.json 文件 demo:

{
  "name": "npm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
(2)安裝

npm install lodash = npm install --save lodash

npm install --save-dev lodash

  • --save 為生產中需要這個軟件包,如 lodash。

  • --save-dev 為僅在開發和測試時需要,如 mocha。

注意:默認安裝該包的 Lastest 版本


上面的命令執行后,具體實行的步驟如下:

1、當前目錄的 package.json 中添加該包的版本描述 (注:用 ^ 版本 標記)

  • 如果是 --save ,則添加到 "dependencies" 字段

  • 如果是 --save-dev ,則添加到 "devDependencies" 字段

其實還有更多的場景分類:

  • peerDependencies
  • optionalDependencies
  • bundledDependencies / bundleDependencies

不多介紹了,待寫。

2、當前目錄的 package-lock.json 中添加該包的版本描述 (注:用 具體版本 標記)

3、安裝的包會放在當前目錄的 node_modules 文件夾里。


安裝后如何使用:

var lodash = require('lodash');

var output = lodash.without([1, 2, 3], 1);
console.log(output);
(3)更新

查找需要更新的:

npm outdated


直接更新:

npm update

只會更新到 wanted ,而不是 latest。如果要指定其他版本的更新,請用 npm install 代替。

(4)卸載

npm uninstall lodash = npm uninstall --save lodash

npm uninstall --save-dev lodash

上面的命令執行后,具體實行的步驟如下:

1、/node_modules中該包的文件刪除

2、/package.json中該包的版本描述刪除

4、包(Packages)跟模塊(Modules)的區別

模塊:在 CommonJS 世界中,大多數情況下,一個文件就是一個模塊,並且可以被 require() 。

:大多數情況下,Node.js 應用就是一個包(他可能包含很多模塊),並且有一個 package.json 文件。

可以簡單粗暴理解成:包 > 模塊

注意1:大多數的包都可以當作模塊去 require(),但少部分不行(如僅提供 cli 命令)。

注意2:為什么叫 node_modules 而不是叫 node_packages? 因為包安裝到 node_modules 后的目的就是為了被 require() 使用,而模塊才能被 require()。

四、鏡像


上面介紹了全局/本地包的安裝,如果嫌在國內安裝速度慢,可以使用淘寶npm鏡像http://npm.taobao.org/

# 臨時
npm install express --registry https://registry.npm.taobao.org
# 永久
npm config set registry https://registry.npm.taobao.org

五、發布包


待寫。

https://www.npmjs.cn/getting-started/publishing-npm-packages/

.npmignore 文件可以列出不想打包的文件,避免把一些無關的文件發布到 npmjs 上。但是,統一使用 .gitignore 可以滿足絕大部分場景下的需求。而且,只存在 .gitignore 的情況下,npm publish 會尊重 .gitignore 的聲明,而 .npmignore.gitignore 同時存在的情況下,npm publish 會忽略 .gitignore,而不是取兩者的並集。

六、包版本


安裝包就涉及到包的版本。有兩種描述包版本的方式。

1、語義版本控制

(1)介紹

首先,semver是一個語義化版本號管理的模塊。可以實現版本號的規范、解析、比較

而 semver 的版本號格式,形如[X,Y,Z] 或 [major, minor, patch],如 2.0.1,且項目應始於 1.0.0

在代碼里 require('semver') 還可以實現更復雜的功能。

(2)規則

(3)寫法

1、^: 不允許 [X, Y, Z] 中最左非零數字的更改。

應用:開發者可以通過 ^ 來鎖定一個模塊的大版本,這樣在每次重新安裝依賴或打包部署的時候,都能夠享受到這個包所有的新增 features 和 bug 修復。

注:安裝本地包,在 package.json 里生成的版本號,默認會加 ^ 。

^15.6.1:>=15.6.1 && <16.0.0
# 因 semver 版本號格式規定必須從 1.0.0 開始,所以下面的情況只用於理論比較,實際情況並不會發生。
^0.1.2:>=0.1.2 && <0.2.0
^0.0.2:>=0.0.2 && <0.0.3

2、~: 匹配大於等於 [X, Y, Z] 的更新的Z的版本號

應用:開發者可以通過 ~ 來鎖定一個模塊的小版本,這樣在每次重新安裝依賴或打包部署的時候,都能夠享受到這個包所有的 bug 修復。

~1.2.3:>=1.2.3 && <1.3.0
# 因 semver 版本號格式規定必須從 1.0.0 開始,所以下面的情況只用於理論比較,實際情況並不會發生
~0.2.3:>=0.2.3 && <0.3.0
~0.0.3:>=0.0.3 && <0.1.0

3、x / * / 空:表示任意

1.2.x / 1.2.* / 1.2: >=1.2.0 && <1.3.0

4、- : 指定范圍

1.3.0-1.4.2: >=1.3.0 && <=1.4.2

注意:這里是左閉右閉,而上面都是左閉右開。

(4)使用

npm install somepkg@1.3.4

2、分發標簽

(1)介紹

分發標簽(dist-tags)補充了上面介紹的語義版本控制。

好處:

  • 標注某個有特殊意義的版本

  • 比語義版本控制更易於閱讀

(2)寫法

例如:

  • X.Y.Z-Alpha: 內測版
  • X.Y.Z-Beta: 公測版
  • X.Y.Z-Stable: 穩定版
  • X.Y.Z-Latest: 最新版
(3)其他

添加標簽 & 使用標簽發布 的 章節待寫

(4)使用

npm install somepkg@latest

其實默認就是:npm install <pkg> = npm install <pkg>@latest

七、安裝項目依賴 與 lock 機制


當你在 github 上拉下一個新項目,或者持續集成自己的項目時,總會涉及到根據 package.json (或 package.json + package-lock.json )文件來安裝依賴(即生成 node_modules )的情況。

那么 npm 提供了兩種方法:

  • 1、不鎖版本:項目包含 package.json ,通過 npm install 安裝依賴

    因為 package.json 的版本號常用 ^ ~ 等,而 npm install 又以 package.json 的版本為主,所以無法保證兩次安裝的具體版本是完全相同的。

  • 2、鎖版本:項目包含 package.json 和 package-lock.json ,通過 npm ci 安裝依賴

    因為 package-lock.json 里是具體的版本,npm ci 以這里為主。即達到了鎖版本的效果。

    注意1:既然使用了 npm ci ,那就別忘了把 package-lock.json 加入 git 倉庫。

    注意2:如果 package.json 和 package-lock.json 版本號沖突,則會報錯。

    注意3:npm ci 在安裝前會自動清除現存的 node_modules,所以 npm ci 天然規避了增量安裝可能帶來的不一致性等問題

而關於這兩者方法哪一種更好,網上其實爭論不少,想了解的請看:

為什么我不使用 shrinkwrap(lock)

透過 js-beautify@1.7.0 的 Bug 來看,npm 默認的 lock 機制是否重要?


支持不鎖版本:

  • 讓項目保持在良性的環境中,正向傳遞 new feature 和 bug fix,前提是一定要選擇靠譜的開源模塊

  • 你可以限制你安裝模塊的版本號,但是你無法限制你安裝模塊依賴的模塊的版本號

支持鎖版本:

  • 保證整個團隊都使用版本完全一致的依賴,開發環境統一。

  • 保證每次部署都使用版本完全一致的依賴,確保安全。(從 npm ci 這個名字就能看出來這個命令是為持續集成准備的)

我的觀點是,還是要看具體場景。例如作為開源包發布,建議不鎖版本,而對生產環境的項目,安全第一,還是鎖版本比較放心(如果要 update 某個/些包 ,一定要做好回歸測試再上線)。

八、競品分析 —— yarn


yarn 是 Facebook 出的。

早期 yarn 有很多新的好用的功能和更快的安裝速度,但是 npm 后來也隨着新版本的升級陸續把借鑒了過來。

現在 npm 6 不管是功能還是性能都已經很接近 yarn 了,所以我還是習慣用 npm。

下面介紹 yarn 當初吸引眼球的 feature。

1、嵌套

之前 npm 的 node_modules 問題在於:

  • 目錄嵌套層級過深
  • 模塊實例無法共享
  • 安裝速度很慢

簡單來說,就是模塊都是獨立的,比如說位於 express 下面的 path-to-regexp 和位於connect 下面的 path-to-regexp 模塊,雖然版本都是一致的,但還是被視為不同的包,被重復安裝兩次,並放置在不同的位置。

后來,有人為了解決這個問題,引入了軟鏈接的方案,市面上有很多第三方的庫。

再后來, npm3 並沒有采用軟鏈接的方案,而是使用了扁平化方案,即直接將所有模塊都安裝到 node_modules 下。第一次出現的包會提升到頂層,后面重復出現的包(版本不一致的)才會被放入再深一層的依賴包的 node_modules 中。

而這些,yarn 早就實現了。

2、lock

yarn 默認提供了 lock 功能(即上面提到的鎖版本)。

而 npm 5 才引入 package-lock.json ,等價於 yarn 中的 yarn.lock

其實 npm 早期就提供了 lock 功能:shrinkwrap。不過他需要用戶執行 npm shrinkwrap 創建 npm-shrinkwrap.json 文件來 手動鎖定版本

3、離線安裝

npm6 的出現加入了緩存,進一步提升了安裝速度。

  • npm install --offline
    • 完全使用線下緩存
  • npm install --online
    • 完全使用線上數據
  • npm install --prefer-offline
    • 優先使用線下緩存(建議使用這個來提高 npm 的安裝速度)
  • npm install --prefer-online 【默認】
    • 優先使用線上數據

4、交互式更新

yarn 有交互式更新功能。

而 npm 也可以安裝第三方工具npm-check ,它提供了命令行下的圖形界面,可以手動選擇升級哪些模塊。

5、npx

npm5 出來 npx 代替了yarn run 這個命令。


原理:

1、分別檢查當前目錄node_modules/.bin和環境變量$PATH

2、如果命令存在,便運行

3、如果命令不存在,便安裝到臨時目錄,運行完后刪除


用處:

1、方便調用本地包

比如,之前項目安裝了 sequelize 包,每次想要執行他的遷移命令都要輸入長長的一串:

# old
./node_modules/sequelize-cli/lib/sequelize db:migrate
# new
npx sequelize db:migrate

2、只想臨時使用下某個包,而不想安裝它(全局和本地都不想安裝)

建議:最好對日常使用的工具時才使用全局安裝

例如,之前項目一直使用 webpack 打包,但現在想臨時試下換用 rollup 打包的效果。

九、其他命令


1、npm audit

有些項目處於維護階段,不打算加新特性了,甚至可能不太嚴重的 bug 都不打算修復了,但是像安全漏洞這樣的嚴重問題還是要管的。這時可以使用 npm audit ,列出項目依賴中有安全漏洞的版本。

但是因為 npm install 引入新依賴時會自動運行 npm audit,再加上會定期運行 npm outdated ,所以手動運行 npm audit 的機會不太多。

2、npm repo 可以打開項目的源代碼倉庫(大部分情況下是 GitHub)

3、npm home 可以打開項目的主頁(官網)

4、npm xmas 命令行里打印聖誕快樂樹(純無聊)

十、待寫


scoped packages(作用域包)

two-factor auth

security tokens

私有源 (如 cnpm,例如上面介紹的淘寶鏡像就算一個)

十一、故事


1、2016年,一個開發者對 NPM 公司不滿,unpublish了自己之前發布的所有模塊。其中包括被廣泛使用的 left-pad,導致 Babel、ReactNative、Ember 等大量工具構建失敗。

2、2019年,GitHub 發布了全新的軟件包管理服務,叫 GitHub Package Registry,完全免費。且還兼容 npm。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM