Node 項(xiàng)目在項(xiàng)目根目錄中名為 package.json 的文件中跟蹤依賴關(guān)系和元數(shù)據(jù)。這是你項(xiàng)目的核心。它包含名稱、描述和版本之類的信息,以及運(yùn)行、開發(fā)以及有選擇地將項(xiàng)目發(fā)布到 NPM 所需的信息。
在本教程中,我們將:
- 了解 package.json 與項(xiàng)目之間的關(guān)系
- 確定重要字段和元數(shù)據(jù)
- 了解如何管理 package.json
目標(biāo)
了解什么是 package.json 文件,它與你項(xiàng)目的關(guān)系以及需要了解的常見屬性。
了解 package.json
如果你以前用過 Node.js,則可能會(huì)遇到 package.json 文件。它是一個(gè) JSON 文件,位于項(xiàng)目的根目錄中。你的 package.json 包含關(guān)于項(xiàng)目的重要信息。它包含關(guān)于項(xiàng)目的使人類可讀元數(shù)據(jù)(如項(xiàng)目名稱和說明)以及功能元數(shù)據(jù)(如程序包版本號(hào)和程序所需的依賴項(xiàng)列表)。
package.json 示例如下所示:
{
"name": "my-project",
"version": "1.5.0",
"description": "Express server project using compression",
"main": "src/index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon",
"lint": "eslint **/*.js"
},
"dependencies": {
"express": "^4.16.4",
"compression": "~1.7.4"
},
"devDependencies": {
"eslint": "^5.16.0",
"nodemon": "^1.18.11"
},
"repository": {
"type": "git",
"url": "https://github.com/osiolabs/example.git"
},
"author": "Jon Church",
"contributors": [
{
"name": "Amber Matz",
"email": "example@example.com",
"url": "https://www.osiolabs.com/#team"
}
],
"keywords": [
"server",
"osiolabs",
"express",
"compression"
]
}
package.json 的用途是什么?
項(xiàng)目的 package.json 是配置和描述如何與程序交互和運(yùn)行的中心。 npm CLI(和 yarn)用它來識(shí)別你的項(xiàng)目并了解如何處理項(xiàng)目的依賴關(guān)系。package.json 文件使 npm 可以啟動(dòng)你的項(xiàng)目、運(yùn)行腳本、安裝依賴項(xiàng)、發(fā)布到 NPM 注冊(cè)表以及許多其他有用的任務(wù)。 npm CLI 也是管理 package.json 的最佳方法,因?yàn)樗兄谠陧?xiàng)目的整個(gè)生命周期內(nèi)生成和更新 package.json 文件。
package.json 會(huì)在項(xiàng)目的生命周期中扮演多個(gè)角色,其中某些角色僅適用于發(fā)布到 NPM 的軟件包。即使你沒有把項(xiàng)目發(fā)布到 NPM 注冊(cè)表中,或者沒有將其公開發(fā)布給其他人,那么 package.json 對(duì)于開發(fā)流程仍然至關(guān)重要。
你的項(xiàng)目還必須包含 package.json,然后才能從 NPM 安裝軟件包。這可能是你在項(xiàng)目中需要它的主要原因之一。
package.json 中的常見字段
讓我們看一下 package.json 中包含的一些最常見和重要的字段,以更好地了解如何使用和管理這個(gè)基本文件。有些用來發(fā)布到 NPM,而其他一些則可以幫助 npm CLI 運(yùn)行應(yīng)用程序或安裝依賴項(xiàng)。
實(shí)際的字段比我們所介紹的要多,你可以在它的文檔中了解其余字段,但以下的是必須要了解的 package.json 屬性。
name
package.json 中最重要的屬性是 name 和 version 兩個(gè)屬性,這兩個(gè)屬性是必須要有的,否則模塊就無法被安裝,這兩個(gè)屬性一起形成了一個(gè) npm 模塊的唯一標(biāo)識(shí)。
name是 package(包)的名稱。名稱的第一部分(如@scope/是可選的,用作名稱空間)。當(dāng)我們的包發(fā)布到 NPM 網(wǎng)站,其他人才能通過搜索name來安裝使用
{
"name": "@scope/name"
}
name 規(guī)范
- 最好取簡(jiǎn)短而語義化的值
- 不能以,.開頭
- 不能有大寫字母/空格/下滑線!
- 不能和 NPM 網(wǎng)站中已有的包名字重名!
version
version是 package(包)的版本,通常,它不會(huì)對(duì)你的項(xiàng)目產(chǎn)生任何影響,
除非它是一個(gè)工作空間(workspaces)-其版本必須與指定的范圍相匹配,才能選擇該工作空間作為解決方案的候選對(duì)象。
version 規(guī)范
version 具體體現(xiàn)為::“x.y.z”
- 修復(fù) bug,小改動(dòng),增加 z
- 增加了新特性,但仍能向后兼容,增加 y
- 有很大的改動(dòng),無法向后兼容,增加 x
詳細(xì)內(nèi)容參考語義化版本 2.0.0
使用 npm version <update_type>自動(dòng)升級(jí)版本號(hào)
update_type為patch, minor, major其中之一,分別表示補(bǔ)丁,小改,大改
npm version patch
npm version minor
npm version major
在 CI(持續(xù)集成)的腳本中可以用到此命令
description
一個(gè)描述,方便別人了解你的模塊作用,搜索的時(shí)候也有用。
{
"description": "xxxx"
}
keywords
一個(gè)字符串?dāng)?shù)組,方便別人搜索到本模塊
{
"keywords": [
"ant",
"component",
"design"
]
}
當(dāng)我們使用 npm 檢索模塊時(shí),會(huì)對(duì)模塊中的 description 字段和 keywords 字段進(jìn)行匹配,寫好 package.json 中的 description 和 keywords 將有利于增加我們模塊的曝光率。
homepage
項(xiàng)目主頁(yè) url,默認(rèn)值為/
一般來說,我們打包的靜態(tài)資源會(huì)部署在 CDN 上,為了讓我們的應(yīng)用知道去哪里加載資源,則需要我們?cè)O(shè)置一個(gè)根路徑,這時(shí)可以通過 package.json 中的 homepage 字段設(shè)置應(yīng)用的根路徑。
{
"homepage": "https://ant.design"
}
bugs
填寫一個(gè) bug 提交地址或者一個(gè)郵箱,被你的模塊坑到的人可以通過這里吐槽,例如:
{
"bugs": {
"url":"https://github.com/ant-design/ant-design/issues"
}
}
license
你應(yīng)該為你的開源代碼模塊制定一個(gè)開源協(xié)議,讓用戶知道他們有何權(quán)限來使用你的模塊,以及使用該模塊有哪些限制
- MIT 是最少約束的選擇。
- GPL 是最多約束的。
如果是個(gè)人隨意作品,建議 MIT 許可。如果是公司或者需要嚴(yán)格保護(hù)的開源產(chǎn)品,GPL。


{
"license": "MIT"
}
詳細(xì)內(nèi)容參考
和用戶相關(guān)的屬性: author, contributors
{
"author": "iikonan",
"contributors": [
"zhangsan",
"lisi"
]
}
funding
在開源領(lǐng)域,資金是一個(gè)長(zhǎng)期存在的問題.
funding命令的作用是讓維護(hù) npm 的開發(fā)人員(為 Node.js 創(chuàng)建包)聲明元數(shù)據(jù),為有意愿的捐贈(zèng)者指明捐贈(zèng)平臺(tái)。
在 package.json 文件中添加了一個(gè)funding 字段, 可指向在線捐贈(zèng)服務(wù)的 url,如 Patreon、Open Collective、GitHub Sponsors、License Zero 或者其他支付網(wǎng)站。
{
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ant-design"
}
}
files
描述了將軟件包作為依賴項(xiàng)安裝時(shí)要包括的條目,默認(rèn)值為[“*”],這意味著它將包括所有文件。
如果需要把打包后的代碼也發(fā)布到 NPM 倉(cāng)庫(kù)
{
"files": ["dist/**/*", "lib/**/*"]
}
你還可以在包的根目錄或子目錄中提供.npmignore 文件,以防止某些文件被發(fā)布。
.npmignore 文件的工作原理與.gitignore 一樣。
如果存在.gitignore 文件,而缺少.npmignore,則將改用.gitignore 的內(nèi)容。
files字段內(nèi)容會(huì)覆蓋.npmignore 和.gitignore的內(nèi)容。
main
main 字段是 package.json 中的另一種元數(shù)據(jù)功能,它可以用來指定加載的入口文件。
假如你的項(xiàng)目是一個(gè) npm 包,當(dāng)用戶安裝你的包后,require('my-module') 返回的是 main 字段中所列出文件的 module.exports 屬性。
當(dāng)不指定main 字段時(shí),默認(rèn)值是模塊根目錄下面的 index.js 文件。
{
"main": "lib/index.js"
}
browserslist
指定該模板供瀏覽器使用的版本。Browserify 這樣的瀏覽器打包工具,通過它就知道該打包那個(gè)文件。
{
"browserslist": [
"> 0.5%",
"last 2 versions",
"Firefox ESR",
"not dead",
"IE 11",
"not IE 10"
]
}
bin
用于將某些可執(zhí)行 Javascript 文件公開給父包的字段。 此處列出的所有條目都可以通過$ PATH 獲得。
通俗點(diǎn)理解就是我們?nèi)职惭b, 我們就可以在命令行中執(zhí)行這個(gè)文件, 本地安裝我們可以在當(dāng)前工程目錄的命令行中執(zhí)行該文件。
"bin": {
"my-bin": "./dist/my-bin.js",
}
dist/my-bin.js
#!/usr/bin/env node
console.log("cool");
repository
{
"repository": {
"type": "git",
"url": "https://github.com/ant-design/ant-design"
}
}
scripts
該字段用于列出在運(yùn)行 yarn run 時(shí)將要執(zhí)行的小型 shell 腳本。
請(qǐng)注意,包含:(冒號(hào))的腳本是項(xiàng)目的全局變量,無論你當(dāng)前的工作空間如何,都可以調(diào)用它們。
最后,請(qǐng)注意,腳本總是相對(duì)于最近的工作空間(而不是 cwd)執(zhí)行。
"scripts": {
"test": "jest",
"build:dev": "webpack-cli --config ./webpack.dev.config.js",
"build:test": "webpack-cli --config ./webpack.test.config.js",
"build:pro": "webpack-cli --config ./webpack.pro.config.js"
}
NPM 腳本的原理
npm 腳本的原理非常簡(jiǎn)單。每當(dāng)執(zhí)行 npm run,就會(huì)自動(dòng)新建一個(gè) Shell,在這個(gè) Shell 里面執(zhí)行指定的腳本命令。因此,只要是 Shell(一般是 Bash)可以運(yùn)行的命令,就可以寫在 npm 腳本里面。
比較特別的是,npm run 新建的這個(gè) Shell,會(huì)將當(dāng)前目錄的 node_modules/.bin 子目錄加入 PATH 變量,執(zhí)行結(jié)束后,再將 PATH 變量恢復(fù)原樣。
這意味著,當(dāng)前目錄的 node_modules/.bin 子目錄里面的所有腳本,都可以直接用腳本名調(diào)用,而不必加上路徑。比如,當(dāng)前項(xiàng)目的依賴?yán)锩嬗?Mocha,只要直接寫 mocha test 就可以了。
"test": "mocha test"
而不用寫成下面這樣。
"test": "./node_modules/.bin/mocha test"
由于 npm 腳本的唯一要求就是可以在 Shell 執(zhí)行,因此它不一定是 Node 腳本,任何可執(zhí)行文件都可以寫在里面。
npm 腳本的退出碼,也遵守 Shell 腳本規(guī)則。如果退出碼不是0,npm 就認(rèn)為這個(gè)腳本執(zhí)行失敗。
config
{
"name": "foo",
"config": {
"port": "8080"
}
}
當(dāng)執(zhí)行npm start命令,就會(huì)引用 npm_package_config_port 環(huán)境變量,
如上面的配置npm start時(shí),就會(huì)通過端口8080啟動(dòng)
但是用戶可以通過執(zhí)行例如 npm config set foo:port 8001 來覆蓋config配置。
dependencies
應(yīng)用依賴,或者叫做業(yè)務(wù)依賴/生產(chǎn)環(huán)境依賴,這是我們最常用的依賴包管理對(duì)象!它用于指定應(yīng)用依賴的外部包,這些依賴是應(yīng)用發(fā)布后正常執(zhí)行時(shí)所需要的,但不包含測(cè)試時(shí)或者本地打包時(shí)所使用的包
{
"dependencies": {
"react": "^16.9.0",
"react-dom": "^16.9.0"
}
}
放置生產(chǎn)環(huán)境依賴包的地方,即執(zhí)行項(xiàng)目的 npm run build 時(shí)需要的依賴包。因此不要把開發(fā)環(huán)境的依賴包放在這里,比如
- eslint
- typesctipt
- webpack-dev-server
……
因?yàn)闀?huì)增加生產(chǎn)環(huán)境安裝依賴的時(shí)間
devDependencies
與dependencies字段類似,但這些依賴項(xiàng)僅在本地開發(fā)環(huán)境中安裝,而不會(huì)由軟件包的使用者(生產(chǎn)環(huán)境)安裝。
開發(fā)環(huán)境依賴,僅次于dependencies的使用頻率!它的作用和dependencies一樣,只不過它里面的包只用于開發(fā)環(huán)境,不用于生產(chǎn)環(huán)境,這些包通常是單元測(cè)試或者打包工具等,例如gulp, webpack, moca等
{
"devDependencies": {
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.1"
}
}
放置開發(fā)環(huán)境依賴包的地方,即執(zhí)行項(xiàng)目的 npm start 時(shí)需要的依賴包。因此不要把生產(chǎn)環(huán)境的依賴包放在這里
peerDependencies
peerDependencies 的目的是提示宿主環(huán)境去安裝滿足插件 peerDependencies 所指定依賴的包,然后在插件 import 或者 require 所依賴的包的時(shí)候,永遠(yuǎn)都是引用宿主環(huán)境統(tǒng)一安裝的 NPM 包,最終解決插件與所依賴包不一致的問題。
舉個(gè)例子,ant-design UI 組件庫(kù)要求宿主環(huán)境安裝指定的 React 版本。具體可以看它的 package.json配置
{
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
}
optionalDependencies
除非你依賴于 fsevents 軟件包,否則通常不需要此字段。
如果僅在使用特定功能時(shí)才需要包,請(qǐng)使用可選的對(duì)等依賴項(xiàng)。
{
"optionalDependencies": {
"fsevents": "^5.0.0"
}
}
engines
engines 字段指明了該模塊運(yùn)行的平臺(tái),比如 Node 的某個(gè)版本或者瀏覽器
該字段也可以指定適用的 npm 版本。
{
"engines": {
"node": ">=12.18.3",
"npm": ">7.0.0"
}
}
private
如果為 true,則該程序包被視為私有程序,Yarn/NPM 會(huì)在任何情況下均拒絕發(fā)布該程序包。這防止私人存儲(chǔ)庫(kù)意外發(fā)布
{
"private": true
}
publishConfig
此字段包含各種設(shè)置,僅當(dāng)從本地來源生成包時(shí)才考慮這些設(shè)置(通過 yarn pack 或像 yarn npm publish 這樣的發(fā)布命令之一)。
publishConfig.access定義將程序包發(fā)布到 npm 注冊(cè)表時(shí)要使用的程序包訪問級(jí)別。 有效值是公開的并且是受限制的,但是受限制的通常需要注冊(cè)付費(fèi)計(jì)劃(這取決于你使用的注冊(cè)表)。
publishConfig.bin如果存在,則在打包打包以將其運(yùn)送到遠(yuǎn)程注冊(cè)表之前,清單中的頂級(jí) bin 字段將被設(shè)置為此新值。 這不會(huì)修改真正的清單,只會(huì)修改存儲(chǔ)在 tarball 中的清單。
publishConfig.browser與publishConfig.bin屬性的原理相同; 生成工作空間 tarball 時(shí),將使用此值代替頂級(jí)瀏覽器字段。
publishConfig.executableFiles默認(rèn)情況下,出于可移植性的原因,在 bin 字段中列出的文件之外的文件都不會(huì)在結(jié)果包歸檔文件中標(biāo)記為可執(zhí)行文件。 executeFiles 字段使你可以聲明必須設(shè)置了可執(zhí)行標(biāo)志(+ x)的其他字段,即使不能通過 bin 字段直接訪問它們也是如此。
publishConfig.main與publishConfig.bin屬性相同的原理; 生成工作空間 tarball 時(shí),將使用此值代替頂級(jí)“ main”字段。
publishConfig.module與publishConfig.bin屬性相同的原理; 生成工作空間 tarball 時(shí),將使用此值代替頂級(jí)“ module”字段。
publishConfig.registry如果存在,當(dāng)將包推送到遠(yuǎn)程位置時(shí),將替換配置中定義的任何注冊(cè)表。
可能的值
{
"publishConfig": {
"access": "public",
"bin": "./build/bin.js",
"browser": "./build/browser.js",
"executableFiles": ["./dist/shim.js"],
"main": "./build/index.js",
"module": "./build/index.mjs",
"registry": "https://npm.pkg.github.com"
}
}
workspaces
工作區(qū)是 monorepos 用來將一個(gè)大型項(xiàng)目拆分為半獨(dú)立子項(xiàng)目的一項(xiàng)可選功能,每個(gè)子項(xiàng)目都列出了自己的一組依賴關(guān)系。 工作區(qū)字段是全局模式列表,這些模式與應(yīng)成為應(yīng)用程序工作區(qū)的所有目錄匹配。
{
"workspaces": ["packages/*"]
}
type
可能的值
- commonjs(默認(rèn)值),適用于 Node.js 環(huán)境(服務(wù)端)
- module,即 ES Module 語法,適用于瀏覽器環(huán)境(客戶端)
無論使用什么值,當(dāng)使用 PnP 時(shí),Yarn 3+都會(huì)生成一個(gè).pnp.cjs 文件。
{
"type": "commonjs"
}
main 字段通常用于指向 UMD 版本的庫(kù)/包,一般指定為 webpack/rollup 打包 UMD 版本后的路徑
UMD 是什么呢?
- CommonJS + AMD 的組合(即 CommonJS 的語法 + AMD 的異步加載)
- 可以用于 AMD/CommonJS 環(huán)境
- UMD 還支持全局變量定義。因此,UMD 模塊能夠在 客戶端和服務(wù)器 上工作。
main 字段還可以在發(fā)布時(shí)通過使用 publishConfig.main 字段來修改。
module
與 ES6 兼容的環(huán)境嘗試通過其名稱訪問程序包時(shí)將使用的路徑。
module 字段用于指向 ES 版本的庫(kù)/包,一般指定為 webpack/rollup 打包 ES 版本后的路徑
{
"module": "es/index.js"
}
unpkg
unpkg 是一個(gè)內(nèi)容源自 npm 的全球快速 CDN
配置unpkg 字段后,發(fā)布到 npmjs.com 中的包會(huì)自動(dòng)同步到 unpkg.com 上,一般為 umd 格式。
{
"unpkg": "dist/antd.min.js"
}
typings
{
"typings": "lib/index.d.ts"
}
sideEffects
與 webpack 相關(guān)的字段,聲明該模塊是否包含 sideEffects(副作用),從而可以為 tree-shaking 提供更大的優(yōu)化空間。
{
"sideEffects": ["dist/*", "es/**/style/*", "lib/**/style/*", "*.less"]
}