NPM (Node Package Manager)

NPM 是 Node.js 默认的包管理器,也是世界上最大的软件注册表。

安装与初始化

# 检查版本
npm --version
# 或
npm -v

# 初始化项目(交互式)
npm init

# 快速初始化(使用默认值)
npm init -y

# 安装所有依赖
npm install
# 或
npm i

包安装

# 安装到 dependencies(运行时依赖)
npm install express
npm install lodash axios moment
npm i <package-name>

# 安装到 devDependencies(开发依赖)
npm install --save-dev typescript jest eslint
npm install -D @types/node @types/express
npm i -D vite

# 全局安装(命令行工具)
npm install -g nodemon typescript create-react-app
npm i -g pnpm yarn

# 安装特定版本
npm install express@4.17.1
npm install lodash@^4.17.0  # 兼容版本
npm install axios@~0.21.0   # 补丁版本

# 从 GitHub 安装
npm install git+https://github.com/user/repo.git
npm install user/repo
npm install user/repo#branch

# 从本地路径安装
npm install ./local-package
npm install /path/to/package

包卸载

# 卸载包
npm uninstall express
npm uninstall -D typescript
npm uninstall -g nodemon

# 卸载多个包
npm uninstall lodash axios moment

包更新

# 检查过时依赖
npm outdated

# 更新到符合 package.json 中版本范围的最新版本
npm update

# 更新全局包
npm update -g typescript

# 交互式升级(使用 npx)
npx npm-check-updates -u
npm install

npm scripts

{
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "build": "tsc && vite build",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src --ext .ts,.js",
    "lint:fix": "eslint src --ext .ts,.js --fix",
    "format": "prettier --write 'src/**/*.{ts,js}'",
    "clean": "rm -rf dist node_modules/.cache",
    "prebuild": "npm run clean",
    "postinstall": "npm run build",
    "deploy": "npm run build && node deploy.js"
  }
}
# 运行脚本
npm run dev
npm run build
npm test  # 特殊:不需要 run

# 传递参数
npm run test -- --watch
npm run build -- --mode production

# 生命周期脚本
npm install  # 会自动执行 preinstall -> install -> postinstall
npm publish  # 会自动执行 prepack -> prepare -> postpack

# 环境变量
NODE_ENV=production npm run build

# 跨平台环境变量(使用 cross-env)
npm install -D cross-env
cross-env NODE_ENV=production npm run build

package.json 详解

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "项目描述",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    },
    "./package.json": "./package.json"
  },
  "files": [
    "dist",
    "README.md",
    "LICENSE"
  ],
  "scripts": {
    "build": "tsc",
    "test": "jest"
  },
  "keywords": [
    "typescript",
    "library"
  ],
  "author": "张三 <zhangsan@example.com>",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/user/repo.git"
  },
  "bugs": {
    "url": "https://github.com/user/repo/issues"
  },
  "homepage": "https://github.com/user/repo#readme",
  "dependencies": {
    "express": "^4.18.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0"
  },
  "peerDependencies": {
    "react": ">=16.8.0"
  },
  "optionalDependencies": {
    "fsevents": "^2.3.0"
  },
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=8.0.0"
  },
  "os": [
    "darwin",
    "linux"
  ],
  "cpu": [
    "x64",
    "arm64"
  ],
  "private": true
}

字段说明:

  • name: 包名,发布到 npm 时必须唯一
  • version: 语义化版本号 (major.minor.patch)
  • description: 包描述,帮助他人了解包的用途
  • main: CommonJS 入口文件
  • module: ESM 入口文件(现代打包工具优先使用)
  • types: TypeScript 类型定义文件
  • type: "module" 启用 ESM,"commonjs" 使用 CJS
  • exports: 条件导出,精确控制包的入口
  • files: 发布到 npm 时包含的文件/目录
  • scripts: 可执行的命令脚本
  • keywords: 关键词,帮助他人搜索包
  • dependencies: 生产环境依赖
  • devDependencies: 开发环境依赖
  • peerDependencies: 对等依赖,要求宿主项目提供
  • optionalDependencies: 可选依赖,安装失败不报错
  • engines: 指定 Node.js 和 npm 版本要求
  • os/cpu: 指定操作系统和 CPU 架构限制
  • private: 设为 true 防止意外发布

版本语义 (SemVer)

# 版本格式:major.minor.patch (主版本.次版本.补丁)
# 例如:1.2.3

# 精确版本
"lodash": "4.17.21"

# 兼容版本(^):允许次版本和补丁版本更新
"express": "^4.18.0"  # >=4.18.0 <5.0.0

# 补丁版本(~):只允许补丁版本更新
"axios": "~1.4.0"     # >=1.4.0 <1.5.0

# 范围
"lodash": ">=4.0.0 <5.0.0"
"lodash": "4.x"       # >=4.0.0 <5.0.0
"lodash": "4.17.x"    # >=4.17.0 <4.18.0

# 特殊标签
"lodash": "latest"    # 最新版本
"lodash": "next"      # 下一个版本(可能是 beta)
"lodash": "*"         # 任何版本(危险!)

# 预发布版本
"lodash": "5.0.0-beta.1"

npm 配置

# 查看配置
npm config list
npm config list -l  # 查看所有配置

# 设置配置
npm config set registry https://registry.npmmirror.com
npm config set init-author-name "张三"
npm config set save-exact true

# 获取配置
npm config get registry

# 删除配置
npm config delete registry

# 使用 .npmrc 文件
# 项目级 .npmrc
registry=https://registry.npmmirror.com
save-exact=true

# 用户级 ~/.npmrc
//registry.npmjs.org/:_authToken=your-token-here

# 临时使用镜像
npm install --registry=https://registry.npmmirror.com

发布包

# 登录
npm login
npm whoami  # 检查当前用户

# 发布
npm publish
npm publish --tag beta  # 发布为 beta 版本
npm publish --access public  # 发布公共包(对于 scope 包)

# 取消发布(72 小时内)
npm unpublish <package>@<version>

# 废弃版本
npm deprecate <package>@<version> "此版本已废弃,请升级到新版本"

# 管理标签
npm dist-tag add <package>@<version> <tag>
npm dist-tag ls <package>
npm dist-tag rm <package> <tag>

Yarn

Yarn 是 Facebook 开发的替代包管理器,速度更快且更可靠。

安装

# 通过 npm 安装
npm install -g yarn

# 通过 Homebrew (macOS)
brew install yarn

# 通过 Corepack(Node.js 16.10+)
corepack enable
corepack prepare yarn@stable --activate

Yarn Classic (v1) vs Yarn Berry (v2+)

# 检查版本
yarn --version

# 初始化项目
yarn init
yarn init -y  # 快速初始化

# 安装依赖
yarn install
yarn  # 简写

# 添加依赖
yarn add express
yarn add -D typescript  # 开发依赖
yarn add -W typescript  # 工作区根目录添加(monorepo)

# 添加特定版本
yarn add express@^4.18.0
yarn add lodash@~4.17.0

# 升级依赖
yarn upgrade express
yarn upgrade  # 升级所有

# 移除依赖
yarn remove express

# 全局安装
yarn global add typescript
yarn global bin  # 查看全局 bin 路径

# 运行脚本
yarn dev
yarn build
yarn test

Yarn Berry (v2+) 特性

# 初始化 Berry 版本
yarn set version berry
yarn set version stable

# Plug'n'Play (PnP) 模式
# 不使用 node_modules,直接通过 .pnp.cjs 解析依赖
yarn install

# 恢复 node_modules(如果需要)
# .yarnrc.yml
nodeLinker: node-modules

# Workspaces(工作区)
# package.json
{
  "workspaces": [
    "packages/*"
  ]
}

# 在工作区中运行命令
yarn workspace package-name build
yarn workspaces foreach run build

# 延迟要求(Lazy requirements)
# yarn.lock 会记录所有依赖的解析结果

Yarn vs NPM 命令对照

功能npmyarn
初始化npm inityarn init
安装所有npm installyarn
添加依赖npm install <pkg>yarn add <pkg>
添加开发依赖npm i -D <pkg>yarn add -D <pkg>
移除依赖npm uninstall <pkg>yarn remove <pkg>
全局安装npm i -g <pkg>yarn global add <pkg>
运行脚本npm run <script>yarn <script>
更新依赖npm updateyarn upgrade
检查过时npm outdatedyarn outdated

PNPM

PNPM 是"快速、节省磁盘空间的包管理器",使用硬链接和符号链接来节省磁盘空间。

安装

# 通过 npm 安装
npm install -g pnpm

# 通过 Homebrew (macOS)
brew install pnpm

# 通过独立安装程序
curl -fsSL https://get.pnpm.io/install.sh | sh -

# Windows
Invoke-WebRequest -Uri https://get.pnpm.io/install.ps1 | Invoke-Expression

基本使用

# 初始化项目
pnpm init

# 安装依赖
pnpm install
pnpm i

# 添加依赖
pnpm add express
pnpm add -D typescript
pnpm add -g pnpm  # 全局安装

# 移除依赖
pnpm remove express
pnpm rm express

# 更新依赖
pnpm update
pnpm up

# 运行脚本
pnpm dev
pnpm build
pnpm run dev  # 也可以

# 执行命令
pnpm exec tsc  # 使用本地安装的 tsc
pnpm dlx create-react-app my-app  # 临时执行

PNPM 优势

1. 磁盘空间节省

# 查看 pnpm store 大小
pnpm store path
du -sh $(pnpm store path)

# 清理 store
pnpm store prune

2. 严格的依赖管理

// .npmrc
shamefully-hoist=false  # 不提升依赖到根目录(默认)
strict-peer-dependencies=true  # 严格的 peerDependencies 检查

3. 工作区支持(Monorepo)

// pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
# 在工作区中运行
pnpm --filter package-name build
pnpm -r build  # 递归运行所有包

# 添加依赖到特定包
pnpm --filter package-name add express

4. 性能优化

# 并行运行
pnpm -r --parallel test

# 按拓扑顺序运行
pnpm -r build

# 只运行有变化的包
pnpm -r --filter '...HEAD~1' build

PNPM vs NPM vs Yarn

特性npmyarnpnpm
安装速度中等最快
磁盘使用低(硬链接)
node_modules 结构扁平扁平严格隔离
幽灵依赖可能可能不可能
Monorepo 支持一般最好
离线缓存有(store)

Bun

Bun 是一个快速的全能 JavaScript 运行时,集 runtime、bundler、test runner、包管理器于一体。

安装

# macOS/Linux
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1|iex"

# 通过 Homebrew
brew install oven-sh/bun/bun

# 通过 npm
npm install -g bun

# 检查版本
bun --version
bun upgrade  # 更新

包管理器

Bun 的包管理器比 npm 快 25-30 倍。

# 初始化项目
bun init
bun init -y

# 安装依赖
bun install
bun i

# 添加依赖
bun add express
bun add -d typescript  # 开发依赖
bun add -g typescript  # 全局安装

# 移除依赖
bun remove express
bun rm express

# 更新依赖
bun update

# 运行脚本
bun run dev
bun dev  # 简写(bun run 可省略)
bun run build

# 执行二进制
bunx tsc  # 类似 npx
bun x create-react-app my-app

运行时特性

// 直接运行 TypeScript
bun run index.ts

// 直接运行 JSX
bun run app.tsx

// 内置 SQLite
import { Database } from "bun:sqlite";
const db = new Database("mydb.sqlite");
db.run("CREATE TABLE users (name TEXT, age INTEGER)");

// 内置文件 API
const file = Bun.file("input.txt");
const text = await file.text();
await Bun.write("output.txt", "Hello Bun!");

// 内置 HTTP 服务器
Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("Hello from Bun!");
  },
});

// 内置测试运行器
bun test

// 内置打包器
bun build ./index.ts --outdir ./dist
bun build ./index.ts --target=browser --outdir ./dist
bun build ./index.ts --target=node --outdir ./dist

// WebSocket 服务器
Bun.serve({
  fetch(req, server) {
    if (server.upgrade(req)) {
      return;
    }
    return new Response("Upgrade required", { status: 426 });
  },
  websocket: {
    message(ws, message) {
      ws.send(`Echo: ${message}`);
    },
  },
});

// 环境变量
const apiKey = process.env.API_KEY;
// 或使用 Bun 的方式
const dbUrl = Bun.env.DATABASE_URL;

// 进程退出
process.exit(0);

// 子进程
const result = Bun.spawnSync(["echo", "hello"]);
console.log(result.stdout.toString());

// 异步子进程
const proc = Bun.spawn(["bun", "--version"]);
const output = await new Response(proc.stdout).text();

性能对比

# 启动速度
time node -e "console.log('hello')"
time bun -e "console.log('hello')"

# 包安装速度
time npm install
time yarn install
time pnpm install
time bun install

# 运行速度
time node index.js
time bun index.js

兼容性

Bun 兼容大多数 Node.js API 和 npm 包:

// Node.js API 兼容
import fs from "fs/promises";
import path from "path";
import { createServer } from "http";

// npm 包兼容
import express from "express";
import React from "react";

// TypeScript 支持(无需配置)
import { User } from "./types"; // 直接导入 .ts 文件

// JSX 支持
const App = () => <div>Hello</div>;

// 路径映射
// tsconfig.json 或 jsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

何时使用 Bun

适合使用 Bun 的场景:

  • 新项目,追求极致性能
  • 需要快速启动的开发服务器
  • 简单的脚本和工具
  • 全栈应用(需要内置打包器和运行时)

谨慎使用的场景:

  • 依赖大量原生 Node.js 模块
  • 需要与旧版 Node.js 生态深度集成
  • 生产环境需要极高的稳定性保证

迁移建议:

# 1. 测试项目兼容性
bun install  # 看是否能安装所有依赖

# 2. 运行测试
bun test  # 使用 Bun 运行测试

# 3. 开发
bun dev  # 开发服务器

# 4. 构建
bun run build  # 或使用 Vite 等工具

# 5. 生产部署
# 选项 1:使用 Bun 作为运行时
bun run dist/index.js

# 选项 2:编译为 Node.js 兼容代码
bun build ./index.ts --target=node --outdir ./dist
node dist/index.js

选择建议

小型项目/快速原型

  • 推荐: Bun 或 npm
  • 理由: 简单快速,开箱即用

中型项目/团队协作

  • 推荐: PNPM 或 Yarn
  • 理由: 速度快,依赖管理严格,支持工作区

大型项目/Monorepo

  • 推荐: PNPM
  • 理由: 最佳的工作区支持,节省磁盘空间,严格的依赖隔离

企业级项目/生产环境

  • 推荐: npm 或 PNPM
  • 理由: 稳定性好,生态成熟,社区支持完善

个人项目/实验性项目

  • 推荐: Bun
  • 理由: 性能极佳,功能全面,开发体验好

最佳实践

1. 锁定版本

// package.json
{
  "engines": {
    "node": ">=18.0.0",
    "pnpm": ">=8.0.0"
  },
  "packageManager": "pnpm@8.15.0"
}

2. 使用锁文件

# 始终提交锁文件到版本控制
git add package-lock.json  # npm
git add yarn.lock          # yarn
git add pnpm-lock.yaml     # pnpm
git add bun.lockb          # bun

3. 定期更新依赖

# 检查过时依赖
npm outdated
pnpm outdated

# 自动更新(使用工具)
npx npm-check-updates -u
npx taze -u  # 更快的替代工具

4. 审计安全漏洞

# npm
npm audit
npm audit fix

# pnpm
pnpm audit

# yarn
yarn audit

5. 清理缓存

# npm
npm cache clean --force

# yarn
yarn cache clean

# pnpm
pnpm store prune

# bun
bun pm cache rm