Search code examples
javascriptnode.jstypescriptdiscord.jscommonjs

Import CommonJS default exports as named exports / Cannot load ES module


I'm making a bot with discord.js using TypeScript, but I get the following error when trying to run the resulting 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;

After doing those modifications, I get this error:

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 is being imported with .registerCommandsIn(join(dirname(fileURLToPath(import.meta.url)), 'commands'));. So I tried both solutions: if I remove the "type": "module" as the message suggests, I get SyntaxError: Cannot use import statement outside a module, and if I change the extension to .cjs, it finally loads the file, but I don't understand why is this necessary and don't know how to output specific files as .cjs instead of .js. And despite that, the command is still not registered correctly.

If useful, this is my tsconfig.json:

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

I think there should be a more straightforward way to do this, but I find modules very confusing.


Solution

  • Is there a reason why you use ESM in your code? You can configure TypeScript to use CommonJS modules like this:

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

    That should remove the error.