node.jsesbuild

How to generate a single file "ESM" bundle using ESBuild for Node.js?


In order to deploy my Node.js server to the serverless platform, I need to bundle the codebase into a single file. I have following constraints:

  1. The produced output should be single file.
  2. The produced output should run on Node.js runtime.
  3. The produced output should be ESM only.

This is my configuration:

export function getESBuildConfig() {
    return {
        format: 'esm',
        sourcemap: true,
        entryPoints: [MAIN_SERVER],
        bundle: true,
        platform: 'node',
        external: [
            'pino',
            'pino-pretty',
            /* Some more externally available modules */
        ],
        outfile: COMPILED_SERVER,
        color: true,
        plugins: [],
    };
}

The problem is even when using esm as a format, it is still producing Common.js bundle. I also tried changing the platform to neutral but it errors on built-in node modules like fs, vm, etc.


Solution

  • I have been there and spend months trying to find the answer. TLDR: you can have any 2 out of 3 requests you have listed. But never all 3. At least for now.

    ESM is generally ignored on NodeJS side of things, despite all the noise around it. 99% of all NodeJS projects and libraries are CJS and will stay CJS. So, every bundler claims ESM support, but ESM formatted bundles simply do not work with NodeJS if you have CJS dependencies. You can spend weeks hunting down individual import/require. So, while NodeJS fully supports ESM, you can't bundle JS code for NodeJS to run it. Unless you have 'HelloWorld' app from the bundler vendor website that bundler is 'fully tested' with.

    Practical advise: stick with CJS, as ESM is really a token option for NodeJS. I hope it will change in coming years.