JavaScript Node.js 如何使用第三方模块

简介

在 Node.js(V8 引擎)中,第三方模块通过 npm(Node Package Manager) 来安装和管理。npm 是全球最大的软件注册表,包含数十万个开源包。

参考文档

  • js-nodejs-api.md — Node.js 核心模块和 CommonJS/ES Modules 基础
  • js-browser-modules.md — 浏览器中的第三方模块使用(CDN、ES Modules 等)

npm(Node Package Manager)

检查 npm 版本

npm --version
# 输出:如 9.0.0(与 Node.js 版本相关)

npm init — 初始化项目

# 交互式创建 package.json
npm init

# 使用默认值快速创建
npm init -y

npm install — 安装包

# 本地安装(项目依赖,记录在 package.json)
npm install lodash
npm install express

# 指定版本
npm install [email protected]
npm install [email protected]

# 作为开发依赖安装(只在开发时使用)
npm install --save-dev jest
npm install -D jest  # 简写

# 从 Git 仓库安装
npm install git+https://github.com/user/repo.git

# 从本地目录安装
npm install ./my-local-package

npm uninstall — 卸载包

npm uninstall lodash
npm uninstall --save-dev jest  # 卸载开发依赖

npm update — 更新包

# 更新所有包
npm update

# 更新指定包
npm update lodash

npm list — 查看已安装的包

# 查看项目依赖树
npm list

# 查看全局安装的包
npm list -g

# 只看顶层依赖
npm list --depth=0

npx — 临时执行包

# 无需全局安装,临时执行包的命令
npx create-react-app my-app
npx vite  # 启动 Vite(无需安装)

# 执行后不会留在 node_modules 中(临时使用)

package.json 详解

运行 npm init -y 会生成 package.json 文件。

基本结构

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "A Node.js project",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "jest",
    "build": "vite build"
  },
  "keywords": ["node", "express"],
  "author": "Alice",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.0",
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "jest": "^29.0.0"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

dependencies vs devDependencies

类型 说明 安装命令 使用场景
dependencies 生产依赖,项目运行时需要 npm install <pkg> Express、Lodash、Axios 等
devDependencies 开发依赖,只在开发时使用 npm install -D <pkg> Jest、Vite、ESLint 等
# 安装生产依赖(默认)
npm install express

# 安装开发依赖
npm install -D jest

# 只安装生产依赖(部署时)
npm install --production  # 或 NODE_ENV=production npm install

scripts 脚本

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "build": "vite build",
    "test": "jest",
    "test:watch": "jest --watch",
    "prestart": "echo '准备启动...'",
    "poststart": "echo '已停止'",
    "lint": "eslint src/"
  }
}
npm start          # 执行 start 脚本
npm run build       # 执行 build 脚本(非 start/test 等默认脚本需加 run)
npm run lint         # 执行 lint 脚本
npm test           # npm test 是 npm run test 的简写

语义化版本(Semantic Versioning)

版本格式:主版本.次版本.修订号(如 4.18.0

符号 含义 示例 说明
^ 兼容版本 ^4.18.0 允许更新次版本和修订号(4.x.x)
~ 近似版本 ~4.18.0 只允许更新修订号(4.18.x)
>= 大于等于 >=4.18.0 允许任何大于等于该版本的版本
* 任意版本 * 总是使用最新版本
无前缀 精确版本 4.18.0 只使用指定版本
{
  "dependencies": {
    "express": "^4.18.0",   // 可更新到 4.x.x,不更新到 5.0.0
    "lodash": "~4.17.21",  // 可更新到 4.17.x,不更新到 4.18.0
    "axios": "1.6.0"       // 精确版本,只使用 1.6.0
  }
}

package-lock.json 的作用

package-lock.json 锁定依赖的精确版本,确保团队成员和部署环境安装完全相同的依赖版本。

# package-lock.json 会自动生成和更新
# 不要手动修改它
# 提交到版本控制系统(Git)

# 根据 package-lock.json 精确安装
npm ci  # 比 npm install 更快,用于 CI/CD 环境

本地安装 vs 全局安装

本地安装(推荐)

# 本地安装(默认)
npm install express
# 包安装在 ./node_modules/ 目录
# 依赖记录在 package.json 的 dependencies 中
// 本地安装的包通过 require() 或 import 使用
const express = require('express');
// 或
import express from 'express';

全局安装

# 全局安装(-g 或 --global)
npm install -g nodemon
npm install -g pm2

# 全局安装的包可以作为命令行工具使用
nodemon index.js
pm2 start index.js
# 查看全局安装位置
npm root -g
# 输出:如 C:\Users\VanMek\AppData\Roaming\npm\node_modules

# 列出全局安装的包
npm list -g --depth=0

对比

特性 本地安装 全局安装
安装位置 ./node_modules/ 全局目录(如 ~/.npm-global/
记录在 package.json 不记录(除非手动)
用途 项目依赖(代码中使用) 命令行工具(如 nodemon、pm2)
可移植性 高(package.json 可共享) 低(其他机器可能没有)
推荐场景 绝大多数情况 命令行工具

node_modules 目录

结构

project/
├── node_modules/
│   ├── express/
│   │   ├── lib/
│   │   ├── package.json
│   │   └── ...
│   ├── lodash/
│   └── ...
├── package.json
└── index.js

查找规则

当使用 require('express') 时,Node.js 按以下顺序查找:

  1. 如果是核心模块(如 fspath),直接返回
  2. 查找当前目录的 node_modules/express
  3. 如果没找到,查找上级目录的 node_modules/express
  4. 继续向上查找,直到文件系统根目录
/project/a/b/c/
  require('express') 查找顺序:
  /project/a/b/c/node_modules/express
  /project/a/b/node_modules/express
  /project/a/node_modules/express
  /project/node_modules/express
  /node_modules/express  ← 全局(如果配置)

注意:通常将 node_modules/ 添加到 .gitignore,不提交到 Git。


CommonJS 方式引入第三方模块

基本语法

// 导入默认导出
const express = require('express');
const _ = require('lodash');

// 导入命名导出
const { debounce, throttle } = require('lodash');

// 导入子路径
const router = require('express').Router;

示例:使用 Lodash

npm install lodash
const _ = require('lodash');

// 防抖(debounce)
let debounced = _.debounce((msg) => {
  console.log('防抖:', msg);
}, 500);

// 节流(throttle)
let throttled = _.throttle((msg) => {
  console.log('节流:', msg);
}, 200);

// 数组操作
let arr = [1, 2, 2, 3, 3, 3];
console.log(_.uniq(arr));  // [1, 2, 3]

// 深拷贝
let obj = { a: { b: 1 } };
let cloned = _.cloneDeep(obj);
cloned.a.b = 2;
console.log(obj.a.b);  // 1(未被影响)

示例:使用 Express

npm install express
const express = require('express');
const app = express();

// 中间件
app.use(express.json());

// 路由
app.get('/', (req, res) => {
  res.send('Hello Express!');
});

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

app.post('/api/users', (req, res) => {
  console.log('收到数据:', req.body);
  res.status(201).json({ id: 2, ...req.body });
});

// 启动服务器
app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

ES Modules 方式引入第三方模块

配置方式

方式 1:在 package.json 中添加 "type": "module"

{
  "name": "my-project",
  "version": "1.0.0",
  "type": "module"
}

方式 2:使用 .mjs 扩展名

// app.mjs
import express from 'express';  // 默认导入
import { debounce } from 'lodash-es';  // 命名导入(需要 lodash-es 包)

示例:ESM 中使用第三方包

npm install express
npm install lodash-es  # Lodash 的 ESM 版本
// index.mjs 或 package.json 中 "type": "module"
import express from 'express';
import { debounce } from 'lodash-es';

const app = express();

app.get('/', (req, res) => {
  res.send('Hello ESM!');
});

// 使用 lodash-es
const debounced = debounce((msg) => {
  console.log(msg);
}, 500);

app.listen(3000);

CommonJS 与 ESM 互操作

// ESM 中导入 CommonJS 模块(通常可以)
import express from 'express';  // express 是 CommonJS 包,但可以导入

// CommonJS 中导入 ESM 模块(不能直接 require)
// const lodash = require('lodash-es');  // ❌ 错误!ESM 包不能用 require

// CommonJS 中可以使用动态 import(返回 Promise)
async function loadLodash() {
  const lodash = await import('lodash-es');
  console.log(lodash.debounce);
}

常用第三方库使用示例

Express — Web 框架

npm install express
npm install -D nodemon  # 开发时自动重启
{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  }
}
const express = require('express');
const app = express();

// 内置中间件
app.use(express.json());  // 解析 JSON 请求体
app.use(express.static('public'));  // 静态文件服务

// 自定义中间件
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();  // 调用 next() 继续处理
});

// 路由
app.get('/', (req, res) => {
  res.send('首页');
});

app.get('/api/users/:id', (req, res) => {
  res.json({ id: req.params.id, name: 'Alice' });
});

// 错误处理中间件(4 个参数)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('服务器错误!');
});

app.listen(3000);

Axios — HTTP 客户端

npm install axios
const axios = require('axios');

// GET 请求
axios.get('https://api.example.com/users')
  .then(res => console.log(res.data))
  .catch(err => console.error(err));

// POST 请求
axios.post('https://api.example.com/users', {
  name: 'Alice',
  age: 25
})
  .then(res => console.log('创建成功:', res.data))
  .catch(err => console.error(err));

// 使用 async/await
async function fetchData() {
  try {
    let res = await axios.get('https://api.example.com/data');
    console.log(res.data);
  } catch (err) {
    console.error('请求失败:', err.message);
  }
}

// 设置默认配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = 'Bearer token';

Day.js — 轻量级日期库

npm install dayjs
const dayjs = require('dayjs');

// 解析和格式化
console.log(dayjs().format('YYYY-MM-DD HH:mm:ss'));  // "2024-05-15 10:30:45"

// 日期运算
console.log(dayjs().add(1, 'day').format('YYYY-MM-DD'));  // 明天
console.log(dayjs().subtract(1, 'week').format('YYYY-MM-DD'));  // 上周

// 日期比较
let date1 = dayjs('2024-01-01');
let date2 = dayjs('2024-12-31');
console.log(date1.isBefore(date2));  // true
console.log(date1.isSame(date2, 'year'));  // true(同年)

// 相对时间(需要插件)
// const relativeTime = require('dayjs/plugin/relativeTime');
// dayjs.extend(relativeTime);
// console.log(dayjs('2024-05-10').fromNow());  // "5 天前"

Jest — 测试框架

npm install -D jest
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }
}
// math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
module.exports = { add, subtract };

// math.test.js
const { add, subtract } = require('./math');

test('add 函数应该正确相加', () => {
  expect(add(1, 2)).toBe(3);
  expect(add(-1, 1)).toBe(0);
});

test('subtract 函数应该正确相减', () => {
  expect(subtract(5, 3)).toBe(2);
  expect(subtract(0, 0)).toBe(0);
});
npm test  # 运行测试

Dotenv — 环境变量管理

npm install dotenv
// .env 文件
// DB_HOST=localhost
// DB_PORT=5432
// SECRET_KEY=my-secret-key

require('dotenv').config();  // 加载 .env 文件

console.log(process.env.DB_HOST);     // "localhost"
console.log(process.env.DB_PORT);     // "5432"(注意是字符串)
console.log(process.env.SECRET_KEY);  // "my-secret-key"

// 也可以指定路径
require('dotenv').config({ path: './config/.env' });

CORS — 跨域处理

npm install cors
const express = require('express');
const cors = require('cors');
const app = express();

// 启用 CORS(允许所有来源)
app.use(cors());

// 自定义 CORS 配置
app.use(cors({
  origin: 'https://example.com',  // 只允许该来源
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

// 单个路由启用 CORS
app.get('/api/data', cors(), (req, res) => {
  res.json({ msg: 'hello' });
});

创建和发布自己的包

创建包

mkdir my-package
cd my-package
npm init -y
{
  "name": "my-awesome-package",
  "version": "1.0.0",
  "description": "A awesome package",
  "main": "index.js",
  "keywords": ["utility", "helper"],
  "author": "Alice <[email protected]>",
  "license": "MIT"
}
// index.js
function myFunction() {
  return 'Hello from my package!';
}

module.exports = { myFunction };

发布到 npm

# 1. 登录 npm(首次需要注册账号 https://www.npmjs.com/)
npm login

# 2. 发布
npm publish

# 3. 更新版本后重新发布
npm version patch  # 1.0.0 → 1.0.1
npm version minor  # 1.0.0 → 1.1.0
npm version major  # 1.0.0 → 2.0.0
npm publish

.npmignore 文件

node_modules/
test/
.gitignore
*.log
.DS_Store

npm 脚本(scripts)

自定义脚本

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "build": "vite build",
    "test": "jest",
    "lint": "eslint src/",
    "clean": "rm -rf dist/",
    "predeploy": "npm run clean && npm run build",
    "deploy": "gh-pages -d dist/"
  }
}

生命周期脚本

{
  "scripts": {
    "prestart": "echo '准备启动...'",
    "start": "node index.js",
    "poststart": "echo '已停止'",
    "prebuild": "rimraf dist",
    "build": "vite build",
    "postbuild": "echo '构建完成'"
  }
}

跨平台脚本

npm install -D cross-env
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon index.js",
    "build": "cross-env NODE_ENV=production webpack"
  }
}

综合示例

示例 1:Express + Lodash + Axios 构建 API

npm init -y
npm install express lodash axios cors
npm install -D nodemon
{
  "name": "my-api",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "nodemon index.js",
    "start": "node index.js"
  },
  "dependencies": {
    "express": "^4.18.0",
    "lodash-es": "^4.17.21",
    "axios": "^1.6.0",
    "cors": "^2.8.5"
  }
}
import express from 'express';
import _ from 'lodash-es';
import axios from 'axios';
import cors from 'cors';

const app = express();
app.use(cors());
app.use(express.json());

const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 }
];

// 获取所有用户
app.get('/api/users', (req, res) => {
  res.json(users);
});

// 获取单个用户
app.get('/api/users/:id', (req, res) => {
  let user = _.find(users, { id: parseInt(req.params.id) });
  if (user) {
    res.json(user);
  } else {
    res.status(404).json({ error: '用户未找到' });
  }
});

// 代理请求外部 API
app.get('/api/external', async (req, res) => {
  try {
    let result = await axios.get('https://jsonplaceholder.typicode.com/users');
    res.json(result.data);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => {
  console.log('API 服务器运行在 http://localhost:3000');
});

示例 2:使用 npm scripts 自动化任务

{
  "scripts": {
    "clean": "rimraf dist",
    "copy:html": "cpx index.html dist/",
    "copy:css": "cpx styles.css dist/",
    "build": "npm run clean && npm run copy:html && npm run copy:css",
    "serve": "http-server dist -p 8080",
    "dev": "npm run build && npm run serve"
  }
}
npm run dev  # 构建并启动服务

示例 3:本地开发与生产环境配置(Dotenv)

npm install dotenv
# .env.development
NODE_ENV=development
API_URL=http://localhost:3000

# .env.production
NODE_ENV=production
API_URL=https://api.example.com
const express = require('express');
const app = express();

// 根据环境加载不同的 .env 文件
const env = process.env.NODE_ENV || 'development';
require('dotenv').config({ path: `.env.${env}` });

console.log('环境:', process.env.NODE_ENV);
console.log('API URL:', process.env.API_URL);

app.get('/', (req, res) => {
  res.send(`环境: ${process.env.NODE_ENV}`);
});

app.listen(3000);
# 开发环境
npm run dev

# 生产环境
NODE_ENV=production npm start

总结:Node.js 第三方模块使用速查表

操作 命令 说明
初始化项目 npm init -y 创建 package.json
本地安装 npm install <pkg> 安装到 node_modules/
开发依赖 npm install -D <pkg> 安装到 devDependencies
全局安装 npm install -g <pkg> 作为命令行工具
卸载包 npm uninstall <pkg> 从 package.json 移除
更新包 npm update <pkg> 按语义化版本更新
查看依赖 npm list --depth=0 查看顶层依赖
临时执行 npx <pkg> 无需安装,临时使用
运行脚本 npm start 执行 package.json 中的 scripts
发布包 npm publish 发布到 npm 注册表
登录 npm npm login 登录 npm 账号

重要提示:本文档介绍的是 Node.js 特有的第三方模块管理(npm)。浏览器中的第三方模块使用请参考 js-browser-modules.md