Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESM builds output CommonJS format despite being in dist/esm #7357

Open
fgnass opened this issue Dec 23, 2024 · 0 comments · May be fixed by #7358
Open

ESM builds output CommonJS format despite being in dist/esm #7357

fgnass opened this issue Dec 23, 2024 · 0 comments · May be fixed by #7358
Labels
type: bug code to address defects in shipped code

Comments

@fgnass
Copy link

fgnass commented Dec 23, 2024

Problem

The ESM builds are outputting CommonJS code. You can see an example in decap-cms-core's ESM build which uses CommonJS-style exports despite being in the ESM directory.

Root Cause

By default, @babel/preset-env transforms ES modules to CommonJS for compatibility. This transformation needs to be explicitly disabled for ESM builds.

The issue likely went unnoticed because most users consume the main bundles through decap-cms or decap-cms-app rather than using the ESM versions of individual packages directly.

Additional Problems

While fixing the issue, I noticed that the CommonJS build fails when the ESM build was not run before and the Nx cache is empty as it tries to build decap-cms and decap-cms-app in parallel, alltough decap-cms-app depends on decap-cms.

This can be fixed by telling Nx to build the dependencies first in nx.json:

{
  "targetDefaults": {
    "build:esm": {
      "cache": true,
      "dependsOn": ["^build:esm"]
    },
    "build": {
      "cache": true,
      "dependsOn": ["^build"]
    }
  }
}

It looks as if someone tried to fix this before by importing from the ESM build directly:

import { DecapCmsApp as CMS } from 'decap-cms-app/dist/esm';

This is problematic as it bypasses the proper package entry points and makes the code fragile.

Impact

  • ESM builds aren't truly ESM, making it impossible to use modern ES module features
  • Packages advertise ESM support through the 'dist/esm' directory but don't actually provide it
  • Clean builds fail unless run through the npm script that enforces sequential execution
  • Code contains fragile imports that bypass proper package entry points

Solution

  1. Configure Babel to preserve ES modules for ESM builds by setting 'modules: false', which tells Babel to keep the original import/export syntax instead of transforming it to require/exports:
function presets() {
  return [
    ['@babel/preset-env', isESM ? { modules: false } : {}],
    ...
  ];
}
  1. Add proper build dependencies in nx.json to ensure correct build order regardless of cache state:
{
  "targetDefaults": {
    "build:esm": {
      "cache": true,
      "dependsOn": ["^build:esm"]
    },
    "build": {
      "cache": true,
      "dependsOn": ["^build"]
    }
  }
}

This ensures:

  • Proper ESM output in dist/esm
  • Correct build ordering through explicit dependencies
  • Builds work correctly with empty cache
  • No need for direct 'dist/esm' imports

I will open a PR with these changes.

@fgnass fgnass added the type: bug code to address defects in shipped code label Dec 23, 2024
@fgnass fgnass linked a pull request Dec 23, 2024 that will close this issue
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug code to address defects in shipped code
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant