将 CommonJS 默认导出导入为命名导出/无法加载 ES 模块

Posted

技术标签:

【中文标题】将 CommonJS 默认导出导入为命名导出/无法加载 ES 模块【英文标题】:Import CommonJS default exports as named exports / Cannot load ES module 【发布时间】:2021-08-24 05:55:27 【问题描述】:

我正在使用 TypeScript 制作一个带有 discord.js 的机器人,但在尝试运行生成的 javascript 时出现以下错误。

import  Client, FriendlyError, SQLiteProvider  from 'discord.js-commando';
                 ^^^^^^^^^^^^^
SyntaxError: Named export 'FriendlyError' not found. The requested module 'discord.js-commando' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'discord.js-commando';
const  Client, FriendlyError, SQLiteProvider  = pkg;

做完这些修改后,我得到这个错误:

internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\Eliqn\projects\He2\dist\commands\general\information.js
require() of ES modules is not supported.
require() of C:\Users\Eliqn\projects\He2\dist\commands\general\information.js from C:\Users\Eliqn\projects\He2\node_modules\require-all\index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename information.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\Users\Eliqn\projects\He2\package.json.

information.js:

export default class Information extends Command 
    /* ... */

information.js 正在与.registerCommandsIn(join(dirname(fileURLToPath(import.meta.url)), 'commands')); 一起导入。所以我尝试了两种解决方案:如果我按照消息提示删除"type": "module",我会得到SyntaxError: Cannot use import statement outside a module,如果我将扩展名更改为.cjs,它最终会加载文件,但我不明白这是为什么必要且不知道如何将特定文件输出为.cjs 而不是.js。尽管如此,该命令仍然没有正确注册。

如果有用,这是我的tsconfig.json


    "compilerOptions": 
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "module": "ES2020",
        "moduleResolution": "Node",
        "noImplicitAny": true,
        "noImplicitThis": true,
        "strictNullChecks": true,
        "outDir": "dist",
        "target": "ES2020"
    

我认为应该有更直接的方法来做到这一点,但我发现模块非常混乱。

【问题讨论】:

【参考方案1】:

您在代码中使用 ESM 是否有原因?你可以像这样配置 TypeScript 来使用 CommonJS 模块:


    "compilerOptions": 
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "module": "CommonJS", // CommonJS
        "moduleResolution": "Node",
        "noImplicitAny": true,
        "noImplicitThis": true,
        "strictNullChecks": true,
        "outDir": "dist",
        "target": "ES2020"
    

这应该可以消除错误。

【讨论】:

以上是关于将 CommonJS 默认导出导入为命名导出/无法加载 ES 模块的主要内容,如果未能解决你的问题,请参考以下文章

TipTap 和 Nuxt - 无法从非 EcmaScript 模块导入命名导出“module”

为啥导出/导入默认 ES 模块属性比命名模块属性更快?

JS模块导入导出规范-CommonJS | ES6 -规范案例

JS模块导入导出规范-CommonJS | ES6 -规范案例

CommonJS和ES6的导入导出区别

ES6 命名导出和默认导出之间的可变差异