一文詳解package.json配置
npm 介紹
npm 是隨同 Node.js 一起安裝的包管理工具,能解決 Node.js 代碼部署上的很多問題,常見的使用場景有以下幾種:
- 允許用戶從
NPM服務器下載別人編寫的第三方包到本地使用; - 許用戶從
NPM服務器下載并安裝別人編寫的命令行程序到本地使用; - 允許用戶將自己編寫的包或命令行程序上傳到
NPM服務器供別人使用;
在現(xiàn)在的前端世界里,幾乎已經(jīng)離不開 npm 了,其提供的依賴安裝、卸載、升級、發(fā)布等一條龍服務,使我們在日常的開發(fā)效率提升了不少。
npm 制定了一個包規(guī)范,所謂規(guī)范就是一些格式和約定,比如作為一個 npm 包中根目錄必須包含一個 package.json 文件,并約定從 package.json 文件里讀取這個包的所有信息,包括它的名字、版本號、它依賴于哪些別的包等;
并且創(chuàng)建一個 node_modules 目錄專門用來存放第三方依賴,Node為此提供的支持是內置的 require()方法默認會到這個目錄下去檢索模塊,而無需手動指定路徑。有了這些規(guī)范,一個包的開發(fā)、依賴安裝、發(fā)布等都步驟都標準化了,省心省力。
我們接下來就讓我們開始學習 npm 之旅吧!!!
packages和modules的區(qū)別
一個 packages 是一個文件,在該文件的根目錄,必須包含一個 package.json 文件,通過該文件,你可以將包發(fā)布到 registry。
modules 是 node_modules 目錄下可以被 require() 函數(shù)加載的任何文件和目錄,這樣的稱為模塊,一個 packages 也是模塊,只不過是由多個模塊組成的包。
為了可以通過 require() 函數(shù)加載到模塊,它必須具有以下特征之一:
- 文件夾中包含
package.json文件,并且包含一個main字段作為入口文件; - 一個
JavaScript文件;

在上面的圖中 moment.js 是一個 modules,但不是一個 packages,在外部引入可以使用。

在上面的例子中,在 node_modules 目錄下手動創(chuàng)建一個名為 moment 的文件,并且添加一個 package.json 的文件,在文件中添加 main 字段,設置 main.js 作為文件的入口。
在這里,調用 const foo = require("moment"); 實際上加載的是 moment 文件夾下的 main.js 文件,所以 foo 函數(shù)被正常調用,最終輸出 hi。
package.json 詳解
在前面的內容中我們多次說到 package.json 的文件,那么我們應該怎么創(chuàng)建這個文件呢,npm 給我們提供了一個命令 npm init,在終端輸入該命令,會有以下問題并要求你輸入回答:

最終會在當前路徑生成一個 package.json 文件,文件內容有如下代碼所示:
{
"name": "moment",
"version": "1.0.0",
"description": "描述信息",
"main": "index.js",
"dependencies": {
"moment": "^1.0.0",
"axios": "^1.2.6"
},
"devDependencies": {},
"scripts": {
"test": "node ./index.js"
},
"repository": {
"type": "git",
"url": "github地址"
},
"keywords": [
"react",
"vue"
],
"author": "作者",
"license": "ISC"
}
通過 npm init -y 會生成一個默認的 package.json 文件。接下來我們對 package.json 文件中部分常見的字段進行詳細的講解。
name
如果你要發(fā)布你的包,name 字段是你的 package.json 文件中非常重要的字段,在 npm 官網(wǎng)搜索到的包名就是該字段的值,如果不打算發(fā)布你的包,則 name 是可選的,name 的 值遵循以下規(guī)則:
- 必須小于或等于214個字符;
- 不能以
'.'、"_"、大寫字母、中文開頭,該字段最終成為URL、命令行上的參數(shù)和文件夾名稱的一部分。因此,name不能包含任何非url安全字符; - 不能使用
NOdejs核心模塊相同的名稱; - 這個名字可能會作為參數(shù)傳遞給
require()函數(shù),所以它應該很短,但也要合理地描述; - 如果你需要發(fā)布包,你需要查看
npm的注冊表(registry)是否存在同名包,否則你將無法發(fā)布成功,當然你可以通過后期修改;
在實際的開發(fā)中,很多項目都不需要發(fā)布到 npm 上,所以這個 name 在這里并不是那么重要,不會影響項目正常運作,可以忽略。
version
和 name 一樣,如果要發(fā)布你的包,這個字段很重要,如果不需要,這個字段則顯得不是那么重要了。
version 必須可以被 node-semver 解析,node-semver 作為依賴項與 npm 捆綁在一起。
semver 的版本規(guī)范是 X.Y.Z:
X為主版本號(major): 通常在涉及重大功能更新,產(chǎn)生了破壞性變更時會更新此版本號;Y為次版本號(Minor): 在引入了新功能,但并未產(chǎn)生破壞性變更,依然向下兼容時更新此版本號;Z為修訂號(Patch): 在修復了一些問題,但未產(chǎn)生破壞性變更時會更新此版本號;
除了 X.Y.Z 這樣的版本號,還有 premajor | preminor | prepatch | prerelease 這樣的版本號,這些屬于測試版本,很多時候一些新改動,并不能直接發(fā)布到穩(wěn)定版本上,這是可以發(fā)布一個預發(fā)布版本,不會影響到穩(wěn)定版本。
可以通過以下命令來查看 npm 包的版本信息,如想要查看的react的:
- 查看最新版本
npm view react version
- 查看所有版本
npm view react versions
我們可以通過 child_process 執(zhí)行該命令以獲取某的包的版本,這個方法將在后面的腳手架中用到,具體操作請看以下代碼:
const cp = require("child_process");
cp.exec("npm view react version", (err, stdout, stderr) => {
console.log(stdout); // 18.2.0
});
description
description 字段用來描述這個包,它可以是一個字符串,也可以是中文,在搜索的時候可以看到該包的描述,并且該描述也可以作為搜索的關鍵詞。
例如 react 中的 description 字段的值為 React is a JavaScript library for building user interfaces.,通過搜索 "React is" 能顯示會有以下結果:

keywords
keywords 字段在里面放關鍵字,好的關鍵詞可以幫助開發(fā)者在 npm 官網(wǎng)上更好的搜索到此項目,增加曝光率。例如 axios 的 keywords 如下:
"keywords": [ "xhr", "http", "ajax", "promise", "node" ],
homepage
項目主頁的鏈接,通常是項目 github 鏈接,項目官網(wǎng)或者文檔首頁,如果是 npm 包,會在這里顯示:

bugs
bugs 字段表示項目提交問題的地址,該字段是一個字符串也可以是一個對象,最常見的 bugs 是 github 的issue,例如 react 中的 bugs 是這樣的:
"bugs": "https://github.com/facebook/react/issues"
license
license 字段表示項目的開源許可證,你應該為你的包指定一個許可證,方便其他開發(fā)者知道如何允許他們使用它,以及你對他施加的任何限制,例如:
"license": "ISC"
repository
repository 字段用于指定代碼所在的位置,通常是 github,如果是 npm 包,則會在包的首頁中顯示:

files
files 字段是一個數(shù)組,當需要項目進行 npm 發(fā)布時,可以通過 files 字段指定哪些文件需要發(fā)布到 registry 來控制 npm 包大小,如果指定的是文件夾,那么該文件夾下面的所有文件都會被提交,例如 react 的配置是這樣的,如下代碼所示:
"files": [ "LICENSE", "README.md", "index.js", "cjs/", "umd/", "jsx-runtime.js", "jsx-dev-runtime.js", "react.shared-subset.js" ]
main和browser
main 字段用來指定包的入口入口文件,在上面的內容就忽略不講了,如果不設置,則默認使用包的根目錄中的 index.js 文件作為入口。
main 字段可以在 browser 環(huán)境和 Nodejs 環(huán)境都可以使用,如果 使用 browser 字段,則表明只能在瀏覽器環(huán)境下使用,不能用于服務端。
type
type 字段表示在 Node 環(huán)境中可以使用的模塊化方式,默認是 CommonJs,另外還可以選擇 EsModule。
bin
一些包的作者希望包可以作為命令行工具使用,配置好 bin 字段之后,通過 npm install package_name -g 命令可以將腳本添加到執(zhí)行路徑中,之后可以在命令行中直接執(zhí)行。
bin 字段的主要作用可以看 在終端里輸入 npm start 后都發(fā)生了啥?????? 這篇文章。
exports
exports 字段可以配置不同環(huán)境對應的模塊入口文件,并且當他存在時,它的優(yōu)先級最高,當 package.json 文件中存在 exports 字段,設置的 main 字段會失效,在 react 中的 package.json 文件中的 exports 字段有如下配置:
"exports": {
".": {
"react-server": "./react.shared-subset.js",
"default": "./index.js"
},
"./package.json": "./package.json",
"./jsx-runtime": "./jsx-runtime.js",
"./jsx-dev-runtime": "./jsx-dev-runtime.js",
"./src/*": "./src/*"
},
這個配置相當于 weboack 中的 resolve.alies 配置路徑別名,請看下面的例子,在 node_modules 文件夾下創(chuàng)建一個 moment 文件,并且添加 package.json 文件讓其作為一個 npm 模塊,通過 require('moment') 會查找到當前文件夾,并通過 main 字段或者 exports 字段查找當前字段的入口,請看如下代碼所示:
"exports": {
".":{
"require":"./test.js"
}
在上面的代碼中,使用 require('moment') 則表示會自動導入 moment 包中的 test.js 文件,所以在自己的項目中導入會有以下輸出:
// moment包中的 test.js
function foo() {
return 'test'
}
module.exports=foo
const foo = require("moment");
console.log(foo()); // test
再在 package.json 中的 exports 字段中添加這行代碼:
"./src": {
"require": "./src/moment.js"
}
當在自己的項目中使用 require('moment/src') 進行導入時,實際上導入的是 moment/src 目錄下的 moment.js 文件,默認情況下會 require('moment/src') 會加載 index.js,因為按照 require 規(guī)則會先查找 index.js,具體示例如下代碼所示:
// moment/src/moment.js
function bar(params) {
return "moment.js";
}
module.exports = bar;
// moment/src/index.js
function bar(params) {
return "index.js";
}
module.exports = bar;
const bar = require("moment/src");
console.log(bar()); // moment.js
在自己的項目中使用 require('moment/src') 最終會輸出 moment.js,如果將 exports 字段刪除會輸出 index.js,更多 require 細節(jié)可以參考 深入淺出CommonJs 這篇文章。
config
config 字段用于設置 script 字段里的腳本運行時的參數(shù),例如設置 prot 為3000:
"config": {
"port": "8080"
}
并且在 script 字段下添加 dev屬性,值設置為 nodemon index.js,終端運行 npm run dev
"scripts": {
"dev": "nodemon index.js"
},
在執(zhí)行腳本的時候,我們可以通過 process.env.npm_package_config_port 這個變量訪問到 3000
console.log(process.env.npm_package_config_port); // 3000
dependencies
dependencies 字段表示運行依賴,也就是項目中生產(chǎn)環(huán)境下需要用到的依賴,例如 react、vue、axios 等 npm 包,使用 npn install <packagename> 或者 npm install <packagename> --save 時,會被自動插入到該字段中:
"dependencies": {
"axios": "^1.2.6",
"react": "^18.2.0",
"shelljs": "^0.8.5"
},
devDependencies
devDependencies 字段表示開發(fā)階段時需要的依賴包,例如 webpack、eslint、sass,該依賴用于提升開發(fā)速度,和 dependencies 不同的是,該字段只需要在開發(fā)階段中使用,不需要在生產(chǎn)環(huán)境中使用,要使依賴安裝到 devDependencies 字段上,可以使用 npm install <packagename> --save-dev 或者 npm install <packagename> -D
dependencies擴展
在依賴包中后面的參數(shù)就是版本,這些版本信息有以下規(guī)則:
version: 表示確定的版本號;>version: 大于當前版本;~version: 表示主版本X和次版本Y保持不變,修訂號Z永遠安裝最新的版本;^version: 表示主版本X保持不變,次版本Y和修訂號Z永遠安裝最新的版本;1.2.x: 表示該版本中的x可以是任何符合規(guī)范的值;*和"": 表示匹配任何版本;version1 - version2: 表示 version<=x>= version;version1 || version2: 表示只要其中一個符合即可;latest: 代表最新版本;path/path/path: 提供到包含包的本地目錄的路徑,本地路徑可以使用npm install保存,該文件會被保存在node_modules目錄下,例如,在根目錄創(chuàng)建一個bar的文件并且在package.json中添加以下字段:
"dependencies": {
"bar": "file:./bar"
},
在 bar 的文件中創(chuàng)建 index.js 文件,并編寫以下代碼:
function foo() {
return "hi";
}
module.exports = foo;
通過執(zhí)行 npm install 會把該文件鏈接到 node_modules 目錄文件下,在根目錄中編寫以下代碼:
const bar = require("bar");
console.log(bar());
執(zhí)行命令 node .\index.js,你會發(fā)現(xiàn) hi 會被正常輸出了。
private
private 字段可以防止我們意外地將私有庫發(fā)布到 registry,只需將 private 字段設置為 true 即可:
"private": true
@ 作用域
已知所有的 npm 包都有一個名字,但是隨著用戶量的增大,npm 包的包名就出現(xiàn)了被占用的問題,占用后其他人就不能使用了,當然 npm 也官方不是閑著,他們提供了一個作用域的概念,該作用域遵循包名的通常規(guī)則,即 url 安全字符,在包名使用時,在作用域前面添加一個 @ 符號,表示這個是一個作用域,在后面加一個斜杠,例如:
@somescope/somepackagename
每個 npm 用戶或者組織都有自己的作用域,它可以是你的用戶名、自己創(chuàng)建的組織名,只有你可以在你的作用域中添加包,這就意味著你不必擔心別人會搶在你前面取你的包名,類似于你的 github,你可以取任何的倉庫名稱,只需名稱合法且在你自己的倉庫中不存在同名倉庫。
作用域包通過在 npm install 中引用它的名稱(前面加@符號)來安裝:
npm install @myorg/mypackage
在 package.json 中有以下的形式:
"dependencies": { "@myorg/mypackage": "^1.3.0" }
因為作用域包安裝在作用域文件夾中,所以在代碼中需要它們時,必須包含作用域的名稱:
require('@myorg/mypackage')
script
script 字段支持許多內置腳本和它們的預設生命周期事件以及任意腳本,這些你都可以使用 npm run <stage> 來執(zhí)行,例如當你要執(zhí)行 npm run dev 命令,具有匹配名稱的 Pre 和 Post 命令也就作為這些命令一起執(zhí)行,執(zhí)行順序為 predev - dev - postdev ,例如在 package.json 文件中有如下定義:
"scripts": {
"dev": "node index.js",
"predev": "node pre.js",
"postdev": "node post.js"
},
當執(zhí)行 npm run dev,會首先執(zhí)行 pre.js 文件,然后執(zhí)行 index.js 文件,再最后執(zhí)行 post.js 文件。
更多關于 scirpt 字段的細節(jié)將會在另一篇文章中講解,敬請期待。
參考
書籍: 深入淺出Nodejs;
以上就是一文詳解package.json配置的詳細內容,更多關于package.json配置的資料請關注腳本之家其它相關文章!
相關文章
從reflect?metadata理解Nest實現(xiàn)原理
這篇文章主要為大家介紹了從reflect?metadata理解Nest實現(xiàn)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
實例分析nodejs模塊xml2js解析xml過程中遇到的坑
這篇文章主要介紹了實例分析nodejs模塊xml2js解析xml過程中遇到的坑,涉及nodejs模塊xml2js解析xml過程中parseString方法參數(shù)使用技巧,需要的朋友可以參考下2017-03-03
Node使用koa2實現(xiàn)一個簡單JWT鑒權的方法
這篇文章主要介紹了Node使用koa2實現(xiàn)一個簡單JWT鑒權的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01
Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解
這篇文章主要介紹了Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10
Node.js創(chuàng)建子進程的幾種實現(xiàn)方式
這篇文章主要介紹了Node.js創(chuàng)建子進程的幾種實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10

