npm相關知識整理
語義化版本
-
major: 重大變化,不兼容老版本
-
minor: 新增功能,兼容老版本
-
patch: 修復bug,兼容老版本
依賴版本號
-
* 匹配最新版本的依賴
-
^ 匹配最近的大版本依賴,比如^1.2.3,會匹配所有1.x.x的包,不包括2.0.0
-
~ 會匹配最近的小版本依賴,比如~1.2.3,會匹配所有1.2.x版本,不包括1.3.0
package入口
如果使用import對庫進行導入,會優先尋找module欄位引入,然後才是main欄位。
{
name: 'midash',
main: './dist/index.js', // es module入口
module: './dist/index.mjs' // commonjs入口
}
package-lock
鎖定規則
-
當package-lock.json中的依賴鎖定版本符合package.json中的版本號範圍時,將以package-lock.json鎖死版本號為主。
-
當package-lock.json中的依賴鎖定版本不符合package.json中的版本號範圍時,將會安裝符合package.json版本號範圍的最新版本號依賴,並重寫 package-lock.json文件
要不要提交package-lock
-
對於項目開發而言,有必要。當有了lock文件時,每一個依賴的版本號都被鎖死在了lock文件,每次依賴安裝的版本號都從lock文件中進行獲取,避免了不可測的依賴風險。
-
對於庫開發而言,也有必要。雖然項目中所有依賴都會根據項目lockfile鎖死而並不會依照庫依賴的lockfile,但是為了貢獻者能很容易地將項目跑起來,devDependencies必須在庫的lockfile中鎖定。
npm腳本原理
- 每當執行npm run xx,就會自動新建一個Shell,在這個Shell裡面執行指定的腳本命令。因此,只要是Shell可以運行的命令,一般是Bash,就可以寫在npm腳本裡面。
- npm run新建的這個Shell,會將當前目錄的node_modules/.bin子目錄加入PATH變數,執行結束後,再將PATH變數恢復原樣,這也就是為什麼npm run指向的命令能夠被執行的原因。
npm腳本執行
{
"scripts": {
"bx": "npm run script1.js & npm run script2.js", // 並行執行(同時執行)
"abc": "npm run script1.js && npm run script2.js", // 繼發執行(即只有前一個任務成功,才執行下一個任務)
}
}
Windows下不支援這2種方式,可以通過安裝npm-run-all、Concurrently模組解決。
npm常用別名
npm add -> npm install
npm create -> npm init
npm發布
- 第一步,在npm官網進行註冊一個帳號。
- 第二步,執行 npm login,輸入註冊的帳號密碼完成登錄。
- 第三步,npm i -y 初始化 package 文件,填入最基本的3個欄位:name,version 和 main 欄位,其中main欄位應該是打包後的程式碼。
- 第四步,在包目錄執行npm publish
npm變數
通過npm_package_前綴,js腳本可以通過process.env對象拿到package.json裡面的欄位。比如,下面這個package.json:
{
"name": "foo",
"version": "1.2.5",
"scripts": {
"view": "node view.js"
}
}
// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
npm_package_前綴也支援嵌套的package.json欄位
// view.js
console.log(process.env.npm_package_scripts_view); // node view.js
npm依賴
-
dependencies 生產依賴
-
devDependencies 開發依賴
安裝命令
npm i --save xxx // 生產依賴
npm i --save-dev // 開發依賴
npm i -S xxx // 生產依賴(簡寫)
npm i -D xxx // 開發依賴(簡寫)
是否要嚴格區分生產和開發?
-
當進行項目開發時,並無必要。因為打包時,依靠的是Webpack/Rollup對程式碼進行模組依賴分析,與該模組是否在dep/devDep並無關係,只要在 node_modules上能夠找到該依賴即可。
-
當進行庫開發時,有必要。因為當在項目中安裝一個依賴庫時,只有該依賴的dependencies會被安裝到node_modules中,devDependencies不會,因此這裡如果不區分,會導致開發項目報錯受影響。
npm鉤子
npm鉤子,也稱npm生命周期。npm默認提供pre和post兩個鉤子,當我們執行任意npm run腳本時,都將自動觸發pre/post的鉤子但是這2個鉤子的內容需要由你自定義。
{
"scripts": {
"preabc": "xxx",
"abc": "xxx",
"postabc": "xxx"
}
}
當你執行npm run abc時,會自動按照下面的順序執行
npm run preabc -> npm run abc -> npm run postabc
一些常用npm腳本,如:publish、install、uninstall、version、test、stop、start和restart,同樣支援自定義這2個鉤子。
npm restart
npm restart是一個複合命令,實際上會執行三個腳本命令:stop、restart、start。具體的執行順序如下:
prerestart
prestop
stop
poststop
restart
prestart
start
poststart
postrestart
npm publish
npm publish發包的生命周期比較複雜,當執行npm publish命令,將自動執行以下腳本:
prepublishOnly: 最重要的一個生命周期,如果你需要在發包之前自動做一些事情,如測試、構建等,可以在這裡完成。
prepack
prepare
postpack
publish
postpublish
prepare鉤子
一個最常用的生命周期鉤子,它的執行時機:
-
npm install 之後自動執行
-
npm publish 之前自動執行
常用的git hook工具husky通常就被放置在這個鉤子里執行
{
prepare: "husky install";
}
npm_lifecycle_event變數
npm提供一個npm_lifecycle_event變數,返回當前正在運行的腳本名稱,比如pretest、test、posttest等等。所以,可以利用這個變數,在同一個腳本文件裡面,為不同的npm scripts命令編寫程式碼。
const TARGET = process.env.npm_lifecycle_event;
if (TARGET === 'test') {
console.log(`Running the test task!`);
}
if (TARGET === 'pretest') {
console.log(`Running the pretest task!`);
}
if (TARGET === 'posttest') {
console.log(`Running the posttest task!`);
}
npx命令
npm 從5.2版開始,增加了npx命令,可以提升開發者使用包內提供的命令行工具的體驗,它有很多用處。
方便調用項目安裝的模組
通常我們安裝完npm依賴或腳手架後,需要將其寫入package.json的scripts欄位裡面,運行npm run xxx才能執行,npx就是想解決這個問題,利用npx,我們可以直接調用運行。
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-bundle": "vue-cli-service build --target lib --name t3-ui ./src/components/index.js",
"lint": "vue-cli-service lint"
}
我們用npx命令的話, 就不需要在寫scripts裡面的內容, 直接在控制台執行npx vue-cli-service serve,就會直接尋找本地依賴並執行。
避免全局安裝模組
運行npx命令後,npx會將依賴下載到一個臨時目錄,使用以後再刪除
npx [email protected] main.js -o ./dist/main.js // 臨時下載壓縮包,執行壓縮
npx http-server // 臨時在當前目錄,安裝並運行起本地伺服器
使用不同版本的node
npx -p node@6 npm run serve
執行邏輯如下:
- npx下載node@6版本
- 將執行的node版本切換為node@6版本
- 使用node@6執行npm run serve
- 命令執行完畢後,刪除下載包,最終不會改變本地的使用版本
npx命令執行邏輯
先自動查找當前依賴包中的可執行文件,如果找不到,就會去PATH里找,如果依然找不到,就會幫你臨時安裝,執行完後再刪除包。
npm init命令
命令用法:
npm init [--force|-f|--yes|-y|--scope]
npm init <@scope> (same as `npx <@scope>/create`)
npm init [<@scope>/]<name> (same as `npx [<@scope>/]create-<name>`)
npm init xxx時,會自動轉換成如下npx命令:
npm init foo -> npx create-foo
npm init @usr/foo -> npx @usr/create-foo
npm init @usr -> npx @usr/create
以vue3官方安裝為例,命令實際效果如下:
// 實際安裝的是create-vue@latest包
npm init vue@latest -> npx create-vue@latest
npm exec命令和npx作用相同,區別僅在於後者會將其後面的標誌和選項都會優先設置為位置參數,具體可對照npm文檔。
npm link命令
簡而言之,就是可以將你本地的npm開發包當作是已經npm install好後的包使用了,用來在本地項目和本地npm模組之間建立連接,方便關聯到項目中進行修改/調試。
局部link
項目和本地npm模組在同一個目錄下,可以使用相對路徑進行link
npm link ../module // 然後,你本地項目的node_modules就出現了該module的軟鏈接
全局link
1.注入全局link
cd modulePath
npm link // 然後,全局node_modules目錄下就出現該module的軟鏈接
2.引入全局link
cd projectPath
npm link module
解除link
解除局部link
cd projectPath
npm unlink module
解除全局link
cd modulePath
npm unlink
以vite為例
如果你迫不及待想要體驗最新的功能,可以自行克隆vite倉庫,然後到本地機器上然後自行將其鏈接
// 第1步,克隆並進入目錄
git clone //github.com/vitejs/vite.git
cd vite
// 第2步,安裝vite作為npm開發包的依賴,然後打包出開發者需要的vite
pnpm install
cd packages/vite
npm run build
// 第3步,全局注入link
npm link
// 第4步,進入本地項目,引入link,這個時候就相當於全局安裝了vite,類似於執行了vite官方安裝命令:npm create vite@latest
pnpm link --global vite
// 第5步,package文件的script內dev寫入vite命令
dev: 'vite'
// 第6步,執行npm命令
npm run dev
實際測試發現,使用link後,第5和第6步是多餘的,本地可以直接在控制台使用vite命令,不管你是全局link的,還是局部link的,都可以運行。
參考文章
- //q.shanyue.tech/engineering/
- //www.ruanyifeng.com/blog/2016/10/npm_scripts.html
- //www.ruanyifeng.com/blog/2019/02/npx.html
- //segmentfault.com/a/1190000020082099
- //blog.csdn.net/xuewenjie0217/article/details/123008562
- //blog.csdn.net/lw001x/article/details/124133735
- //juejin.cn/post/7018344866811740173