引入

把所有逻辑写在一个文件中,早期看起来简单,功能增加后却很难测试和复用。Node.js 的模块系统让文件可以明确暴露能力,也可以限制内部实现。

正文

CommonJS

CommonJS 使用 require 导入,使用 module.exportsexports 导出:

// math.js
function add(a, b) {
  return a + b;
}
 
module.exports = { add };
const { add } = require('./math');
 
console.log(add(1, 2));

ES Module

ES Module 使用 importexport。可以在 package.json 中声明:

{
  "type": "module"
}
// math.js
export function add(a, b) {
  return a + b;
}
import { add } from './math.js';

ES Module 的相对路径通常需要写明文件扩展名。一个项目应明确选择并保持一致,不要在同一套代码中随意混用两种导入方式。

内置模块和第三方模块

import path from 'node:path';
import { readFile } from 'node:fs/promises';

node: 前缀能明确表示这是 Node.js 内置模块,避免和第三方包混淆。第三方模块应通过 package.json 管理,而不是手动复制到项目目录。

模块边界

  • 一个模块围绕一个相对明确的职责组织。
  • 通过导出内容表达公共接口,不要让其他文件依赖内部变量。
  • 避免模块之间形成循环依赖。
  • 配置、业务逻辑和输入输出可以分层,便于测试。

引出

模块只是代码组织方式,真正影响运行结果的还包括异步操作和错误传播。继续学习 Nodejs异步编程 时,要特别注意 await 的作用范围和异常处理边界。