原文鏈接: 什么是 npm —— 寫給初學者的編程教程
自 2009 年以來,Node.js 一直席卷全球。成千上萬個系統基于 Node.js 構建,促使開發者在社區宣稱“JavaScript 正在吞噬軟件”。
Node 成功的主要因素之一是它廣受歡迎的軟件包管理器——npm,因為 npm 使 JavaScript 開發人員可以快速方便地共享軟件包, 例如 lodash 和 moment。
NPM 是什么
npm(“Node 包管理器”)是 JavaScript 運行時 Node.js 的默認程序包管理器。
它也被稱為“Ninja Pumpkin Mutants”,“Nonprofit Pizza Makers”,以及許多其他隨機名稱,可以在 npm-expansions 上探索這些名稱。
npm 由兩個主要部分組成:
- 用于發布和下載程序包的 CLI(命令行界面)工具
- 托管 JavaScript 程序包的 在線存儲庫
為了更直觀地解釋,我們可以將存儲庫 npmjs.com 視為一個物流集散中心,該中心從賣方(npm 包裹的作者)那里接收貨物的包裹,并將這些貨物分發給買方(npm 包裹的用戶)。
為了促進此過程,npmjs.com 物流集散中心雇用了一群勤勞的袋熊(npm CLI),他們將被分配給每個 npmjs.com 用戶作為私人助理。 因此,dependencies(依賴項)會如下傳遞給 JavaScript 開發人員:
發布 JS 軟件包的過程如下:
讓我們看看這只袋熊如何協助想要在項目中使用 JavaScript 包的開發人員。下面我們還將看到它們(npm CLI)如何幫助開源向導將其出色的庫推向世界。
package.json
每個 JavaScript 項目(無論是 Node.js 還是瀏覽器應用程序)都可以被當作 npm 軟件包,并且通過 package.json 來描述項目和軟件包信息。
我們可以將 package.json 視為快遞盒子上的運輸信息。
當運行 npm init 初始化 JavaScript/Node.js 項目時,將生成 package.json 文件,文件內的內容(基本元數據)由開發人員提供:
name:JavaScript 項目或庫的名稱。
version:項目的版本。通常,在應用程序開發中,由于沒有必要對開源庫進行版本控制,因此經常忽略這一塊。但是,仍可以用它來定義版本。
description:項目的描述。
license:項目的許可證。
npm scripts
package.json 還支持一個 scripts 屬性,可以把它當作在項目本地運行的命令行工具。例如,一個 npm 項目的 scripts部分可能看起來像這樣:
{"scripts": {"build": "tsc","format": "prettier --write **/*.ts","format-check": "prettier --check **/*.ts","lint": "eslint src/**/*.ts","pack": "ncc build","test": "jest","all": "npm run build && npm run format && npm run lint && npm run pack && npm test"}
}
eslint,prettier,ncc,jest 不是安裝為全局可執行文件,而是安裝在項目本地的 node_modules/.bin/ 中。
最新引入的 npx 使我們可以像在全局安裝程序一樣運行這些 node_modules 項目作用域命令,方法是在其前面加上 npx …(即npx prettier --write ** / *。ts)。
dependencies vs devDependencies
這兩個以鍵值對象的形式出現,其中 npm 庫的名稱為鍵,其語義格式版本為值。 大家可以看看 Github 的 TypeScript 操作模板中的示例:
{"dependencies": {"@actions/core": "^1.2.3","@actions/github": "^2.1.1"},"devDependencies": {"@types/jest": "^25.1.4","@types/node": "^13.9.0","@typescript-eslint/parser": "^2.22.0","@zeit/ncc": "^0.21.1","eslint": "^6.8.0","eslint-plugin-github": "^3.4.1","eslint-plugin-jest": "^23.8.2","jest": "^25.1.0","jest-circus": "^25.1.0","js-yaml": "^3.13.1","prettier": "^1.19.1","ts-jest": "^25.2.1","typescript": "^3.8.3"}
}
這些依賴通過帶有 --save 或 --save-dev 標志的 npm install 命令安裝。 它們分別用于生產和開發/測試環境。 在下一節中,我們將更深入地研究這些軟件包的安裝。
同時,理解語義版本前面的符號非常重要(假設你已經閱讀 semver 的 major.minor.patch 模型):
- ^:表示最新的次版本,例如, ^1.0.4 可能會安裝主版本系列 1 的最新次版本 1.3.0。
- ?:表示最新的補丁程序版本,與 ^ 類似, ?1.0.4 可能會安裝次版本系列 1.0 的最新次版本1.0.7。
所有這些確切的軟件包版本都將記錄在 package-lock.json 文件中。
package-lock.json
該文件描述了 npm JavaScript 項目中使用的依賴項的確切版本。如果 package.json 是通用的描述性標簽,則 package-lock.json 是成分表。
就像我們通常不會讀取食品包裝袋上的成分表(除非你太無聊或需要知道)一樣,package-lock.json 并不會被開發人員一行一行進行讀取。
package-lock.json 通常是由 npm install 命令生成的,也可以由我們的 NPM CLI 工具讀取,以確保使用 npm ci 復制項目的構建環境。
用戶如何使用 NPM
從前面提到的 130 萬個發布的軟件包中,有 160 億次下載,可以推斷出,大多數 npm 用戶都朝這個方向使用 npm。所以,了解如何使用這個強大的工具會很有幫助。
npm install
這是現在我們開發 JavaScript/Node.js 應用程序時最常用的命令。
默認情況下,npm install 將安裝帶有 ^ 版本號的軟件包的最新版本。npm 項目上下文中的 npm install 將根據 package.json 規范將軟件包下載到項目的 node_modules 文件夾中,從而升級軟件包的版本(并重新生成 package-lock.json )。 npm install 可以基于 ^ 和 ? 版本匹配。
如果要在全局上下文中安裝程序包,可以在機器的任何地方使用它,則可以指定全局標志 -g(例如 live-server)。
npm 使安裝 JavaScript 軟件包非常容易,以至于經常錯誤地使用此命令。 導致一些程序員對 npm 開這樣的玩笑:
但是,npm 包太大、太深這樣的問題可以通過 --production 標志來拯救!在上一節中,我們討論了分別用于生產和開發/測試環境的 dependencies 和 devDependencies 。 這個 --production 標志是如何在 node_modules 中進行區別的。
通過將此標志附加到 npm install 命令,我們將僅從 dependencies 安裝軟件包,從而將 node_modules 的大小大大減小到應用程序正常運行所必需的大小。——不應該將 devDependencies 引入生產環境!
npm ci
因此,如果 npm install --production 對于生產環境是最佳選項,那么是否必須有一個對本地環境,測試環境最合適的選項?
答案是 npm ci。
就像如果 package_lock.json 尚不存在于項目中一樣,無論何時調用 npm install 都會生成它,npm ci 會消耗該文件來下載項目所依賴的每個軟件包的確切版本。
這樣,無論是用于本地開發的筆記本電腦還是 Github Actions 等 CI(持續集成)構建環境,我們都可以確保項目上下文在不同機器上保持完全相同。
npm audit
隨著越來越多的軟件包發布,并且易于安裝,因此 npm 軟件包容易受到惡意作者的惡意攻擊,例如這些。
意識到生態系統存在問題,npm.js 組織提出了 npm audit 的主意。 他們維護了一個安全漏洞列表,開發人員可以使用 npm audit 命令來審核項目中的依賴項。
npm audit 為開發人員提供了有關漏洞以及是否有要修復的版本的信息,例如:
如果補救措施在下一個不間斷的版本升級中可用,則可以使用 npm audit fix 來自動升級受影響的依賴項的版本。
作者如何使用 NPM
我們已經了解了作為用戶,如何通過 NPM CLI 有效得使用 NPM,但是作為作者又如何使用呢?
npm publish
將軟件包發送到 npmjs.com 非常容易,因為我們只需要運行 npm publish 。 棘手的部分(并非專門針對 npm 軟件包作者)是確定軟件包的版本。
根據 semver.org 的經驗法則:
當你進行不兼容的 API 更改時使用 MAJOR 版本
以向后兼容的方式添加功能時使用 MINOR 版本
進行向后兼容的 bug 修復時使用 PATCH 版本
在發布軟件包時,遵循上述規則尤為重要,可以確保你不會破壞任何人的代碼,因為 npm 中匹配的默認版本是^(又稱下一個次版本)。