You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESM模块如何实现类似CommonJS的程序化动态导出?

问题核心原因

ESM的export是静态语法关键字,不是CommonJS里那个可读写的exports对象,你写的export[group] = xxx从语法层面就不合法。
ESM规范在模块解析阶段就会确定所有导出项,不允许在循环、条件判断等运行时逻辑里动态新增命名导出;且import * as xxx拿到的模块命名空间对象是密封不可修改的,从机制上就不存在和CJS完全一致的、运行时往导出列表加属性的能力。

可落地方案

方案1:默认导出聚合对象(改动成本最低)

直接把原本要挂到exports上的内容全部挂到自定义的普通对象上,最后默认导出这个对象即可,逻辑和你原来的CJS代码几乎一致:

const cloudFunctions = {
  // 你原有的函数集合定义
}

const exportCollector: Record<string, any> = {}
let group: keyof typeof cloudFunctions;
// 逻辑和原来完全一致,只是操作自己定义的收集对象
for (group in cloudFunctions) {
  if (group != null) {
    exportCollector[group] = cloudFunctions[group];
  }
}

export default exportCollector;

如果你的循环里没有额外的过滤、转换逻辑,甚至可以直接写export default cloudFunctions,连循环操作都不需要。

导入时使用:

// 先导入默认对象,再解构拿需要的函数
import funcSet from './your-module-path.js'
const { funcA, funcB } = funcSet

这个方案适合不需要Tree Shaking、对导入写法无强制要求的场景,代码改动量最小。

方案2:构建阶段生成静态导出(适配ESM全生态)

如果你需要支持import { funcA } from 'xxx'这种命名导入写法、或者需要打包工具做Tree Shaking优化,可以在构建环节加一段简单的扫描逻辑,提前读取cloudFunctions的所有键,自动生成静态导出代码,效果和你手动逐个写导出完全一致:

// 构建阶段自动生成,不需要手动维护
export const funcA = cloudFunctions.funcA;
export const funcB = cloudFunctions.funcB;
// ... 其余所有函数对应的静态导出

这个方案没有任何运行时兼容问题,所有ESM运行环境、打包工具都能完美支持,是生产环境的推荐方案。

不推荐方案:运行时拼字符串构造动态模块

部分支持data URL导入的环境(比如Node.js)可以把动态导出逻辑拼成JS字符串,通过import()加载data URL生成临时模块实现动态命名导出,但这种方式性能差、调试困难,除非有强需求否则不建议使用。

内容的提问来源于stack exchange,提问作者Cupid Chan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:06:14