【NPM】解析 npm 安裝和更新的行為

【NPM】解析 npm 安裝和更新的行為

本篇重點

  • npm install 有無指定版本的差異
  • npm install 已安裝套件再次安裝的情境
  • npm 設定檔的分工設計
  • npm 相依套件的分類
  • 語意化版本(SemVer)、符號(^、~)的實際安裝範圍
  • npm update 是一個依版本規則自動前進的更新工具
  • npm update 有無指定套件的差異
  • npm 降版本需求使用 npm install,不能使用 npm update

npm install 行為機制

有無指定版本的差異

當執行 npm i <package> 指令時,npm 會根據指令後方是否帶有版本號,決定下載策略及對設定檔的變更方式。

  • 未指定版本:預設下載該套件在 npm registry 標記為 latest 的版本(通常是最新穩定版)。安裝後,package.json 預設會在版本號前加上 ^ 符號(例如 "lodash": "^4.17.21"),表示未來允許更新至該大版本下的最新小版本。
  • 指定版本:使用 npm i <package>@<version> 指定精確版本(如 1.2.3),package.json 會移除版本符號,直接記錄該固定數值。若指定版本範圍(如 @1.x),則安裝該範圍內的最新版。
npm
1
2
3
4
5
6
7
# 未指定套件版本
npm i lodash

# 指定套件版本
npm i lodash@4.17.20
npm i lodash@4.x
npm i lodash@~4.17

已安裝套件再次安裝的情境

  • 版本一致node_modules 中的套件已完整符合 package-lock.json 描述的狀態(包含版本、來源與完整性),npm 會續用現有套件不重新下載。
  • 版本不一致(升降級):宣告版本和現有 node_modulespackage-lock.json 不同,npm 會移除舊版並安裝新版,同時更新 package-lock.json

健忘筆記

有可能出現多版本共存的狀況,這會發生在不同主套件各自依賴不同版本的同名套件。

檔案間的連動關係

npm 專案中,透過以下三部分來維持狀態同步:

  • package.json:定義專案「允許使用」的套件版本範圍。
  • package-lock.json:鎖定專案「實際安裝」的確切版本與依賴樹。
  • node_modules:存放套件原始碼的實體資料夾。

健忘筆記

通常只會修改 package.json 內容或透過 npm 指令來管理套件,不會去更動 package-lock.jsonnode_modules 的內容。

安裝過程中,npm 會根據 package-lock.json 的狀態決定執行行為。

Lock 檔不存在時: npm 依據 package.json 的版本範圍(如 ^1.0.0)向 Registry 查詢符合條件的最新版本(例如 1.5.0)。安裝後,此確切版本會被記錄在 package-lock.json,但 package.json 的宣告範圍維持不變。

Lock 檔存在時

  • 範圍一致:若 package.json 的描述與 Lock 檔記錄一致,npm 優先依照 Lock 檔進行安裝,確保環境穩定。
  • 範圍衝突:若 package.json 導致範圍與 Lock 檔不符,npm 會以 package.json 為準下載新版,再回頭更新 package-lock.json 以維持同步。

取得實際套件版本的方法

  1. 查看 package-lock.json

    直接在 package-lock.json 中搜尋套件名稱,查看 version 欄位。

    package-lock.json
    1
    2
    3
    "node_modules/some-lib": {
    "version": "1.5.0",
    }
  2. 使用 npm 指令查詢

    查詢指定套件版本,輸出會顯示目前專案中實際安裝的版本。

    npm
    1
    2
    3
    4
    5
    # 顯示巢狀依賴,輸出有時較雜
    npm list some-lib

    # 僅顯示專案直接依賴的版本
    npm list some-lib --depth=0
  3. 透過 node_modules 直接確認

    查看 node_modules/some-lib/package.json 檔案。

    package.json
    1
    2
    3
    4
    {
    "name": "some-lib",
    "version": "1.5.0"
    }

相依套件分類

dependencies vs devDependencies

在實務中,區分套件存放位置對於建置(Build)後的產品體積非常重要。

類型適用套件範例說明
dependenciesreact, lodash, axios執行環境(Production)必須具備的套件。
devDependenciestypescript, jest, eslint僅在開發、測試、建置階段需要的工具。

範例

package.json
1
2
3
4
5
6
7
8
9
10
{
"dependencies": {
"axios": "^1.13.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"eslint": "^9.39.2",
"typescript": "^5.9.3"
}
}

語意化版本

SemVer

遵循 MAJOR.MINOR.PATCH 格式,分別代表主版本號、次版本號與修補版本號。

  • MAJOR:不相容的重大變更
  • MINOR:向下相容的新功能
  • PATCH:向下相容的錯誤修正

版本符號

  • ^:允許更新不變更主版本的最新版(不更動最左側非零數字)
  • ~:允許更新修補版本(僅允許更新最右側非零數字)
符號名稱範例實際安裝範圍
Caret (^) 插入符號^1.2.3>=1.2.3<2.0.0
Tilde (~) 波浪符號~1.2.3>=1.2.3<1.3.0
Exact 精確版本1.2.3僅安裝 1.2.3
Wildcard (*) 萬用字元*接受任何版本,不建議使用

健忘筆記

特別注意 0.x.x 版本的符號行為,在語意化版本中,0.x.x 被視為不穩定階段的開發中版本,npm 會採用更保守的更新策略,MINOR 會被視為重大變更,因此升級行為有所不同。例如:^0.2.3 的實際範圍為 >=0.2.3 <0.3.0,不會升級到 0.3.0 以上的版本。

詳細的語意化版本說明可到【npm 官方文件】查看。

npm update 行為機制

依循規範自動化升級

  • 適用於將套件升級至符合 package.json 範圍內的最新版本,並同步更新 node_modulespackage-lock.json
  • 無法指定版本號進行更新,版本規則全權由 package.json 決定。

健忘筆記

如果有降版本的需求,需 使用 npm install <package>@<version> 達到目的。

有無指定套件的差異

未指定套件名稱時:

npm
1
npm update

更新所有依賴套件,只要該套件有新版本且符合版本範圍。

適合情境:

  • 例行套件維護
  • 小版本或 patch 更新
  • 專案整體升級

指定套件名稱時:

npm
1
npm update some-lib

更新指定套件和其子套件,指定套件以外的直接依賴不會變動。

適合情境:

  • 只想升級特定套件
  • 希望控制變動影響範圍

範例

package.json
1
2
3
"dependencies":{
"some-lib":"^1.2.0"
}

此設定代表允許更新至 1.x.x 的最新版本。

npm
1
npm update some-lib

npm 會自動解析可用版本,並更新:

npm
1
some-lib@1.9.3

健忘筆記

npm update 是一個「依版本規則自動前進」的更新工具,而版本的精準控制(指定或回退)必須使用 npm install 處理。

結論

npm 的核心邏輯在於提供一套可重現的依賴套件解析機制,把「版本範圍」與「確切版本」明確分離,透過 package.json 控制版本範圍、 package-lock.json 穩定專案確切版本,理解 npm 安裝和更新的實際行為,有助於解讀版本變動、維護專案、多人開發協作,降低不可預期的風險。

延伸閱讀

作者

健忘工程師

發表於

2026-01-21

更新於

2026-01-21

許可協議


你可能也想看

【NPM】常用指令速查表
【Linux】解析資料重定向
【Linux】使用 less 查看檔案

評論

複製完成