一. 包管理工具npm
(關於npm的安裝、配置下載路徑、一些指令,可以參考之前的文章:https://www.cnblogs.com/yaopengfei/p/14478126.html)
1. npm簡介
(1). 包管理工具npm
npm全稱,Node Package Manager,也就是Node包管理器;
但是目前已經不僅僅是Node包管理器了,在前端項目中我們也在使用它來管理依賴的包;比如vue、vue-router、vuex、express、koa、react、react-dom、axios、babel、webpack等等;
(2).如何下載npm工具呢?
npm屬於node的一個管理工具,所以我們需要先安裝Node,安裝完node以后,npm也就安裝了。
node管理工具:https://nodejs.org/en/
(3). npm管理的包可以在哪里查看、搜索呢?
npm包的官網:https://www.npmjs.com/
(4). npm管理的包存放在哪里呢?
我們發布自己的包其實是發布到registry上面的;當我們安裝一個包時其實是從registry上面下載的包;
A. 通過【npm install xxx -g】全局安裝的包,在你設置的全局文件夾下:D:\Develop\npm\node_modules
B. 通過【npm install xxx】和【npm install -D】安裝項目依賴的包,在對應項目的node_modules里。
注意:對於項目依賴的包,她是有緩存的,即如果本地電腦已經下載過這個版本的包,就直接去本地拿到壓縮包,解壓到項目中的node_modules即可,不需要去npm官網的registry上下載,那么這個壓縮包在 D:\Develop\npm-cache 下。
【后面將結合package_lock.json詳細講解】2. npm配置文件(package.json)
(1). npm如何管理這么多包?
我們每一個項目都會有一個對應的配置文件,無論是前端項目(Vue、React)還是后端項目(Node);這個配置文件會記錄着你項目的名稱、版本號、項目描述等;也會記錄着你項目所依賴的其他庫的信息和依賴庫的版本號;
這個配置文件就是package.json
(2). 如何生成這個配置文件
A. 手動從零創建項目,【npm init –y】 或者【npm init】一步一步生成
B. 通過腳手架創建項目,腳手架會幫助我們生成package.json,並且里面有相關的配置
npm init -y 創建的配置文件
{
"name": "01_npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Vue3的配置文件

{
"name": "vue3Admin",
"version": "0.1.0",
"description": "vue3 vite next admin template js setup",
"author": "ypf",
"license": "MIT",
"scripts": {
"serve": "vite --force",
"build": "vite build",
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
},
"dependencies": {
"@element-plus/icons-vue": "^0.2.4",
"axios": "^0.24.0",
"echarts": "^5.2.2",
"element-plus": "^1.2.0-beta.6",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"qrcodejs2-fixes": "^0.0.2",
"screenfull": "^6.0.0",
"sortablejs": "^1.14.0",
"vue": "3.2.20",
"vue-clipboard3": "^1.0.1",
"vue-router": "^4.0.12",
"vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.0.1",
"@vue/compiler-sfc": "^3.2.26",
"dotenv": "^10.0.0",
"eslint": "^8.5.0",
"eslint-plugin-vue": "^8.2.0",
"prettier": "^2.5.1",
"sass": "^1.45.1",
"sass-loader": "^12.4.0",
"unplugin-auto-import": "^0.5.4",
"vite": "^2.7.4",
"vite-plugin-vue-setup-extend": "^0.1.0",
"vue-eslint-parser": "^8.0.1"
},
"browserslist": [
"> 1%", "last 2 versions", "not dead" ], "bugs": { "url": "https://www.cnblogs.com/yaopengfei" }, "engines": { "node": ">=12.0.0", "npm": ">= 6.0.0" }, "keywords": [ "vue", "vue3", "vuejs/vue-next", "vuejs/vue-next-template", "vuejs/vue-next-template-js", "element-ui", "element-plus", "vue-next-admin", "next-admin" ], "repository": { "type": "git", "url": "https://www.cnblogs.com/yaopengfei" } }
3. package.json屬性詳解
(1). 基本屬性
name是項目的名稱;【必填】
version是當前項目的版本號;【必填】
description是描述信息,很多時候是作為項目的基本描述;
author是作者相關信息(發布時用到);
license是開源協議(發布時用到);
(2). private屬性
private屬性記錄當前的項目是否是私有的;
當值為true時,npm是不能發布它的,這是防止私有項目或模塊發布出去的方式;
(3). main屬性
設置程序的入口。webpack實際上是找到對應的main屬性查找文件的
(4). scripts屬性
scripts屬性用於配置一些腳本命令,以鍵值對的形式存在;配置后我們可以通過 npm run 命令的key來執行這個命令;
比如配置了 "serve": "vite --force", 我們就可以執行 【npm run server】 實際上等價於 【npx vite --force】
特殊情況:對於常用的key,是可以省略run的。【npm start】和【npm run start】是等價的。對於常用的 start、 test、stop、restart可以省略掉run直接通過 npm start等方式運行;
(5). dependencies屬性
dependencies屬性是指定無論開發環境還是生產環境都需要依賴的包;通常是我們項目實際開發用到的一些庫模塊vue、vuex、vue-router、react、react-dom、axios等等;
(6). devDependencies屬性
一些包在生產環境是不需要的,僅開發過程中需要,比如webpack、babel等; 這個時候我們會通過 【npm install webpack --save-dev】,將它安裝到devDependencies屬性中;
(7). peerDependencies屬性
還有一種項目依賴關系是對等依賴,也就是你依賴的一個包,它必須是以另外一個宿主包為前提的; 比如element-plus是依賴於vue3的,ant design是依賴於react、react-dom;
(8). 依賴版本管理【重】
npm的包通常需要遵從semver版本規范:semver:https://semver.org/lang/zh-CN/ npm semver:https://docs.npmjs.com/misc/semver
semver版本規范是X.Y.Z:
X主版本號(major):當你做了不兼容的 API 修改(可能不兼容之前的版本);
Y次版本號(minor):當你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
Z修訂號(patch):當你做了向下兼容的問題修正(沒有新功能,修復了之前版本的bug);
比如: "vue": "3.2.20"、“^3.2.20”、“~3.2.20”、
我們這里解釋一下 ^和~的區別:
^x.y.z:表示x是保持不變的,y和z永遠安裝最新的版本;【這里指npm install的時候】
~x.y.z:表示x和y保持不變的,z永遠安裝最新的版本; 【這里指npm install的時候】
x.y.z : 就如字面一樣的版本
(9). engines屬性
engines屬性用於指定Node和NPM的版本號;
在安裝的過程中,會先檢查對應的引擎版本,如果不符合就會報錯;
事實上也可以指定所在的操作系統 "os" : [ "darwin", "linux" ],只是很少用到;
(10). browserslist屬性
用於配置打包后的JavaScript瀏覽器的兼容情況,參考;否則我們需要手動的添加polyfills來讓支持某些語法;也就是說它是為webpack等打包工具服務的一個屬性
二. npm install原理
1. package-lock.json剖析
下面代碼是執行了【npm install axios】后的文件

{
"name": "01_npm",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "01_npm",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"axios": "^0.26.1"
}
},
"node_modules/axios": {
"version": "0.26.1",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dependencies": {
"follow-redirects": "^1.14.8"
}
},
"node_modules/follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
}
},
"dependencies": {
"axios": {
"version": "0.26.1",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"requires": {
"follow-redirects": "^1.14.8"
}
},
"follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
}
}
}
name:項目的名稱;
version:項目的版本;
lockfileVersion:lock文件的版本;
requires:使用requires來跟蹤模塊的依賴關系;
dependencies:項目的依賴,當前項目依賴axios,但是axios依賴follow-redireacts;
axios中的屬性如下:
version表示實際安裝的axios的版本;
resolved用來記錄下載的地址,registry倉庫中的位置;
requires記錄當前模塊的依賴;
integrity用來從緩存中獲取索引,再通過索引去獲取壓縮包文件;
2. 【npm install】指令原理
npm install首先會檢測是有package-lock.json文件:
(1). 沒有lock文件
A. 分析依賴關系,這是因為我們可能包會依賴其他的包,並且多個包之間會產生相同依賴的情況;
B. 從registry倉庫中下載壓縮包(如果我們設置了鏡像,那么會從鏡像服務器下載壓縮包,比如設置了從taobao下載);
C. 獲取到壓縮包后會對壓縮包進行緩存(從npm5開始有的);
D. 將壓縮包解壓到項目的node_modules文件夾中(require的查找順序會在該包下面查找)
(2). 有lock文件
A. 檢測lock中包的版本是否和package.json中一致(會按照semver版本規范檢測,詳見上面08);
B. 不一致,那么會重新構建依賴關系,直接會走頂層的流程;
C. 一致的情況下,會去優先查找緩存
D. 沒有找到,會從registry倉庫下載,直接走頂層流程;
E. 查找到,會獲取緩存中的壓縮文件,並且將壓縮文件解壓到node_modules文件夾中;
(3). 緩存的作用
將通過npm下載過的包存放到本地(D:\Develop\npm-cache\_cacache) ,【npm get cache 查找路徑】,下次npm的時候,會先查看package_lock中的版本是否符合package中的版本要求,如果符合,則優先查找緩存。
如何查找去緩存中查找呢?
package_lock中的integrity屬性存放的是索引,然后根據索引去對應的文件夾Content-v2中找到壓縮包,然后解壓到項目中去。
D:\Develop\npm-cache\_cacache\index-v5 存放索引
D:\Develop\npm-cache\_cacache\content-v2 存放內容
(4). package_lock.json的作用
A. 鎖定實際版本,用於【npm install】恢復的時候,下載該版本的包。
B. 記錄包本地緩存的索引,便於查找本地磁盤中的查找壓縮包,來解壓到項目中。
4. 實戰測試
場景1:只有package.json , 初始化運行【npm install】
如下,為package.json中的包對應的版本號,此時npm服務器上最新的版本分別為 0.26.1、4.17.21
"dependencies": {
"axios": "^0.26.0",
"lodash": "^4.17.20"
}
運行指令【npm install】,按照規范 y和z處的版本號都要保持最新,所以實際安裝的使 0.26.1 和 4.17.21這一版本 ,如下圖生成的package_lock.json文件中的版本號
場景2:存在lock文件,初始化運行【npm install】
如下,為package.json中的包對應的版本號,此時npm服務器上最新的版本分別為 0.26.1、4.17.21
"dependencies": {
"axios": "^0.26.0",
"lodash": "^4.17.20"
}
package_lock.json文件中的的版本號為 0.26.0 、4.17.20
"dependencies": {
"axios": {
"version": "0.26.0",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.26.0.tgz",
"integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"requires": {
"follow-redirects": "^1.14.8"
}
},
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
}
}
運行【npm install】,安裝的是lock中鎖定的版本 0.26.0、4.17.20 (通過查node_modules中下載的源碼可知)
總結:如果copy代碼給別人,只包含package.json文件,則會根據package.json文件的版本號規范,去下載符合規范的最新版本。
如果包含package.json和package_lock.json文件,且lock的中版本號符合package的規范,則安裝的使lock文件中鎖定的版本號,lock中版本是多少,下載的就是多少。
場景3:存在lock文件,但是安裝指定版本【npm install xxx@1.2.1】
無論lock中鎖定的版本是多少,都會被修改為1.2.1。
場景4:存在lock文件,安裝默認版本 【npm install xxx】
如下,package.json文件中axios的版本為 "axios": "^0.26.0", package_lock.json中的版本號為:0.26.0,服務器上最新的版本號為:0.26.1
此時運行指令【npm install axios】,結果如下:
package.json中變為: axios: ^0.26.1,lock文件中的版本號變為:0.26.1
三. npm 常用指令
詳見官方文檔:https://docs.npmjs.com/cli-documentation/cli
詳見之前的文檔:https://www.cnblogs.com/yaopengfei/p/14478126.html
四. npx工具
1. 說明
npx是npm5.2之后自帶的一個命令。npx的作用非常多,但是比較常見的是使用它來調用項目中的某個模塊的指令(node_modules文件夾中的某個包下的指令)。
2. 實操
比如:以webpack為例,全局安裝的是webpack5.1.3,項目安裝的是webpack3.6.0。
那么我在項目中的命令行運行指令 【 webpack --version】,顯示的是5.1.3, 調用的是全局的webpack,那么如何調用項目依賴的webpack呢?
方案1:
直接到node_modules下的webpack文件夾下執行這個指令,如:【./node_modules/.bin/webpack --version】
方案2:
配置package.json中的script下配置,如下,運行指令【npm run ypf】即可
"scripts": {
"ypf": "webpack --version"
},
方案3:
使用npx直接調用即可,指令為:【npx webpack --version】
五. npm發布包
1. 准備
首先需要去npm官網注冊npm賬號:https://www.npmjs.com/
2. 發布
(1). 編寫ESModule代碼
(2). 項目中運行指令 【npm login】,輸入賬號密碼進行登錄
(3). 運行指令【npm publish】進行發布
如果要更新的話,需要修改版本號,需要符合semver規范,重新運行【npm publish】進行發布。
其它指令:
刪除發布的包:【npm unpublish】
讓發布的包過期:【npm deprecate】
3. 使用
通過【npm install xxx】下載即可
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。