场景
node 环境下有这么一段代码
import path from "path"
// ...
const yamlPath = path.join(process.cwd(), `./config/.${environment}.yaml`)
代码中通过 path.join() 拼接路径,运行后报错: TypeError: Cannot read properties of undefined (reading 'join') 。
解决方案
- TS 配置中设置
esModuleInterop字段为true。 - 将
import path from path修改为import * as path from。
问题产生原因
import xxx from xxx 属于 ESM 的默认导入语法,对应的导出是默认导出(export default);而 nodejs 的内置模块属于 CommonJS,没有默认导出,所以导致报错。
TS 配置中设置 esModuleInterop 字段为 true 的原理
启用 esModuleInterop 后,会有一个包装函数 __importDefault 将 CommonJS 包装成兼容 ESM 的默认导出。
编译后的代码类似: const path = __importDefault(require('path')).default这样就拥有了 default 属性。
import * as path from 的原理
import * as path from path 属于命名空间导入,将模块的所有导出绑定到一个命名空间对象上,也就可以通过该命名空间对象访问导出的属性和方法了。
对于 ESM 模块,如果它有默认导出
export default时,通过命名空间导入时,默认导出会绑定到[[命名空间]].default属性上。
适用场景
- 导入一个没有显式声明为 ESM 的模块时,这种方式最为安全。
- ESM 中只有命名导出,没有默认导出,可以方便将所有命名导出一次性导入。
import path from node:path 的作用
这种写法是 nodejs 14.13.0+ 引入的。
这种方式显式指明引入的是 nodejs 的核心模块,限定模块来源,避免与同名第三方模块冲突。