npm基礎回顧

概述

  • npm是什麼
  • 配置
  • npm install
  • 版本號規則
  • 安裝過程
  • package.lock.json
  • script生命週期
  • 常見問題

npm是什麼

是用nodejs寫的包管理生態系統css

  • 網站 www.npmjs.com/
  • 註冊表(npm數據庫,60W+package)
  • cli工具(命令行)

npm配置

環境變量

windows 安裝完node一般會自動設置環境變量PATHnode

NODE_PATH = XXX\Node\nodejs
PATH = %NODE_PATH%\;%NODE_PATH%\node_modules;%NODE_PATH%\node_global;
複製代碼

若是不配置呢?git

error:node不是內部或外部命令,也不是可運行的程序 或批處理文件。算法

npm配置項

查看npm配置數據庫

npm config ls 或 npm config list
複製代碼

image

上面一樣列舉了npmrc(npm用戶配置文件)的地址npm

這裏面核心的是三項json

  • 當前的用戶信息(username、email...)
  • registry - 鏡像地址,npm包的下載源(一般會修改成淘寶鏡像或者私服鏡像)
  • prefix - 全局安裝目錄

修改全局安裝目錄

npm config set prefix "F:\office_software\nodejs\xxx_global"
複製代碼

修改鏡像地址(推薦使用nrm進行多鏡像管理)

npm config set registry "https://registry.npm.taobao.org"
複製代碼

另一個配置就是npm緩存的目錄windows

$ npm config get cache
C:\Users\Administrator\AppData\Roaming\npm-cache
複製代碼

npm-cache存放下載包的緩存(對應sha1計算後的內容也在裏面)緩存

修改npm緩存目錄

npm config set cache "F:\office_software\nodejs\xxx_cache"
複製代碼

npm install

安裝操做

npm install 或 npm i

這兩個命令是同樣的,一個全寫一個簡寫bash

npm install 或 npm i
複製代碼

npm會根據package.json配置文件中的依賴配置下載安裝到項目下的node_modules目錄

-g 或 -global

npm i -g XXX
複製代碼

全局安裝,安裝後的包位於系統預設目錄下

image

這樣就安裝在了C:\Users\Administrator\AppData\Roaming\npm\node_modules目錄下

-S 或 --save

安裝的包將寫入package.json裏面的dependencies,dependencies:生產環境須要依賴的庫

好比:less和scss編譯用的包,只有開發時才用獲得,實際運行時並不用到,因此就不用放到生產環境依賴包中

-D 或 --save-dev

安裝的包將寫入packege.json裏面的devDependencies,devdependencies:只有開發環境下須要依賴的庫

安裝本地包

  • 安裝本地模塊

假如npm_pkg包已經寫好(裏面只要有個package.json就能夠),如

npm install ../npm_pkg
複製代碼

一般用來測試本地npm包

  • 將包做爲一個命令行工具(cli)
npm install ../npm_demo_cli -g
複製代碼

npm install還有不少其餘使用方式,不經常使用,就不一一介紹了。 具體請參照《官方文檔》

npm版本號規則

版本號格式

主版本號[MAJOR].次版本號[MINOR].修訂號[PATCH]

版本號遞增規則以下:

  • 主版本號:當作了不兼容的 API 修改,
  • 次版本號:當作了向下兼容的功能性新增,
  • 修訂號:當作了向下兼容的問題修正。先行版本號及版本編譯信息能夠加到「主版本號.次版本號.修訂號」的後面,做爲延伸。

當主版本號升級後,次版本號和修訂號須要重置爲0,次版本號進行升級後,修訂版本須要重置爲0。

關於測試版本後綴命名:

  • alpha:初期內測版,會有不少bug, 如:1.0.0-alpha.1。
  • beta:中期內測,但會持續加入新的功能。
  • rc:Release Candidate 系統平臺上就是發行候選版本。RC版不會再加入新的功能了,主要着重於除錯,處在beta版以後,正式版以前

semver:semantic version 語義化版本

  • 固定版本:例如 1.0.一、1.2.1-beta.0 這樣表示包的特定版本的字符串
  • 範圍版本:是對知足特定規則的版本的一種表示,例如 1.0.3-2.3.四、1.x、^0.二、>1.4

語義化說明

用到的語義化字符有: ~、>、<、=、>=、<=、-、||、x、X、*

'^2.1.1' // 2.x最新版本(主版本號鎖定)
'~2.1.1' // 2.1.x最新版本好(主和次版本號鎖定)
'>2.1'   // 高於2.1版本的最新版本
'1.0.0 - 1.2.0' // 兩個版本之間最新的版本(必需要有空格)
'*'      // 最新的版本號
'3.x'    // 對應x部分最新的版本號
複製代碼

npm install默認安裝 ^x.x.x類型的版本,用於兼容大版本下最新的版本

npm安裝過程

  • 執行工程自身preinstall

  • 肯定首層依賴模塊

    • 即:package.json中的 dependencies 和 devDependencies
  • 獲取模塊

    • 在下載一個模塊以前,首先要肯定其版本,這是由於 package.json 中每每是 semver版本
    • 此時若是版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有該模塊信息直接拿便可

    若是npm-shrinkwrap.json和package-lock.json同時存在,則以npm-shrinkwrap.json爲主,忽略另外一個

    • 若是沒有則從倉庫獲取(向registry查詢)。如 packaeg.json 中某個包的版本是 ^1.1.0,npm 就會去倉庫中獲取符合 1.x.x 形式的最新版本。
  • 獲取模塊內容

    • 上一步會獲取到模塊的壓縮包地址(resolved 字段),npm 會用此地址檢查本地緩存,緩存中有就直接拿,若是沒有則從倉庫下載
  • 查找該模塊依賴

    • 若是有依賴則回到第1步,若是沒有則中止。
  • 模塊扁平化

    • 遍歷全部節點,逐個將模塊放在根節點下面,也就是 node-modules 的第一層。當發現有重複模塊時,則將其丟棄

    • 這裏須要對重複模塊進行一個定義,它指的是模塊名相同且 semver 兼容。每一個 semver 都對應一段版本容許範圍,若是兩個模塊的版本容許範圍存在交集,那麼就能夠獲得一個兼容版本,而沒必要版本號徹底一致,這可使更多冗餘模塊在 dedupe 過程當中被去掉。

      好比

      node-modules 下 foo 模塊依賴 lodash@^1.0.0,bar 模塊依賴 lodash@^1.1.0,則 ^1.1.0 爲兼容版本。

      而當 foo 依賴 lodash@^2.0.0,bar 依賴 lodash@^1.1.0,則依據 semver 的規則,兩者不存在兼容版本。會將一個版本放在 node_modules 中,另外一個仍保留在依賴樹裏。

  • 安裝模塊

    • 這一步將會更新工程中的 node_modules,並執行模塊中的生命週期函數(按照 preinstall、install、postinstall 的順序)。
  • 執行工程自身生命週期

    • 當前 npm 工程若是定義了鉤子此時會被執行
  • 最後一步是生成或更新版本描述文件(package.json和package-lock.json),npm install 過程完成。

安裝的npm有子依賴包

若是這個npm還有其餘依賴包,會一併安裝(只會安裝dependencies部分)

devDependencies中的依賴並不會安裝

安裝的npm包中依賴了同名不一樣==小版本==的包

A@1
  |-B@1.1
  |-C@1
D@1
  |-B@1.2
E@1
  |-B@1.3
複製代碼

這個時候,由於解析的時候,B@1已經在根目錄了 那麼B@2就會成爲D@1中私有模塊,即

node_modules
  |-A@1
  |-B@1.3
  |-C@1
  |-D@1
  |-E@1
複製代碼

安裝的npm包中依賴了同名不一樣==大版本==的包

A@1
  |-B@1
  |-C@1
D@1
  |-B@2
E@1
  |-B@2
複製代碼

這個時候,由於解析的時候,B@1已經在根目錄了 那麼B@2就會成爲D@1中私有模塊,即

node_modules
  |-A@1
  |-B@1
  |-C@1
  |-D@1
    |-node_modules
       |-B@2
  |-E@1
    |-node_modules
       |-B@2
複製代碼

後面版本的npm包,即便是以前在私有目錄中安裝過,也一樣會重複安裝

那一樣版本的npm包會屢次安裝麼

package.lock.json

npm 5版本引入了package.lock.json

即在npm install以後會在根目錄下生成一個package.lock.json文件

舉個例子

{
  ...
  "babel-polyfill": {
    "version": "6.26.0",
    "resolved": "https://rcnpm.zhuanspirit.com/babel-polyfill/download/babel-polyfill-6.26.0.tgz",
    "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
    "requires": {
      "babel-runtime": "6.26.0",
      "core-js": "2.6.5",
      "regenerator-runtime": "0.10.5"
    },
    "dependencies": {
      "regenerator-runtime": {
        "version": "0.10.5",
        "resolved": "https://rcnpm.zhuanspirit.com/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz",
        "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
      }
    }
  }
}
複製代碼

結構很簡單:

  • babel-polyfill: 包名字
  • version:安裝的版本號
  • resolved:npm壓縮包下載地址
  • integrity:sha1值(一種哈希算法)按內容計算後的值
  • requires:所依賴的包信息
  • dependencies:requires的模塊中所依賴的包,且和根目錄中版本不一致的包信息

那它是作什麼用的?

鎖定安裝時包的版本號,而且能夠上傳到git

保證每一個人安裝的依賴是同樣的

爲何要生成這個文件?

由於npm install -D xxx 以後,默認版本是向後兼容的

好比:

"dependencies": {
    "core-js": "^3.2.0",
}
複製代碼

^3.2.0 即表示3.x版本中最新的版本

也就是說package.json中鎖定的實際上是大版本號,而小版本每次安裝都是取最新的。

假如說後面又發佈了3.x更高版本,那麼後面執行npm install同窗安裝的就是更高的版本了,好比3.5.0

固然,上面說的版本號規則都是所謂的「規則」,並無什麼強制校驗的措施,遵不遵照全憑自覺。因此頗有可能出現:

即便是小版本也會出現和以前版本不兼容的狀況。

因此,鎖定當前的npm包的版本號就頗有必要,package.lock.json 也就應運而生了。

那麼package.lock.json做用就是:鎖定npm包小版本號

問題:那npm install時,若是package.json和package-lock.json都存在,以哪一個爲主?

其實只有一條規則:==若是package-lock中的版本,在package.json範圍內,就以package-lock爲主,不然以package.json爲主==

好比:以core-js爲例子

1)場景一

package.json 中是 "^3.2.0", package-lock.json 中是 "3.1.0"

兼容範圍是3.2.0+版本,而3.1.0是在這範圍以外(比這小),因此安裝時以package.json的^3.2.0爲主,就會安裝3.x最新的版本(目前是3.5.0)

2)場景二

package.json 中是 "^3.1.0", package-lock.json 中是 "3.2.0"

兼容範圍是3.1.0+版本,而3.2.0正符合這個範圍,因此安裝就按照package-lock.json中指定的3.2.0版本

npm script

生命週期

node爲script指令提供了生命週期鉤子

  • preXXX - XXX命令以前以前調用
  • postXXx - XXX命令以後調用

舉個例子,好比package.json中:

"scripts": {
  "aaa": "echo \"Log: aaa specified\""
}
複製代碼

當執行下面腳本時

npm run aaa
複製代碼

實際上等價於際執行

if (preaaa) npm run preaaa
npm run aaa
if (postaaa) npm run postaaa
複製代碼

因此,進一步實驗

"scripts": {
  "aaa": "echo \"Log: aaa specified\"",
  "preaaa": "echo \"Log: preaaa specified\"",
  "postaaa": "echo \"Log: postaaa specified\" & exit 1"
}
複製代碼

結果爲:

E:\work\npm_test>npm run aaa

> npm_test@1.0.0 preaaa E:\work\npm_test
> echo "Log: preaaa specified"

"Log: preaaa specified"

> npm_test@1.0.0 aaa E:\work\npm_test
> echo "Log: aaa specified"

"Log: aaa specified"

> npm_test@1.0.0 postaaa E:\work\npm_test
> echo "Log: postaaa specified"

"Log: postaaa specified"
複製代碼

./node_modules/.bin/

npm run執行時,會把./node_modules/.bin/ 目錄添加到執行環境的 PATH 變量中

這樣,即使只在當前項目裏安裝了某個包,npm run同樣能夠調用

傳參

執行 script 腳本若是須要傳入參數,須要在命令後加 -- 標明, 如:

npm run dev -- -r main

複製代碼

將自定義參數r=main傳入dev命令中

process.env

在執行的script 腳本中,能夠直接使用process.env對象,它會返回全部和執行環境相關的信息

  • npm_lifecycle_event - 正在運行的腳本名稱
  • npm_package_ - 當前項目 package.json 中指定字段的配置值:如 npm_package_name 獲取包名
  • npm_package__ - package.json 中嵌套屬性:如:npm_package_dependencies_core_js

注:獲取屬性時,若是是帶有中劃線的屬性,須要改爲下劃線,如core-js須要改爲core_js

npm常見疑問

npm cache clean --force

刪除npm_cache下全部緩存文件

刪除後,package-lock.json文件中就找不到對應的sha1內容了,就會強制從新從服務器拉取npm包

npm cache verify

從新計算npm_cache下全部緩存文件是否與sha1值匹配,若是不匹配可能刪除

npm install發生錯誤(大招)

刪除package.lock.json文件

npm cache clean --force強制刪除緩存中的npm包

相關文章
相關標籤/搜索