跳轉到

2010:npm 與套件管理生態#

事件#

2010年,Isaac Schlueter 建立 npm(Node Package Manager):Node.js 的官方套件管理器與 registry。2011年 npm 1.0 支援相依版本管理;此後 npm registry 成為世界上最大的軟體套件庫。

為何重要#

  • 套件管理讓生態爆發:Express(2010)、Grunt(2012)、Gulp(2013)、React(2013)、webpack(2014)、Vue(2014)等工具與框架快速累積。
  • npm 的 package.json + node_modules 模式成為 JavaScript 專案的事實標準,連前端專案(不跑 Node 程式碼)也用它管理相依。
  • 治裝文化(left-pad 事件,2016)的教訓:一個11行的套件被刪除導致全球建置失敗,暴露了極小套件與 semver 相依鏈的脆弱性,也促進了 lockfile(package-lock.json,2017)與 yarn(2016)的出現。

理論與實用原因#

  • 理論原因:模組化與組合是軟體工程的核心(Parnas 的資訊隱藏理論);npm 把「共用小模組」的邊際成本降到近零,實踐了 Unix「小工具組合」哲學。
  • 實用原因:Node.js 問世時沒有內建套件管理,開發者需要手動下載相依;npm 解決「找套件、裝套件、版本相依」三大痛點。

彌補了什麼缺陷#

彌補了 JavaScript/Node 生態「無套件管理、程式碼無法重用與版本化」的缺陷——對比 Ruby gems(2004)、Python pip(2008),npm 讓 JS 生態在十年內超越所有前輩。

相關條目#

程式範例#

1. npm 的核心:package.json#

{
  "name": "my-app",
  "version": "1.2.3",
  "dependencies": {
    "express": "^4.18.0",     // ^ = 相容 4.x(semver 語義化版本)
    "lodash": "~4.17.21"      // ~ = 相容 4.17.x
  },
  "devDependencies": {
    "jest": "^29.0.0"
  }
}
npm install express     # 裝套件並寫入 dependencies
npm install             # 依 package.json 還原整個環境

2. CommonJS 模組的重用#

// math.js —— 匯出
exports.add = function (a, b) { return a + b; };

// app.js —— 匯入(npm 裝的或本地模組都一樣)
var add = require("./math").add;
add(2, 3); // 5

3. left-pad 事件的教訓(2016):相依鏈的脆弱性#

// 被刪除的套件全部內容只有 11 行:
function leftpad(str, len, ch) {
  str = String(str);
  var i = -1;
  ch = !ch && ch !== 0 ? " " : ch;
  len = len - str.length;
  while (++i < len) str = ch + str;
  return str;
}
// 但全球無數專案 require 它——刪除後 npm install 全部失敗
// 教訓促成了 lockfile(package-lock.json)與 yarn(2016)