(譯)package.json詳解

原文連接php

概述html

本文囊括了全部package.json文件中你須要知道的細節。注意package.json必須是純JSON的,而不只僅是一個JavaScript對象字面量。
該文件描述的不少行爲都受npm-config中的配置影響。node

下面分別介紹package.json中各個字段的含義和用法。linux

namegit

name和version字段是package.json文件中最重要的字段。這是必須的字段,若是你的npm包沒有指定這兩個字段,將沒法被安裝。name和version字段被假定組合成一個惟一的標識符。包內容的更改和包版本的更改是同步的。github

name字段的含義不須要過多解釋,就是npm包名。express

幾個規則:apache

1. name的長度必須小於等於214個字符。
2. name不能以"."(點)或者"_"(下劃線)開頭。
3. name中不能包含大寫字母。
4. name最終將被用做URL的一部分、命令行的參數和文件夾名。所以,name不能含有非URL安全的字符。npm

幾個建議:json

1. 不要使用已存在的name做爲包名。
2. 不要在name中使用"js"和"node",這會假定這是js文件,一旦你寫一個package.json文件,你就能夠在"engines"字段中指定解釋器引擎。
3. name字段可能會被做爲傳輸傳遞給require()函數,所以它最好是簡短的、自描述的。
4. 你可能會須要在深刻開發一個包以前先檢查npm的registry來確認某個name是否被使用過,能夠參考https://www.npmjs.com/。

一個name能夠用scope來指定一個前綴,好比@myorg/mypackage,能夠參考npm-scope

version

name和version字段是package.json文件中最重要的字段。這是必須的字段,若是你的npm包沒有指定這兩個字段,將沒法被安裝。name和version字段被假定組合成一個惟一的標識符。包內容的更改和包版本的更改是同步的。

version字段必須可以被node-semver解析,node-semver做爲依賴項被捆綁進了npm中。(可使用npm install semver來使用)

關於版本號和範圍的信息能夠參考semver

description

npm包的描述,description是一個字符串。它能夠幫助人們在使用npm search時找到這個包。

keywords

npm包的關鍵字,keywords是一個字符串的數組。它能夠幫助人們在使用npm search時找到這個包。

homepage

項目主頁的url。

注意: 這和"url"不同。若是你放一個"url"字段,registry會覺得是一個跳轉到你發佈在其餘地方的地址,而後鄙視你。

bugs

改項目的issue跟蹤頁面或這報告issue的email地址。這對使用這個包遇到問題的用戶會有幫助。

差很少是這樣:

{ 
  "url" : "https://github.com/owner/project/issues",
  "email" : "project@hostname.com"
}

你能夠擇其一或者兩個都寫上。若是隻想提供一個url,你能夠對"bugs"字段指定一個字符串而不是object。

若是提供了一個url,它會被用於npm bugs命令。

license

你應該對你的包指定一個license來讓用戶知道他們的使用權利和和任何限制。

若是你正在使用BSD-2-Clause或MIT這樣的通用許可證,能夠爲你的license添加一個當前SPDX的許可證標識符,好比:

{ "license" : "BSD-3-Clause" }

你能夠查看SPDX許可證標識符的完整列表,理想狀況下你應該挑選一個通過OSI覈準的標識符。

若是你的包在多個通用許可證下被受權,使用一個SPDX許可證表達式語法v2.0,好比:

{ "license" : "(ISC OR GPL-3.0)" }

若是你正在使用的許可未被授予一個SPDX標識符,或者你正在使用自定義的許可證,使用以下:

{ "license" : "SEE LICENSE IN <filename>" }

而後在包的根目錄下提供一個叫<filename>的許可證文件。

一些舊的包使用license對象或一個"license"屬性包含一個license的數組:

// Not valid metadata
{ "license" :
    { 
        "type" : "ISC""url" : "http://opensource.org/licenses/ISC"
    }
}        
//Notvalidmetadata
{
    "licenses": [
        {
            "type": "MIT",
            "url": "http://www.opensource.org/licenses/mit-license.php"
        },
        {
            "type": "Apache-2.0",
            "url": "http://opensource.org/licenses/apache2.0.php"
        }
    ]
}

上述這種風格的寫法已經被廢棄了,取而代之的是SPDX表達式:

{ "license": "ISC" }

{ "license": "(MIT OR Apache-2.0)" }

最後,若是你不但願受權別人以任何形式使用私有包或未發佈的包,能夠這樣寫:

{ "license": "UNLICENSED"}

也能夠設置:

"private": true

來防止意外的發佈。

關於人的字段: author, contributors

author是一我的,contributors是一些人的數組。person是一個對象,擁有必須的name字段和可選的url和email字段,像這樣:

{
    "name": "Barney Rubble",
    "email": "b@rubble.com",
    "url": "http://barnyrubble.tumblr.com/"
}

或者你也可使用單個字符串的精簡形式,npm會幫你解析它:

"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"

這裏email和url也是可選的。

npm也會使用你提供的npm用戶信息來設置一個頂級的"maintainers"字段。

files

files字段是一個被項目包含的文件名數組,若是你在裏面放一個文件夾名,那麼這個文件夾中的全部文件都會被包含進項目中(除非是那些在其餘規則中被忽略的文件)。

你還能夠在包的根目錄或子目錄下提供一個".npmignore"文件來忽略項目包含文件,即便這些文件被包含在files字段中。.npmignore文件和.gitignore的功能很像。

某些文件老是被包含的,不管是否在規則中指定了它們:

package.json
README (and its variants)
CHANGELOG (and its variants)
LICENSE / LICENCE

相反地,一些文件老是被忽略:

.git
CVS
.svn
.hg
.lock-wscript
.wafpickle-N
*.swp
.DS_Store
._*
npm-debug.log

main

main字段指定了模塊的入口程序文件。就是說,若是你的模塊名叫"foo",用戶安裝了它,而且調用了 require("foo"),則這個main字段指定的模塊的導出對象會被返回。

這應該是一個相對於包根目錄的模塊標識。

對於大部分模塊來講,main字段除了指定一個主入口文件之外沒什麼其餘用處了。

bin

許多包有一個或多個可執行文件但願被安裝到系統路徑。在npm下要這麼作很是容易(事實上,npm就是這麼運行的)。

這須要在你的package.json中提供一個bin字段,它是一個命令名和本地文件名的映射。在安裝時,若是是全局安裝,npm將會使用符號連接把這些文件連接到prefix/bin,若是是本地安裝,會連接到./node_modules/.bin/。

好比,要使用myapp做爲命令時能夠這麼作:

{ "bin" : { "myapp" : "./cli.js" } }

這麼一來,當你安裝myapp,npm會從cli.js文件建立一個到/usr/local/bin/myapp的符號連接(這使你能夠直接在命令行執行myapp)。

若是你只有一個可執行文件,那麼它的名字應該和包名相同,此時只須要提供這個文件路徑(字符串),好比:

{
    "name": "my-program",
    "version": "1.2.5",
    "bin": "./path/to/program"
}

這和如下這種寫法相同:

{
    "name": "my-program",
    "version": "1.2.5",
    "bin": {
        "my-program": "./path/to/program"
    }
}

man

指定一個單一的文件名或一個文件名數組來讓man程序使用。

若是隻給man字段提供一個文件,則安裝完畢後,它就是man <pkgname>的結果,這和此文件名無關,好比:

{
    "name": "foo",
    "version": "1.2.3",
    "description": "A packaged foo fooer for fooing foos",
    "main": "foo.js",
    "man": "./man/doc.1"
}

上面這個配置將會在執行man foo時就會使用./man/doc.1這個文件。

若是指定的文件名並未以包名開頭,那麼它會被冠之前綴,像這樣:

{
    "name": "foo",
    "version": "1.2.3",
    "description": "A packaged foo fooer for fooing foos",
    "main": "foo.js",
    "man": [
        "./man/foo.1",
        "./man/bar.1"
    ]
}

這將會爲man foo和man foo-bar建立文件。

man文件必須以一個數字結尾,和一個可選的.gz後綴(當它被壓縮時)。這個數字說明了這個文件被安裝到哪一個節中。

{
    "name": "foo",
    "version": "1.2.3",
    "description": "A packaged foo fooer for fooing foos",
    "main": "foo.js",
    "man": [
        "./man/foo.1",
        "./man/foo.2"
    ]
}

會爲使用man foo和man 2 foo而建立。

directories

CommonJS Packages規範說明了幾種你能夠用directories對象來標示你的包結構的方法。若是你去看npm's package.json,你會看到它標示出出doc、lib和man。

在將來,這個信息可能會被用到。

directories.lib

告訴你庫文件夾的位置,目前沒有什麼地方須要用到lib文件夾,可是這是重要的元信息。

directories.bin

若是你在directories.bin中指定一個bin目錄,在這個目錄中的全部文件都會被當作在bin來使用。

因爲bin指令的工做方式,同時指定一個bin路徑和設置directories.bin將是一個錯誤。若是你想指定獨立的文件,使用bin,若是想執行某個文件夾裏的全部文件,使用directories.bin。

directories.man

directories.man指定的文件夾裏都是man文件,系統經過遍歷這個文件夾來生成一個man的數組。

directories.doc

把markdown文件放在這。也許某一天這些文件將被漂亮地展現出來,不過這僅僅是也許。

directories.example

把示例腳本放在這。也許某一天會被用到。

repository

指明你的代碼被託管在何處,這對那些想要參與到這個項目中的人來講頗有幫助。若是git倉庫在github上,用npm docs命令將會找到你。

像這樣:

{
    "repository": {
        "type": "git",
        "url": "https://github.com/npm/npm.git"
    }
}

url應該是公開且可用的(多是隻讀的),這個url應該能夠被版本控制系統不經修改地處理。不該該是一個在瀏覽器中打開的html項目頁面,這個url是給計算機使用的。

對於github、github gist、Bitbucket或GitLab的倉庫,你能夠在npm install中使用相同的縮寫形式:

"repository": "npm/npm"
"repository": "gist:11081aaa281"
"repository": "bitbucket:example/repo"
"repository": "gitlab:another/repo"

scripts

scripts字段是一個由腳本命令組成的字典,這些命令運行在包的各個生命週期中。這裏的鍵是生命週期事件名,值是要運行的命令。能夠參考npm-scripts獲取配置scripts的更多信息。

config

config字段是一個對象,能夠用來配置包腳本中的跨版本參數,好比以下這個實例:

{
    "name": "foo",
    "config": {
        "port": "8080"
    }
}

而後有一個start命令引用npm_package_config_port環境變量,用戶也能夠用以下方式改寫:

npm config set foo:port 8001

能夠參考npm-confignpm-scripts得到更多關於包配置的信息。

dependencies

dependencies字段是一個對象,它指定了依賴的包名和其版本範圍的映射。版本範圍是個有一個或多個空白分隔描述符的字符串。dependencies字段還能夠用tarball或者git URL。

請不要將測試或過渡性的依賴放到dependencies中,請參考下面的devDependencies。

能夠參考semver獲取更多關於指定版本範圍的細節信息。

1. version 必須確切匹配這個version
2. \>version 必須大於這個version
3. \>=version 必須大於等於這個version
4. < version 必須小於這個version
5. <=version 必須小於等於這個version
6. ~version 大約至關於version,參考[semver](https://docs.npmjs.com/misc/semver)
7. ^version 與version兼容,參考[semver](https://docs.npmjs.com/misc/semver)
8. 1.2.x 能夠是1.2.0、1.2.1等,但不能是1.3.0
9. http://... 參考下面的URL做爲依賴項
10. \* 匹配任何版本
11. ""(空字符串) 匹配任何版本,和\*同樣
12. version1 - version2 至關於 >=version1 <=version2
13. range1 || range2 range1或range2其中一個知足時採用該version
14. git... 參考下面的Git URL做爲依賴項
15. user/repo 參考下面的GitHub URLs
16. tag 一個以tag發佈的指定版本,參考[npm-tag](https://docs.npmjs.com/cli/tag)
17. path/path/path 參考下面的本地Paths

舉個栗子,下面這種寫法是合法的:

{
    "dependencies": {
        "foo": "1.0.0 - 2.9999.9999",
        "bar": ">=1.0.2 <2.1.2",
        "baz": ">1.0.2 <=2.3.4",
        "boo": "2.0.1",
        "qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
        "asd": "http://asdf.com/asdf.tar.gz",
        "til": "~1.2",
        "elf": "~1.2.3",
        "two": "2.x",
        "thr": "3.3.x",
        "lat": "latest",
        "dyl": "file:../dyl"
    }
}

URLs做爲依賴項

能夠在version上指定一個壓縮包的url。

當執行npm install時這個壓縮包會被下載而且安裝到本地。

Git URLs做爲依賴項

Git URLs能夠是以下幾種形式之一:

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

commit-ish能夠是任何tag、sha或者branch,並做爲一個參數提供給git進行checkout,默認值是master。

GitHub URLs

從1.1.65版本開始,你能夠引用Github urls做爲版本號,好比"foo": "user/foo-project"。也能夠包含一個commit-ish後綴,舉個栗子:

{
    "name": "foo",
    "version": "0.0.0",
    "dependencies": {
        "express": "visionmedia/express",
        "mocha": "visionmedia/mocha#4727d357ea"
    }
}

本地路徑

從版本2.0.0開始你能夠提供一個包的本地路徑。本地路徑能夠在你使用npm install -S或npm install --save時被保存,具體形式以下:

../foo/bar
~/foo/bar
./foo/bar
/foo/bar

在下面這種狀況下它會被規範化成爲一個相對路徑而且加入到你的package.json文件中,好比:

{
    "name": "baz",
    "dependencies": {
        "bar": "file:../foo/bar"
    }
}

這個特性有助於當你不想從一個外部服務器安裝npm包的狀況,好比本地離線開發和建立測試,但最好不要在發佈包到公共registry時這樣使用。

devDependencies

若是有人計劃在他們的項目中下載和使用你的模塊,但他們可能並不想或並不須要你開發所使用的外部測試和文檔框架。

在這種狀況下,最好將這些附加的項放在devDependencies中。

這些項將會在根目錄下執行npm link或npm install時被安裝,而且能夠像其餘npm配置參數同樣被管理。能夠參考npm-config得到更多信息。

對於那些非特定平臺的構建步驟,好比編譯CoffeeScript或把其餘語言轉換成JavaScript,可使用prepublish腳原本處理,而且把這個過程的依賴包放在devDependencies中。

舉個栗子:

{
    "name": "ethopia-waza",
    "description": "a delightfully fruity coffee varietal",
    "version": "1.2.3",
    "devDependencies": {
        "coffee-script": "~1.6.3"
    },
    "scripts": {
        "prepublish": "coffee -o lib/ -c src/waza.coffee"
    },
    "main": "lib/waza.js"
}

prepublish腳本會在publishing前運行,這樣用戶就能夠不用本身去require來編譯就能使用。在開發模式下(好比本地運行npm install),將會執行這個腳本,這樣測試就很是方便了。

peerDependencies

在某些狀況下,當一個主機沒法require依賴包時,你會想要告訴它還有哪些工具或庫與這個依賴包兼容。這一般被成爲一個插件。尤爲是在host文檔中聲明的模塊會暴露一個特定的接口。

舉個栗子:

{
    "name": "tea-latte",
    "version": "1.3.5",
    "peerDependencies": {
        "tea": "2.x"
    }
}

這將確保tea-latte這個包只會和2.x版本的tea一塊兒被安裝。執行npm install tea-latte可能產生如下關係圖:

├── tea-latte@1.3.5
└── tea@2.2.0

注意:若是沒有在依賴樹中顯式聲明比它們更高的依賴版本,版本1和版本2的npm將會自動安裝peerDependencies。在npm的下一個大版本npm3中,狀況將徹底不一樣。你將收到一個警告,告訴你peerDependency尚未被安裝。在npm1和npm2中這個行爲常常會致使混亂,新的npm版本的設計將會極力避免這種狀況。

試圖安裝一個有衝突的依賴項的插件將會致使一個錯誤。所以你必須確保你的插件的依賴項版本範圍儘量大,而且不要把版本鎖死在一個特色的補丁版本上。

假設主機使用semver進行編譯,只改變這個包的主版本將會致使你的插件不可用。所以,若是你的插件的某個依賴包運行在每一個1.x版本下,使用"^1.0"或"1.x"。若是你須要的功能在1.5.2版本中,使用">= 1.5.2 < 2"。

bundledDependencies

在發佈包時,包名的數組會被打包進去。

若是拼寫成"bundleDependencies"(少個d),也是能夠的。

optionalDependencies

若是一個依賴項可用,但但願在這個依賴項沒法被找到或者安裝時失敗npm還能繼續處理(不中斷),那麼你能夠把它放在optionalDependencies中。和dependencies同樣,optionalDependencies是一個包名和版本號或url的映射。區別在於optionalDependencies中的依賴構建失敗時不會致使npm總體安裝失敗。

可是你的程序依然有責任處理這種缺失的依賴項,好比這樣:

try{
    varfoo=require('foo')varfooVersion=require('foo/package.json').version
}catch(er){
    foo=null
}if(notGoodFooVersion(fooVersion)){
    foo=null
}//..thenlaterinyourprogram..if(foo){
    foo.doFooThings()
}

optionalDependencies中的項會覆蓋dependencies中的同名項,因此一個特定名字的項最好只出如今一個地方。

engines

你能夠指定node的工做版本:

{ "engines" : { "node" : ">=0.10.3 <0.12" } }

和dependencies相似,若是你不指定一個node版本(或者你用'*'指定),則任何一個node版本均可以。

若是你指定了一個'engines'字段,則npm將會在某處包含這個node版本。若是忽略'engines'字段,則npm只會僅僅假設這個包工做在node下。

你還可使用'engines'字段來指定能夠安裝這個包的npm版本,舉個栗子:

{ "engines" : { "npm" : "~1.0.20" } }

請注意,除非用戶設置了engine-strict標記,不然這個字段只是一個建議值。

engineStrict

這個特性在npm 3.0.0中已經廢棄。

npm 3.0.0以前的版本,這個特性用來處理那些設置了engine-strict標記的包。

os

能夠指定模塊運行的操做系統:

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

也可使用操做系統黑名單來替代白名單,只要在前面加個'!':

"os" : [ "!win32" ]

主機的操做系統能夠經過process.platform來肯定。

雖然找不到什麼很好的理由支持這麼作,可是這裏還能夠黑名單和白名單混用。

cpu

若是你的代碼只能運行在特定的cpu架構上,你能夠指明:

"cpu" : [ "x64", "ia32" ]

和os選項相似,你還可使用黑名單:

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

主機的cpu架構能夠經過process.arch來肯定。

preferGlobal

若是你的包是一個須要進行全局安裝的命令行應用,須要設置preferGlobal爲true,若是這個包被本地安裝會報出一個警告。

這個選項並不會阻止用戶本地安裝這個包,但這麼作確實能在包未按照預期被安裝形成諸多麻煩時提供一些提示。

private

若是你在包的package.json中設置"private": true,則npm會拒絕發佈它。

這是防止私有包被之外發布的一種方法。若是你但願包裝某個包只能被髮布到特定的一個registry中(好比,一個內部的registry),則可使用下面的publishConfig字典來描述以在publish-time重寫registry配置參數。

publishConfig

這是一個在publish-time時會用到的配置集合。當你想設置tag、registry或access時特別有用,因此你能夠確保一個給定的包沒法在沒有被打上"latest"標記時就被髮布到全局公共的registry。

任何配置均可以被覆蓋,固然可能只有"tag", "registry"和"access"和發佈意圖有關。

參考npm-config來查看那些能夠被覆蓋的配置項列表。

DEFAULT VALUES

npm會基於包內容設置一些默認值。

"scripts": {"start": "node server.js"}

若是包的根目錄中有一個server.js,那麼npm會用它來做爲入口文件:運行node server.js。

"scripts":{"preinstall": "node-gyp rebuild"}

若是包的根目錄中有一個binding.gyp文件,那麼npm會在運行preinstall命令編譯時使用它。

 "contributors": [...]

若是包的根目錄中有一個AUTHORS文件,那麼npm會把它的每個行格式化成Name \< email \> (url)的形式,其中email和url是可選的。以一個#或者空白符開頭的行將被忽略。

參考資料

semver
npm-init
npm-version
npm-config
npm-config
npm-help
npm-faq
npm-install
npm-publish
npm-uninstall

相關文章
相關標籤/搜索