CommonJS 无原生加载拦截机制,但 Node.js 通过 require.extensions 允许注册自定义扩展处理器实现预处理;该机制仅适用于 CommonJS、对特定扩展名生效、需手动读取/编译文件,且在 Node.js v12+ 已被标记为废弃。

CommonJS 本身不提供模块加载前的拦截机制,但 Node.js 的 require.extensions API 允许你注册自定义扩展名处理器,从而在模块真正执行前介入——这是实现预处理的核心入口。
修改 require.extensions 注册钩子
Node.js 在加载文件时,会根据后缀名查找 require.extensions 中对应的处理函数。你可以覆盖或新增条目,在编译、转译、注入逻辑等环节做预处理。
- 只对特定扩展名生效(如
.ts、.jsx、.md) - 处理函数接收两个参数:
module实例和filename路径 - 你需要手动读取文件内容、做转换,再用
module._compile执行处理后的代码
典型预处理操作示例
比如为 .js 文件自动添加调试日志头:
const fs = require('fs');
const Module = require('module');
const originalHandler = Module._extensions['.js'];
Module._extensions['.js'] = function (module, filename) {
let content = fs.readFileSync(filename, 'utf8');
// 插入预处理逻辑:加一行 console.log
content = `console.log('Loaded: ${filename}');\n` + content;
module._compile(content, filename);
};
使用 require-extension-hooks 等工具封装
直接操作 require.extensions 易出错且难以维护。推荐使用成熟封装库:
立即学习“Java免费学习笔记(深入)”;
-
require-extension-hooks提供链式钩子、条件过滤、异步支持 -
ts-node就是基于此思路:劫持.ts扩展,调用 TypeScript 编译器,再交给 JS 处理器 - 可组合 Babel、ESLint、Mock 注入等多阶段处理
注意兼容性与限制
该机制仅在 CommonJS 环境下有效,且有明确约束:
- Node.js v12+ 已标记
require.extensions为废弃(DEP0145),但尚未移除,仍广泛使用 - ESM(
import)完全不走这套流程,无法拦截 - 预处理不能改变模块导出语义(如把
module.exports = {}改成export default会导致报错)


















