一文詳解package.json配置
npm 介紹
npm
是隨同 Node.js
一起安裝的包管理工具,能解決 Node.js
代碼部署上的很多問題,常見的使用場景有以下幾種:
- 允許用戶從
NPM
服務器下載別人編寫的第三方包到本地使用; - 許用戶從
NPM
服務器下載并安裝別人編寫的命令行程序到本地使用; - 允許用戶將自己編寫的包或命令行程序上傳到
NPM
服務器供別人使用;
在現在的前端世界里,幾乎已經離不開 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()
函數加載的任何文件和目錄,這樣的稱為模塊,一個 packages
也是模塊,只不過是由多個模塊組成的包。
為了可以通過 require()
函數加載到模塊,它必須具有以下特征之一:
- 文件夾中包含
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
函數被正常調用,最終輸出 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
官網搜索到的包名就是該字段的值,如果不打算發(fā)布你的包,則 name
是可選的,name
的 值遵循以下規(guī)則:
- 必須小于或等于214個字符;
- 不能以
'.'
、"_"
、大寫字母、中文開頭,該字段最終成為URL
、命令行上的參數和文件夾名稱的一部分。因此,name
不能包含任何非url安全字符; - 不能使用
NOdejs
核心模塊相同的名稱; - 這個名字可能會作為參數傳遞給
require()
函數,所以它應該很短,但也要合理地描述; - 如果你需要發(fā)布包,你需要查看
npm
的注冊表(registry
)是否存在同名包,否則你將無法發(fā)布成功,當然你可以通過后期修改;
在實際的開發(fā)中,很多項目都不需要發(fā)布到 npm
上,所以這個 name
在這里并不是那么重要,不會影響項目正常運作,可以忽略。
version
和 name
一樣,如果要發(fā)布你的包,這個字段很重要,如果不需要,這個字段則顯得不是那么重要了。
version
必須可以被 node-semver 解析,node-semver
作為依賴項與 npm
捆綁在一起。
semver
的版本規(guī)范是 X.Y.Z
:
X
為主版本號(major
): 通常在涉及重大功能更新,產生了破壞性變更時會更新此版本號;Y
為次版本號(Minor
): 在引入了新功能,但并未產生破壞性變更,依然向下兼容時更新此版本號;Z
為修訂號(Patch
): 在修復了一些問題,但未產生破壞性變更時會更新此版本號;
除了 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
官網上更好的搜索到此項目,增加曝光率。例如 axios
的 keywords
如下:
"keywords": [ "xhr", "http", "ajax", "promise", "node" ],
homepage
項目主頁的鏈接,通常是項目 github
鏈接,項目官網或者文檔首頁,如果是 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
字段是一個數組,當需要項目進行 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
字段里的腳本運行時的參數,例如設置 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
字段表示運行依賴,也就是項目中生產環(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ā)階段中使用,不需要在生產環(huán)境中使用,要使依賴安裝到 devDependencies
字段上,可以使用 npm install <packagename> --save-dev
或者 npm install <packagename> -D
dependencies擴展
在依賴包中后面的參數就是版本,這些版本信息有以下規(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ā)現 hi
會被正常輸出了。
private
private
字段可以防止我們意外地將私有庫發(fā)布到 registry
,只需將 private
字段設置為 true
即可:
"private": true
@ 作用域
已知所有的 npm
包都有一個名字,但是隨著用戶量的增大,npm
包的包名就出現了被占用的問題,占用后其他人就不能使用了,當然 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配置的資料請關注腳本之家其它相關文章!
相關文章
實例分析nodejs模塊xml2js解析xml過程中遇到的坑
這篇文章主要介紹了實例分析nodejs模塊xml2js解析xml過程中遇到的坑,涉及nodejs模塊xml2js解析xml過程中parseString方法參數使用技巧,需要的朋友可以參考下2017-03-03Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解
這篇文章主要介紹了Node.js報錯信息Error:?Cannot?find?module?'XXX'問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10