Skip to content

模块化系统

什么是模块化系统

模块化系统是一种将代码组织成独立、可重用单元的方法。在 Node.js 中,模块化系统允许开发者将代码分割成多个文件,每个文件负责特定的功能,然后通过导入/导出机制在不同文件之间共享代码。

Node.js 模块化系统的历史

1. CommonJS 模块系统

  • Node.js 最初采用的模块系统
  • 使用 require() 导入模块
  • 使用 module.exports 导出模块
  • 同步加载模块

2. ES 模块系统

  • ECMAScript 2015 (ES6) 引入的模块系统
  • 使用 import 导入模块
  • 使用 export 导出模块
  • 异步加载模块
  • Node.js v12+ 支持

CommonJS 模块系统

导出模块

javascript
// 导出单个值
module.exports = value;

// 导出多个值
module.exports = {
  value1,
  value2,
  value3
};

// 或
exports.value1 = value1;
exports.value2 = value2;
exports.value3 = value3;

导入模块

javascript
// 导入整个模块
const module = require('./module');

// 导入特定值
const { value1, value2 } = require('./module');

// 导入内置模块
const fs = require('fs');

// 导入第三方模块
const express = require('express');

模块解析规则

  1. 如果模块路径以 ... 开头,则解析为相对路径
  2. 如果模块路径是一个文件名,则解析为该文件
  3. 如果模块路径是一个目录,则尝试加载该目录下的 index.js 文件
  4. 如果以上都失败,则在 node_modules 目录中查找

ES 模块系统

导出模块

javascript
// 导出单个值
export default value;

// 导出多个值
export const value1 = 'value1';
export const value2 = 'value2';

// 或
export {
  value1,
  value2
};

导入模块

javascript
// 导入默认值
import value from './module.js';

// 导入特定值
import { value1, value2 } from './module.js';

// 导入所有值
import * as module from './module.js';

// 导入内置模块
import fs from 'fs';

// 导入第三方模块
import express from 'express';

启用 ES 模块

  1. 将文件扩展名改为 .mjs
  2. package.json 中设置 "type": "module"

模块的缓存

  • Node.js 会缓存已加载的模块
  • 多次 require 同一个模块只会执行一次
  • 缓存可以提高性能
  • 但也可能导致状态共享的问题

模块的循环依赖

  • 当模块 A 依赖模块 B,模块 B 又依赖模块 A 时,会产生循环依赖
  • CommonJS 模块系统会返回未完成的模块导出
  • ES 模块系统会返回模块的引用

最佳实践

1. 模块设计

  • 每个模块只负责一个特定的功能
  • 模块大小适中,避免过大或过小
  • 清晰的模块接口

2. 目录结构

  • 按功能组织模块
  • 合理的文件夹结构
  • 统一的命名规范

3. 依赖管理

  • 明确的依赖关系
  • 避免循环依赖
  • 合理使用第三方模块

4. 代码风格

  • 一致的代码风格
  • 清晰的注释
  • 模块化的命名规范

工具和库

1. 模块 bundler

  • Webpack
  • Rollup
  • Parcel

2. 模块加载器

  • requireJS
  • SystemJS

3. 包管理器

  • npm
  • Yarn
  • pnpm

实践练习

  1. 创建一个使用 CommonJS 模块系统的项目
  2. 创建一个使用 ES 模块系统的项目
  3. 实现模块之间的依赖关系
  4. 处理模块的循环依赖

基于 VitePress 的本地知识库