本文為 Node.js 基礎,第 8 篇:
當你第一次接觸一個 JavaScript 或 Node.js 專案時,最常見的兩個檔案之一就是 package.json 和 package-lock.json。
許多人第一時間會去找 README.md 看看這個專案是幹嘛的,但有些專案可能沒有寫 README,或內容不夠清楚。
這時,理解 package.json 就變得超級重要。
什麼是 package.json?
簡單來說,package.json 是每個 Node.js 專案的核心設定檔,可以把它想像成這個專案的「身份證」或「說明書」。
它不只是 npm 安裝套件時會參考的文件,更是一個讓開發者快速了解專案架構、功能模組、執行方式的重要參考點。
以下是 package.json 所扮演的幾個關鍵角色:
- 描述專案的基本資訊:如名稱、版本、簡介等,讓你知道這是什麼專案。
- 列出專案依賴的套件(libraries):分為正式運行需要的(
dependencies)和開發過程中用的(devDependencies)。 - 定義可以執行的指令(scripts):像是啟動伺服器、測試、編譯等等,這些指令可以用
npm run一鍵執行。 - 指定程式進入點:告訴 Node.js 或其他工具,當載入這個專案時要從哪裡開始執行。
- 作為發佈與版本控制的依據:如果你要把這個專案上傳到 npm registry 或跟其他人協作,
package.json是不可或缺的。
graph LR
PKG[package.json] --> BASIC[基本資訊]
PKG --> DEPS[依賴管理]
PKG --> FILE[檔案相關]
PKG --> BUILD[建置配置]
PKG --> PUB[發布設定]
BASIC --> BASIC1[name: 套件名稱]
BASIC --> BASIC2[version: 版本號]
BASIC --> BASIC3[description: 描述]
BASIC --> BASIC4[author: 作者]
DEPS --> DEPS1[dependencies: 生產依賴]
DEPS --> DEPS2[devDependencies: 開發依賴]
DEPS --> DEPS3[peerDependencies: 對等依賴]
FILE --> FILE1[main: 主程式入口]
FILE --> FILE2[module: ES模組入口]
FILE --> FILE3[bin: 指令工具]
FILE --> FILE4[files: 發布檔案清單]
BUILD --> BUILD1[scripts: 腳本命令]
BUILD --> BUILD2[eslintConfig: 程式碼檢查]
BUILD --> BUILD3[babel: 轉譯配置]
PUB --> PUB1[private: 私有設定]
PUB --> PUB2[license: 授權方式]
PUB --> PUB3[repository: 程式倉庫]
style PKG fill:#6a6a8c,stroke:#333,stroke-width:2px,color:#fff
style BASIC fill:#5d8392,stroke:#333,color:#fff
style DEPS fill:#8c6351,stroke:#333,color:#fff
style FILE fill:#7a9251,stroke:#333,color:#fff
style BUILD fill:#7b5192,stroke:#333,color:#fff
style PUB fill:#51928c,stroke:#333,color:#fff即使沒有 README.md,你也可以從 package.json 觀察以下幾件事:
- ✅ 這個專案的用途是什麼?(看
description和套件) - 🧰 用了哪些第三方套件?(看
dependencies) - 🏁 要怎麼啟動或執行?(看
scripts裡的 start 或 dev) - 🧪 有沒有測試機制?建置流程?(看
scripts和devDependencies)
基本結構解說
以下是一份簡單的 package.json 範例,說明每個欄位的用途:
{
"name": "my-project",
"version": "1.0.0",
"description": "這是一個測試專案",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"jest": "^29.6.1"
}
}
常見欄位說明:
| 欄位名稱 | 用途說明 |
|---|---|
name | 專案名稱,通常小寫、無空格,例如 my-app。這在 npm 發佈套件時非常重要。 |
version | 專案版本,依照語意化版本規則(SemVer),例如 1.0.0 表示主版號 1。 |
description | 一段簡單的專案描述,用於辨識與說明專案功能。 |
main | 專案的進入點檔案,當其他人使用 require() 或 import 時,會預設從這裡開始讀取程式碼。 |
scripts | 預設可執行的指令集,常見如 start(啟動)、test(測試)、dev(開發模式)等。用 npm run [指令] 執行。 |
dependencies | 專案執行時所需的函式庫,例如 Web 框架、資料庫驅動等等。部署到伺服器時這些都會一併安裝。 |
devDependencies | 只在開發階段需要的套件,例如測試框架(如 Jest)、打包工具(如 Webpack)、Linter 等,這些不會在生產環境安裝。 |
補充:你可能會看到的其他欄位(選用)
| 欄位名稱 | 用途說明 |
|---|---|
keywords | 關鍵字陣列,有助於在 npm 搜尋時被找到。 |
author | 作者資訊,例如姓名與 email。 |
license | 授權條款,例如 MIT、ISC 等。 |
repository | 專案原始碼的儲存位置,通常是 GitHub 連結。 |
engines | 指定此專案相容的 Node.js 或 npm 版本,避免版本不符。 |
透過這些資訊,package.json 就像一本為你量身打造的開發說明書,不只能幫助你啟動專案,還能讓你快速了解整個開發生態與依賴架構。真正熟練這個檔案,就等於會看懂一個專案的「骨架」。
什麼是 package-lock.json?為什麼需要它?
當你執行 npm install 安裝套件時,除了會更新 node_modules/ 資料夾與 package.json(如果你安裝了新的套件),npm 還會自動產生或更新一個名為 package-lock.json 的檔案。
這個檔案不是多餘的,它非常關鍵。它的主要作用是:準確地記錄「實際安裝下來的每一個套件版本」,而不只是你在 package.json 中寫的那些主要依賴。舉個例子:
"dependencies": {
"express": "^4.18.0"
}
這段的意思是允許安裝 4.18.x 的任一版本(x 可變),只要版本相容。但如果你今天執行 npm install 時裝的是 4.18.2,那 package-lock.json 就會明確記下來:
"express": {
"version": "4.18.2",
...
}
不只這樣,它還會詳細記下 express 這個套件底下又使用了哪些其他套件,它們的版本是什麼,這一整個「依賴樹」都會被記錄下來。
graph TD
subgraph package-lock.json
A[專案根目錄 package.json]
B[依賴套件 A v1.2.0]
C[依賴套件 B v2.1.0]
D[依賴套件 C v0.5.0]
E[子依賴 D v1.0.0]
F[子依賴 E v3.2.1]
G[子依賴 F v0.8.5]
H[子依賴 G v2.0.0]
I[子依賴 H v1.1.0]
end
A --> B
A --> C
A --> D
B --> E
B --> F
C --> F
C --> G
D --> H
F --> I
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:1px
style C fill:#bbf,stroke:#333,stroke-width:1px
style D fill:#bbf,stroke:#333,stroke-width:1px
style E fill:#ddf,stroke:#333,stroke-width:1px
style F fill:#ddf,stroke:#333,stroke-width:1px
style G fill:#ddf,stroke:#333,stroke-width:1px
style H fill:#ddf,stroke:#333,stroke-width:1px
style I fill:#ddf,stroke:#333,stroke-width:1px
classDef locked stroke-dasharray: 5 5
class A,B,C,D,E,F,G,H,I locked在這個圖中:
- 專案根目錄 (粉紅色節點) 是你的主要
package.json定義的專案 - 直接依賴 (淺藍色節點) 是專案中直接安裝的套件 (A、B、C)
- 間接依賴/子依賴 (更淺藍色節點) 是由直接依賴引入的套件 (D、E、F、G、H)
圖中的虛線表示所有這些依賴都在 package-lock.json 中被「鎖定」到特定版本,這是 package-lock.json 的核心功能:
- 它確保每個套件的確切版本都被記錄
- 它記錄完整的依賴樹結構
- 它保證團隊中每個人和部署環境都使用完全相同的依賴版本
- 它避免了「我的電腦上可以運行」的問題
當你執行 npm install 時,npm 會優先使用 package-lock.json 來安裝確切的套件版本,而不是根據 package.json 中的版本範圍重新解析依賴,這樣就能確保環境的一致性。
為什麼這很重要?不能只有 package.json 嗎?
✅ 1. 確保所有人安裝的版本「完全一致」
在多人開發的環境中,如果只有 package.json 而沒有 package-lock.json,每個人執行 npm install 可能會安裝到不同的子套件版本,因為 "^" 或 "~" 這些符號會讓 npm 去抓「相容的最新版本」。
這會導致一個常見的問題:
- A 在他的電腦上開發一切正常
- B 在另一台電腦上跑卻報錯、功能壞掉
- 為什麼?因為套件版本不一樣
而有了 package-lock.json,npm 就會完全依照這份檔案來安裝所有套件,包括主套件與其所有依賴套件的版本,確保 A、B、C 三個開發者裝到的版本 100% 一致。
✅ 2. 安裝速度更快(npm 不用重新演算版本)
當 package-lock.json 存在時,npm 不需要花時間去查詢「哪些版本可用」、「怎樣組合才相容」等問題,因為所有依賴的版本組合都已經被記錄下來。
這樣安裝過程就能跳過一大段計算與決策,加快速度。
✅ 3. 專案更容易除錯與回溯
如果某次更新套件後出現 bug,只要你有保留舊的 package-lock.json,就能準確回到原本的狀態,完全重建當時的環境,這對於找出問題、進行版本比對非常有幫助。
它不該被手動編輯
是的,package-lock.json 是由系統自動生成與維護的,開發者通常不需要(也不建議)手動修改它。
你唯一需要注意的事情是:
- ✅ 確保它被加入版本控制(如 Git)
很多新手會把它漏掉,或者錯誤地加入.gitignore裡,這樣其他開發者就會安裝出不一樣的環境,產生「你跑得動我跑不動」的經典災難。 - 🚫 不要隨意刪除或修改內容
如果你發現 lock file 跟實際安裝的有衝突,最常見的做法是刪除整個node_modules/與package-lock.json,再重新跑一次npm install,讓 npm 幫你生成乾淨的版本。
rm -rf node_modules package-lock.json
npm install統整
| 功能 | 說明 |
|---|---|
| 精準版本記錄 | 記錄實際安裝的每個套件版本與完整依賴樹 |
| 保證一致性 | 所有人執行 npm install 時都會安裝到一樣的版本 |
| 加速安裝流程 | 省去重新解析依賴的時間 |
| 回溯與除錯方便 | 出錯時可還原到特定版本組合 |
與 npm ci 搭配 | 確保 CI/CD 安裝環境完全一致 |
記得一句話:package.json 告訴 npm「我要什麼」,package-lock.json 記錄「我實際上拿到了什麼」。兩者缺一不可,合作無間!
如何從 package.json 看懂專案?
當你拿到一個陌生專案,裡面沒有寫 README,或內容太陽春,最直接的方式就是:打開 package.json。
這個檔案就像專案的說明書,藏著大量能幫助你快速上手的線索。
我們可以從三個地方著手:
看 scripts:快速知道怎麼啟動專案、執行開發任務
在 package.json 中,scripts 區塊定義了這個專案能執行的自訂指令。
這些指令通常會對應開發者日常常做的動作,例如啟動伺服器、打包前端資源、執行測試、格式化程式碼等等。
範例如下:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest",
"build": "vite build",
"lint": "eslint ."
}
常見指令說明:
| 指令 | 說明 |
|---|---|
npm start | 啟動主程式,一般用於正式執行或本地伺服器啟動 |
npm run dev | 啟動開發模式,通常具備熱重載、自動重編譯等功能 |
npm test | 執行測試,通常搭配 Jest、Mocha 等測試框架 |
npm run build | 編譯或打包程式碼,常見於前端專案 |
npm run lint | 進行程式碼格式檢查或自動修正問題 |
💡 小提醒:
start是唯一一個可以省略run的指令,其他都需要寫npm run xxx。
▶️ 怎麼用?
你可以直接打開終端機,在專案根目錄輸入其中一個指令:
npm start看看有沒有什麼畫面跑出來?伺服器有沒有啟動?有報錯嗎?
這種「實際下指令、觀察結果」的方式,比看說明文件更直覺有效!
看 dependencies 和 devDependencies:判斷這個專案用了哪些技術
這兩個區塊是 package.json 裡最關鍵的部分之一,裡面列出這個專案使用到的所有 npm 套件。
dependencies:專案正式執行時需要的套件devDependencies:開發階段才會用到的工具,如測試、打包器、Linter 等
透過這兩區的內容,我們可以快速判斷這個專案:
🔍 是前端還是後端?
- 有
react、vite、vue、webpack→ 大多是前端專案 - 有
express、koa、mongoose→ 多半是後端 API 或伺服器 - 有
next、nuxt→ 屬於全端框架(Full Stack / SSR)
🧱 使用了哪些框架?
以下是一些常見框架與對應推測:
| 套件 | 可能用途 |
|---|---|
react | 前端 UI 框架 |
vue | 前端 UI 框架 |
next | React + SSR 全端框架 |
nestjs | 後端 TypeScript 架構化框架 |
express | 傳統後端 REST API 框架 |
vite | 前端開發伺服器與打包工具 |
svelte | 現代輕量前端框架 |
🧪 有沒有在做測試?
看 devDependencies 裡是否出現以下常見測試工具:
| 套件 | 說明 |
|---|---|
jest | 最常見的 JavaScript 單元測試框架 |
mocha | 彈性強、輕量的測試框架 |
vitest | Vite 的原生測試工具,速度快、與前端整合佳 |
@testing-library/react | 專為 React 組件設計的測試套件 |
⚠️ 小技巧
你可以用這個指令快速列出套件:
npm list --depth=0這會印出目前安裝的所有套件(不含子依賴),方便你檢查有哪些工具被使用。
看 main:從哪裡開始閱讀程式碼?
在 package.json 裡,main 欄位會指出這個專案的「進入點」,也就是 Node.js 執行時會先讀的主檔案。例如:
"main": "index.js"這表示專案執行時會從 index.js 開始跑。這個檔案通常是程式邏輯的起點,例如建立伺服器、初始化設定、引入主模組等。
📌 小提醒:如果這是套件型專案(比如你開發 npm 套件),那
main也決定了別人引用你這個套件時會讀到哪個檔案。
常見問題與錯誤解析
問題:安裝後專案跑不起來?
可能原因:
- 沒有跑
npm install - 忘記用正確的指令啟動(
npm startvsnpm run dev) - 套件版本衝突,試試
rm -rf node_modules && npm install
問題:套件安裝出錯?
可能原因:
node版本太舊package-lock.json記錄的版本和系統衝突- 用的是
yarn卻只有package-lock.json(應該用npm)
問題:明明寫著 ^1.2.3,為什麼裝的是 1.2.5?
因為 ^ 符號允許安裝「相容的較新版本」。如果你不希望這樣,可以手動指定版本,例如 "1.2.3",或使用 npm ci 根據 package-lock.json 安裝。
結語:讓 package.json 成為你的好幫手
雖然很多初學者會把 package.json 當作 npm 自動生成的「背景設定檔」,但其實它就是整個專案的說明書,只是格式是 JSON 而已。
掌握它,你就可以:
- 不靠 README 也能搞懂專案
- 解決環境出錯的問題
- 更快上手別人的代碼
下一次 clone 一個新專案時,先打開 package.json 看一眼吧,它比你想像中有用!