最可靠判断模块格式的方式是通过 try/catch 检测 import.meta 是否存在:不报错则为 ESM,抛 ReferenceError 则为 CJS;不可用 typeof import.meta !== 'undefined' 直接判断,因未声明变量会语法报错。

不能直接用 import.meta 判断模块格式是 CJS 还是 ESM —— 它只在 ESM 中存在,CJS 环境下根本无法访问 import.meta,一用就报 ReferenceError: import.meta is not defined。所以“探测”不是靠它主动返回类型,而是利用它的**有无**作为关键信号。
核心思路:用 import.meta 的存在性反推模块类型
ESM 模块中 import.meta 始终可用(Node.js v12.2.0+ 启用 ESM 后);CJS 模块中它根本不存在。因此最可靠、最轻量的判断方式是:
- 尝试访问
import.meta,不报错 → 当前是 ESM - 访问时报
ReferenceError→ 当前是 CJS
注意:不能用 typeof import.meta !== 'undefined',因为未声明变量会直接抛错,必须用 try/catch 或 Function 构造函数绕过语法检查。
安全检测写法(推荐)
以下代码可在 .js 文件中无条件运行,兼容 CJS 和 ESM 环境:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
const isESM = (() => {
try {
// 在 Function 中执行,避免顶层语法错误
return Function('return typeof import.meta !== "undefined"')();
} catch {
return false;
}
})();
if (isESM) {
// ESM 分支:可放心使用 import.meta.url、动态 import() 等
import('./utils.mjs').then(m => m.doSomething());
} else {
// CJS 分支:用 require、__dirname、path.resolve 等
const utils = require('./utils.cjs');
utils.doSomething();
}
配合模块重写实现兼容性桥接
仅判断还不够,常需在 ESM 中模拟 CJS 的行为(如获取当前目录),或在 CJS 中提供类似 import.meta.url 的能力。典型场景:
-
替代 __dirname / __filename:ESM 中无这两个变量,但可通过
import.meta.url+fileURLToPath构造 -
路径拼接统一化:CJS 用
path.join(__dirname, 'config.json'),ESM 改为path.join(dirname(fileURLToPath(import.meta.url)), 'config.json') -
JSON 导入适配:ESM 需
import data from './data.json' assert { type: 'json' },CJS 仍用require('./data.json'),可用上述分支分别处理
构建时自动注入(适用于打包工具)
Webpack/Vite/Rollup 可在构建阶段识别入口模块类型,并注入预定义变量:
- Vite:在
vite.config.ts中配置define: { '__MODULE_TYPE__': '"esm"' },配合插件根据文件后缀自动切换值 - Rollup:用
transform钩子检测import.meta出现位置,对 CJS 入口注入 polyfill - TSC 编译:不建议依赖编译输出判断,因
type: "module"是运行时语义,TS 只做类型检查
这类方式适合统一工程规范,但运行时检测更灵活、无需构建参与。

















