commonjs 的 require 不支持真正动态路径加载,但可通过条件式 require、固定前缀拼接(需白名单校验)和预加载映射表三种方式安全模拟;注意 require.cache 需手动清理才能重载模块。

CommonJS 的 require 本身不支持真正意义上的动态路径加载(比如 require(someVariable)),因为它的依赖关系必须在静态分析阶段可确定。但实际开发中,我们常需要“按需选模块”,这时可通过几种安全、可控的方式模拟动态行为,关键在于理解限制并避开陷阱。
条件式 require:最稳妥的“伪动态”写法
把 require 写在 if、switch 或三元表达式中,路径用字面量字符串(不能是拼接变量)。Node.js 允许这样写,且运行时只执行匹配分支里的 require,逻辑上实现了按条件加载。
- ✅ 支持 Node.js 原生运行,Webpack/Vite 等工具也能正确识别依赖
- ❌ 所有分支中的模块仍可能被打包工具提前引入(除非配置 tree-shaking 或使用实验性特性)
- 示例:const handler = env === 'prod' ? require('./prod-handler') : require('./dev-handler');
固定前缀 + 变量名拼接:有限但实用
路径中只让文件名部分动态,目录前缀保持字面量(如 './routes/' + name)。Node.js 运行时能执行,但要注意:Webpack 等构建工具无法推断全部可能值,可能报 warning 或打包所有匹配文件。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- ✅ 适合已知有限枚举场景,例如路由控制器、语言包(
require(`./locales/${lang}.json`)) - ❌ 不要用于用户输入或不可控变量,否则会触发路径遍历风险或运行时报错
- 建议加白名单校验:const validNames = ['user', 'order', 'payment']; if (!validNames.includes(name)) throw new Error('Invalid module');
预加载映射表:运行时真正可控的方式
提前把所有可能用到的模块 require 进内存,存进对象或 Map,后续通过 key 查找。完全规避路径解析问题,也便于单元测试和热替换。
- ✅ 模块加载时机明确,无缓存干扰;支持类型提示(TS 友好)
- ❌ 启动时多加载几个模块,略微增加初始化开销(通常可忽略)
- 示例:const controllers = { user: require('./controllers/user'), order: require('./controllers/order') }; const ctrl = controllers[name];
注意缓存与重载边界
require 加载后会永久缓存到 require.cache,即使文件内容变了也不会自动更新。若需动态重载(如配置模块、插件热更),得手动清理:
- 先用
require.resolve('./config')获取绝对路径 - 再执行
delete require.cache[resolvedPath] - 最后重新
require('./config') - ⚠️ 生产环境慎用——可能引发竞态或状态不一致
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










