在 Node.js
中,模塊是一個庫或框架,也是一個 Node.js
項目。Node.js
項目遵循模塊化的架構,當我們創建了一個 Node.js
項目,意味着創建了一個模塊,這個模塊必須有一個描述文件,即 package.json
。它是我們最常見的配置文件,但是它裏面的配置你真的有詳細瞭解過嗎?配置一個合理的 package.json
文件直接決定着我們項目的質量,本章就帶大家瞭解下 package.json
的各項詳細配置。
必備屬性
package.json
中有非常多的屬性,其中必須填寫的只有兩個:name
和 version
,這兩個屬性組成一個 npm
模塊的唯一標識。
npm包命名規則
name
即模塊名稱,其命名時需要遵循官方的一些規範和建議:
包名會成爲模塊url
、命令行中的一個參數或者一個文件夾名稱,任何非url
安全的字符在包名中都不能使用,可以使用 validate-npm-package-name
包來檢測包名是否合法。
語義化包名,可以幫助開發者更快的找到需要的包,並且避免意外獲取錯誤的包。
若包名稱中存在一些符號,將符號去除後不得與現有包名重複
例如:由於react-native
已經存在,react.native
、reactnative
都不可以再創建。
如果你的包名與現有的包名太相近導致你不能發佈這個包,那麼推薦將這個包發佈到你的作用域下。
例如:用戶名 conard
,那麼作用域爲 @conard
,發佈的包可以是@conard/react
。
查看包是否被佔用
name
是一個包的唯一標識,不得和其他包名重複,我們可以執行 npm
view packageName
查看包是否被佔用,並可以查看它的一些基本信息:
若包名稱從未被使用過,則會拋出 404
錯誤:
另外,你還可以去 https://www.npmjs.com/
查詢更多更詳細的包信息。
描述信息
{
"description": "An enterprise-class UI design language and React components implementation",
"keywords": [
"ant",
"component",
"components",
"design",
"framework",
"frontend",
"react",
"react-component",
"ui"
]
}
description
用於添加模塊的的描述信息,方便別人瞭解你的模塊。
keywords
用於給你的模塊添加關鍵字。
當然,他們的還有一個非常重要的作用,就是利於模塊檢索。當你使用 npm search
檢索模塊時,會到description
和 keywords
中進行匹配。寫好 description
和 keywords
有利於你的模塊獲得更多更精準的曝光:
開發人員
描述開發人員的字段有兩個:author
和 contributors
, author
指包的主要作者,一個 author
對應一個人。contributors
指貢獻者信息,一個 contributors
對應多個貢獻者,值爲數組,對人的描述可以是一個字符串,也可以是下面的結構:
{
"name" : "ConardLi",
"email" : "[email protected]",
"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
用於指定模塊的代碼倉庫。
bugs
指定一個地址或者一個郵箱,對你的模塊存在疑問的人可以到這裏提出問題。
依賴配置
我們的項目可能依賴一個或多個外部依賴包,根據依賴包的不同用途,我們將他們配置在下面幾個屬性下:dependencies、devDependencies、peerDependencies、bundledDependencies、optionalDependencies
。
配置規則
在介紹幾種依賴配置之前,首先我們來看一下依賴的配置規則,你看到的依賴包配置可能是下面這樣的:
"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",
}
依賴配置遵循下面幾種配置規則:
- 依賴包名稱:
VERSION
VERSION
是一個遵循SemVer
規範的版本號配置,npm install
時將到npm
服務器下載符合指定版本範圍的包。
- 依賴包名稱:
DWONLOAD_URL
DWONLOAD_URL
是一個可下載的tarball
壓縮包地址,模塊安裝時會將這個.tar下載並安裝到本地。
- 依賴包名稱:
LOCAL_PATH
LOCAL_PATH
是一個本地的依賴包路徑,例如file:../pacakges/pkgName
。適用於你在本地測試一個npm
包,不應該將這種方法應用於線上。
- 依賴包名稱:
GITHUB_URL
GITHUB_URL
即github
的username/modulename
的寫法,例如:ant-design/ant-design
,你還可以在後面指定tag
和commit 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
指定了項目運行所依賴的模塊,開發環境和生產環境的依賴模塊都可以配置到這裏,例如
"dependencies": {
"lodash": "^4.17.13",
"moment": "^2.24.0",
}
devDependencies
有一些包有可能你只是在開發環境中用到,例如你用於檢測代碼規範的 eslint
,用於進行測試的 jest
,用戶使用你的包時即使不安裝這些依賴也可以正常運行,反而安裝他們會耗費更多的時間和資源,所以你可以把這些依賴添加到 devDependencies
中,這些依賴照樣會在你本地進行 npm install
時被安裝和管理,但是不會被安裝到生產環境:
"devDependencies": {
"jest": "^24.3.1",
"eslint": "^6.1.0",
}
peerDependencies
peerDependencies
用於指定你正在開發的模塊所依賴的版本以及用戶安裝的依賴包版本的兼容性。
上面的說法可能有點太抽象,我們直接拿 ant-design
來舉個例子,ant-design
的 package.json
中有如下配置:
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
當你正在開發一個系統,使用了 ant-design
,所以也肯定需要依賴 React
。同時, ant-design
也是需要依賴 React
的,它要保持穩定運行所需要的 React
版本是16.0.0,而你開發時依賴的 React
版本是 15.x:
這時,ant-design
要使用 React
,並將其引入:
import * as React from 'react'
;
import * as ReactDOM from 'react-dom'
;
這時取到的是宿主環境也就是你的環境中的 React
版本,這就可能造成一些問題。在 npm2
的時候,指定上面的 peerDependencies
將意味着強制宿主環境安裝 react@>=16.0.0
和react-dom@>=16.0.0
的版本。
npm3
以後不會再要求 peerDependencies
所指定的依賴包被強制安裝,相反 npm3
會在安裝結束後檢查本次安裝是否正確,如果不正確會給用戶打印警告提示。
"dependencies": {
"react": "15.6.0",
"antd": "^3.22.0"
}
例如,我在項目中依賴了 antd
的最新版本,然後依賴了 react
的 15.6.0
版本,在進行依賴安裝時將給出以下警告:
optionalDependencies
某些場景下,依賴包可能不是強依賴的,這個依賴包的功能可有可無,當這個依賴包無法被獲取到時,你希望 npm install
繼續運行,而不會導致失敗,你可以將這個依賴放到 optionalDependencies
中,注意 optionalDependencies
中的配置將會覆蓋掉 dependencies
所以只需在一個地方進行配置。
當然,引用 optionalDependencies
中安裝的依賴時,一定要做好異常處理,否則在模塊獲取不到時會導致報錯。
bundledDependencies
和以上幾個不同,bundledDependencies
的值是一個數組,數組裏可以指定一些模塊,這些模塊將在這個包發佈時被一起打包。
"bundledDependencies": ["package1" , "package2"]
協議
{
"license": "MIT"
}
license
字段用於指定軟件的開源協議,開源協議裏面詳盡表述了其他人獲得你代碼後擁有的權利,可以對你的的代碼進行何種操作,何種操作又是被禁止的。同一款協議有很多變種,協議太寬鬆會導致作者喪失對作品的很多權利,太嚴格又不便於使用者使用及作品的傳播,所以開源作者要考慮自己對作品想保留哪些權利,放開哪些限制。
軟件協議可分爲開源和商業兩類,對於商業協議,或者叫法律聲明、許可協議,每個軟件會有自己的一套行文,由軟件作者或專門律師撰寫,對於大多數人來說不必自己花時間和精力去寫繁長的許可協議,選擇一份廣爲流傳的開源協議就是個不錯的選擇。
以下就是幾種主流的開源協議:
- MIT:只要用戶在項目副本中包含了版權聲明和許可聲明,他們就可以拿你的代碼做任何想做的事情,你也無需承擔任何責任。
- Apache:類似於 MIT,同時還包含了貢獻者向用戶提供專利授權相關的條款。
- GPL:修改項目代碼的用戶再次分發源碼或二進制代碼時,必須公佈他的相關修改
如果你對開源協議有更詳細的要求,可以到 https://choosealicense.com/
獲取更詳細的開源協議說明。
目錄、文件相關
程序入口
{
"main": "lib/index.js",
}
main
屬性可以指定程序的主入口文件,例如,上面 antd
指定的模塊入口 lib/index.js
,當我們在代碼用引入 antd
時:import { notification } from 'antd'
; 實際上引入的就是 lib/index.js
中暴露出去的模塊。
命令行工具入口
當你的模塊是一個命令行工具時,你需要爲命令行工具指定一個入口,即指定你的命令名稱和本地可指定文件的對應關係。如果是全局安裝,npm 將會使用符號鏈接把可執行文件鏈接到 /usr/local/bin
,如果是本地安裝,會鏈接到 ./node_modules/.bin/
。
{
"bin": {
"conard": "./bin/index.js"
}
}
例如上面的配置:當你的包安裝到全局時:npm
會在 /usr/local/bin
下創建一個以 conard
爲名字的軟鏈接,指向全局安裝下來的 conard
包下面的 "./bin/index.js"
。這時你在命令行執行 conard
則會調用鏈接到的這個js文件。
這裏不再過多展開,更多內容在我後續的命令行工具文章中會進行詳細講解。
發佈文件配置
{
"files": [
"dist",
"lib",
"es"
]
}
files
屬性用於描述你 npm publish
後推送到 npm
服務器的文件列表,如果指定文件夾,則文件夾內的所有內容都會包含進來。我們可以看到下載後的包是下面的目錄結構:
另外,你還可以通過配置一個 .`npmignore` 文件來排除一些文件, 防止大量的垃圾文件推送到 npm, 規則上和你用的 `.gitignore` 是一樣的。`.gitignore` 文件也可以充當.`npmignore` 文件。
man
man
命令是 Linux
下的幫助指令,通過 man
指令可以查看 Linux
中的指令幫助、配置文件幫助和編程幫助等信息。
如果你的 node.js
模塊是一個全局的命令行工具,在 package.json
通過 man
屬性可以指定 man
命令查找的文檔地址。
man
文件必須以數字結尾,或者如果被壓縮了,以 .gz
結尾。數字表示文件將被安裝到 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
模塊是基於 CommonJS
模塊化規範實現的,嚴格按照 CommonJS 規範,模塊目錄下除了必須包含包描述文件 package.json
以外,還需要包含以下目錄:
- bin:存放可執行二進制文件的目錄
- lib:存放js代碼的目錄
- doc:存放文檔的目錄
- test:存放單元測試用例代碼的目錄
- …
在模塊目錄中你可能沒有嚴格按照以上結構組織或命名,你可以通過在 package.json
指定 directories
屬性來指定你的目錄結構和上述的規範結構的對應情況。除此之外 directories
屬性暫時沒有其他應用。
{
"directories": {
"lib": "src/lib/",
"bin": "src/bin/",
"man": "src/man/",
"doc": "src/doc/",
"example": "src/example/"
}
}
不過官方文檔表示,雖然目前這個屬性沒有什麼重要作用,未來可能會整出一些花樣出來,例如:doc 中存放的 markdown 文件、example 中存放的示例文件,可能會友好的展示出來。
腳本配置
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
用於配置一些腳本命令的縮寫,各個腳本可以互相組合使用,這些腳本可以覆蓋整個項目的生命週期,配置後可使用 npm run command
進行調用。如果是 npm
關鍵字,則可以直接調用。例如,上面的配置制定了以下幾個命令:npm run test
、npm run dist
、npm run compile
、npm run build
。
{
"config" : { "port" : "8080" }
}
發佈配置
preferGlobal
如果你的 node.js
模塊主要用於安裝到全局的命令行工具,那麼該值設置爲 true
,當用戶將該模塊安裝到本地時,將得到一個警告。這個配置並不會阻止用戶安裝,而是會提示用戶防止錯誤使用而引發一些問題。
private
如果將 private
屬性設置爲 true
,npm
將拒絕發佈它,這是爲了防止一個私有模塊被無意間發佈出去。
publishConfig
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
發佈模塊時更詳細的配置,例如你可以配置只發布某個tag
、配置發佈到的私有 npm
源。更詳細的配置可以參考 npm-config
os
假如你開發了一個模塊,只能跑在 darwin
系統下,你需要保證 windows
用戶不會安裝到你的模塊,從而避免發生不必要的錯誤。
使用 os
屬性可以幫助你完成以上的需求,你可以指定你的模塊只能被安裝在某些系統下,或者指定一個不能安裝的系統黑名單:
"os" : [ "darwin", "linux" ]
"os" : [ "!win32" ]
例如,我把一個測試模塊指定一個系統黑名單:“os” : [ “!darwin” ],當我在此係統下安裝它時會爆出如下錯誤:
在node環境下可以使用 process.platform 來判斷操作系統。
cpu
和上面的 os
類似,我們可以用 cpu
屬性更精準的限制用戶安裝環境:
"cpu" : [ "x64", "ia32" ]
"cpu" : [ "!arm", "!mips" ]
在node環境下可以使用 process.arch 來判斷 cpu 架構。
參考
http://caibaojian.com/npm/files/package.json.html