本文參考:
前言
隨著前端工程的發展,npm
已然成為每個前端開發者的必備技能,然而大多數人對它的使用也只是停留在使用npm
安裝一些依賴包而已。作為全世界最大規模的包管理器,每周大約有30億次的下載量,npm
的功能遠不止安裝依賴這么簡單,本文的目的就是介紹npm
更多的功能。
tips
:本文 demo 倉庫:npm-demo
1. 安裝 npm 和管理 npm 版本
npm
是NodeJS自帶的一個包管理工具,在 NodeJS官網 安裝NodeJS
后即可使用npm
。
- 查看
npm
版本
$ npm -v
- 更新
npm
版本
$ npm install npm@latest -g
2. npm init
該命令的原理是調用腳本(init-package-json),輸出一個初始化的package.json
文件,package.json
中記錄了項目中的依賴包的信息(如名稱、版本等)。
執行npm init
每次都會輸入如上信息,可以使用npm init --yes
快速創建一個帶有默認信息的package.json
的文件。
3. 安裝依賴包
安裝依賴包是npm
的核心功能,輸入npm install
,npm
會自動從package.json
文件中尋找dependencies
,devDependencies
下的依賴包,并安裝到項目的node-modules
文件夾下。
3.1 關于 package
當手動安裝一個依賴包時,使用npm install <package>
命令即可安裝,參數package
即是要安裝的依賴包名,一般npm
會在 默認源倉庫 中去查找對應的包名。然而,package
不光是一個包名,還有更多的定義方式,參見:Understanding Packages and Modules,以下是package
定義的規則:
- 包含
package.json
文件描述該程序的文件夾
- 滿足規則(1)的
gzip
壓縮文件
- 可以下載到規則(2)資源的
url
鏈接
- 格式為
<name>@<version>
,一般是已發布在npm源倉庫
上的可訪問url
,且該url
滿足規則(3)
- 格式為
<name>@<tag>
,通過tag
標記獲取到version
,且滿足規則(4)
- 格式為
<name>
,默認添加latest
標記獲取最新發布版,且滿足規則(5)
- 滿足規則(1)的
git url
(git url 支持格式)
按照以上不同規則安裝后的package.json
文件如下:
注意:無論以何種方式安裝依賴包,
npm install
時都會去根據package.json
文件中的dependencies
字段下載它所依賴的相關包
3.2 本地包應用場景
場景模擬如下所示:
- 創建一個公共模塊
common-package-test
,存放項目中一些公共的配置或方法
- 在
src
目錄下創建一個輪播圖列表組件
- 利用
webpack
打包該文件,并進行測試
- 打開
index.html
,查看控制臺,正常輸出
通過以上場景模擬,內容可以正常輸出,但是問題在于引用路徑一直往上層尋找,這種引用很不利于項目的維護。而且公共模塊也確實需要單獨分離出來給其他模塊引用,為了更優雅的引用,可以利用npm
本地包將公共模塊封裝到node_modules
中。
解決方案:
- 在公共模塊
common-package-test
下創建一個package.json
文件
- 利用
npm
安裝本地包
- 在輪播圖組件重新引入
common-package-test
模塊
- 通過 webpack 打包進行測試
3.3 遠程 git 倉庫包應用場景
場景:使用一個npm
包時發現它有bug,也找出了它的問題,并直接在node_modules
中修復了它,這樣并沒有用。因為在.gitignore
文件一般會忽略提交node_modules
,即node_modules
不在版本控制內,即使修復了它,下次下載依賴是還是會覆蓋修復。
解決:先在git
倉庫中fork
要修復的npm
包,然后在自己的倉庫中修復該問題,最后在package.json
中引用自己的git url
即可解決問題。
4. 工作原理
-
npm2
采用的是遞歸安裝的方法,當項目較復雜時,目錄結構也會很深,會出現超出windows
系統中路徑超過260字符的錯誤;部分相同的依賴包也會被重復安裝,造成大量冗余。 -
npm3
采用扁平結構優化解決了以上問題,但也導致了npm
依賴樹不能和文件結構所對應了,可以通過npm ls
來查看模塊間的依賴關系。 -
npm5
依然采用扁平結構,還引入了package-lock.json
文件,它可以鎖定依賴的安裝結構和版本等信息。
package-lock.json
文件主要由version
,resolved
,integrity
,requires
,dependencies
幾個字段組成。
-
version
:包的準確版本號 -
resolved
:安裝源 -
integrity
:完整哈希 -
requires
:除最外層的requires
屬性為true
, 其他的requires
屬性都對應著該依賴包中的package.json
里記錄的自己的依賴項 -
dependencies
:與node_modules
文件結構有著一一對應的關系。
使用package-lock.json
的好處在于可以鎖定安裝的依賴包,在另外一臺設備上下載依賴會按照鎖定版本去下載,這樣就不會因為依賴包版本不同而導致一些意外的問題。
5. 依賴包版本管理
5.1 semver
-
npm
采用語義化版本 (semver) 規范進行版本管理。
版本格式:主版本號.次版本號.修訂號
,版本號遞增規則如下:
-
主版本號
:做了不兼容的 API 修改 -
次版本號
:做了向下兼容的功能性新增, -
修訂號
:做了向下兼容的問題修正。
-
npm
提供了網站 npm semver calculator ,可以方便地計算semver
的匹配范圍。下面列舉一些規則示例:
-
^4.1.3
:指定的主版本號下,所有更新的版本 -
~4.1.3
:指定的次版本號下,所有更新的版本 -
>4.1.3
:版本號大于4.1.3
-
<=4.3
:版本號小于等于4.3
-
3.1.0 - 4.2.1
:版本號在3.1.0
到4.2.1
之間 -
>=3.3.1 <3.8.0
:與邏輯,版本號大于等于3.3.1
且小于3.8.0
-
>4.3.1 || <=2.3.1
:或邏輯,版本號大于4.3.1
或小于等于2.3.1
-
*
:所有主版本 -
2
或2.*
或2.x
:主版本號為2
的所有版本 -
3.3
或3.3.*
或3.3.x
:版本號為3.3
開頭的所有版本 -
5.0.0-alpha
:預發布版本 -
7.0.0-beta.3
:預發布版本 -
1.0.0-rc.3
:預發布版本
5.2 依賴包管理建議
- 使用
npm5.2
以上的版本,保留package-lock.json
文件 - 不要手動修改
package-lock.json
- 升級小版本依賴包:
npm update <package>
- 升級大版本依賴包:
npm install <package>@<version>
- 降級依賴包:
npm install <package>@<version>
- 刪除依賴包:
npm uninstall <package>
- 當提交了
package.json
,package-lock.json
的更新后,應及時拉取更新,并重新npm install
重新安裝更新后的依賴
6. npm 腳本
6.1 npm scripts
- 使用
npm scripts
可以在package.json
文件中自定義腳本
{
"script": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
以上代碼片段是create-react-app
腳手架生成的React
項目中的scripts
,可以使用npm run
命令來執行上面的scripts
,執行npm run build
就等同于執行對應的npm
腳本:react-scripts build
-
npm
腳本原理
當執行npm run
命令時,會自動新建一個shell
去執行里面的腳本,shell
會將./node_modules./bin
目錄添加到PATH
變量中。也就是說,如果./node_modules./.bin
目錄中的腳本,可以直接調用腳本名,不用去寫完整的腳本路徑或是全局安裝腳本了。
- 簡寫
-
npm start
是npm run start
的簡寫 -
npm stop
是npm run stop
的簡寫 -
npm test
是npm run test
的簡寫 -
npm restart
是npm run stop && npm run restart && npm run start
的簡寫
- 變量
npm
腳本可以通過環境變量process.env
的方式獲取到運行時的相關變量:
{
"name": "webpack",
"version": "3.8.1",
"repository": {
"type": "git",
"url": "https://github.com/webpack/webpack.git"
}
}
上面的代碼片段是webpack
的package.json
文件中的部分內容,可以通過process.env
對象獲取其中的變量。
例如:process.env.npm_package_name
返回webpack
,process.env.npm_package_version
返回3.8.1
,process.env.npm_package_repository_type
返回git
6.2 npx
- 先舉個例子,在
npm5.2
版本以前,如果只是在項目中安裝了webpack
,打包的時候就需要用./node_modules./.bin/webpack
來調用webpack
命令來進行打包。調用命令時每次都要輸入這么長的路徑,會覺得很麻煩,所以一般會在全局安裝webpack
和webpack-cli
,然后直接用webpack
命令來打包,這是因為在webpack
的package.json
文件中有對bin
字段的定義:
"bin": {
"webpack": "./bin/webpack.js"
}
但是全局安裝的webpack
命令可能會與項目使用的weboack
命令版本不同,也會導致不能成功構建。上一節講到了npm scripts
,這時我們就可以將webpack
命令寫到npm scripts
中,而不需要全局安裝了,因為npm run
命令能夠在執行時把./node_modules/.bin
加入到PATH
變量中,進而直接調用webpack
命令了
在npm5.2
版本以后,npx
很方便地解決了上述問題,直接使用npx webpack
就可以去自動尋找項目中安裝好的webpack
依賴包,然后進行打包
- 執行遠程
npm
遠的二進制包
在npm5.2
版本以前,初始化React
腳手架項目,需要現在全局安裝create-react-app
,然后再創建初始化的項目:
npm install -g create-react-app
create-react-app my-app
npm5.2
版本后,直接使用npx
即可安裝并創建初始化項目,這樣也就不必全局安裝create-react-app
了,也不必去檢查全局安裝的依賴包版本是否過低:
npx create-react-app my-app
6.3 切換不同的Node
版本
在以前都是用 nvm 或 n 這樣的Node
版本管理工具來切換Node
版本,而有了npx
同樣可以在不手動切換Node
的前提下,使用不同的Node
版本環境:
7. npm 配置
7.1 npm-config
通過npm config ls -l
可以查看npm
的所有配置,詳細的配置說明可在官方文檔查看:config | npm Documentation
修改配置命令:npm config set <key> <value>
修改npm倉庫源為淘寶鏡像源:npm config set registry https://registry.npmjs.org/
7.2 .npmrc文件
上面的修改npm
配置是借助命令行來完成的,除了命令還可以通過.npmrc
文件來修改配置。
npm
讀取config
配置的優先級:
- 工程目錄下的
.npmrc
文件(/path/to/my/project/.npmrc
) - 用戶配置文件(
~/.npmrc
) - 全局配置文件(
$PREFIX/etc/npmrc
) -
npm
內置的配置文件(/path/to/npm/npmrc
)
8. 總結
- 為了統一配置,項目中的
npm config
添加到.npmrc
文件中 - 統一
node
運行環境,package.json
和package-lock.json
文件 - 合理使用安裝依賴包:
npm install <package>|<local file>|<git url>
- 使用
npm5.2
以上版本 - 合理使用
npm scripts
與npx
管理應用相關腳本
npm
的一些基礎使用和介紹先到此為止,關于更加詳細的使用和其他高級用法請看下一篇文章:npm總結(二)