
在 ES 模块(ESM)环境下,无法像 CommonJS 那样在运行时动态 require() 不同文件,但可通过预导入 + 条件赋值的方式实现环境感知的默认导出。本文详解如何安全、清晰地按 NODE_ENV 动态选择 ./prod 或 ./dev 模块。
在 es 模块(esm)环境下,无法像 commonjs 那样在运行时动态 `require()` 不同文件,但可通过预导入 + 条件赋值的方式实现环境感知的默认导出。本文详解如何安全、清晰地按 `node_env` 动态选择 `./prod` 或 `./dev` 模块。
ES 模块的 import 语句必须是顶层静态声明,不支持 if 分支内直接 import,因此不能将 import 写在条件逻辑中。但我们可以采用“先统一导入,后运行时选择”的策略——即提前导入所有可能用到的模块,再根据环境变量决定最终导出哪一个。
以下是推荐实现方式:
// config/index.js —— 环境感知入口文件 import Production from './prod.js'; import Development from './dev.js'; const defaultExport = process.env.NODE_ENV === 'production' ? Production : Development; export default defaultExport;
✅ 优点说明:
基于三引擎设计,从微信文章、新闻和博客网页提取干净内容,支持标题作者日期元数据,多格式和批量处理。
- 完全符合 ESM 规范,无语法错误,可被 Node.js(v14.13+)、Vite、Webpack 等现代工具链正确解析;
- 所有依赖在构建/加载阶段即被识别,利于 tree-shaking(尽管实际中 prod 和 dev 通常互斥,建议确保二者导出结构一致);
- 逻辑清晰,易于测试与维护。
⚠️ 注意事项:
- ./prod.js 和 ./dev.js 必须导出相同类型与接口(例如都默认导出一个配置对象、函数或类),否则运行时可能因类型不匹配引发错误;
- 若模块含副作用(如启动服务、连接数据库),需确保仅被选中的模块执行其副作用——上述写法中,两个模块仍会在加载时执行(ESM 的模块体在首次导入时即执行)。若需真正惰性加载,应改用 dynamic import()(需异步上下文):
// ✅ 真正按需加载(适用于 Node.js 14.13+ 或浏览器)
let defaultExport;
if (process.env.NODE_ENV === 'production') {
defaultExport = (await import('./prod.js')).default;
} else {
defaultExport = (await import('./dev.js')).default;
}
export default defaultExport;
? 提示:动态 import() 返回 Promise,因此该方式要求所在模块为 type="module" 且调用处支持 await(如顶层 await,需 Node.js ≥ v14.8 并启用 --experimental-top-level-await,或封装为异步函数)。
总结:对于大多数配置类场景,推荐使用静态预导入 + 条件赋值的简洁方案;若模块初始化开销大或存在强副作用,且项目支持顶层 await,则选用 import() 动态加载更稳妥。无论哪种方式,务必保持环境分支间导出契约的一致性,以保障类型安全与运行稳定。










