Skip to content

dataToEsm emits a duplicate default export for a default key with includeArbitraryNames #2001

Description

@semimikoh
  • Rollup Plugin Name: @rollup/pluginutils
  • Rollup Plugin Version: 5.3.0 (and current master)
  • Rollup Version: N/A — dataToEsm is a standalone utility, no bundling involved
  • Operating System (or Browser): macOS
  • Node Version: 20+
  • Link to reproduction (⚠️ read below): self-contained snippet below (pure function, no bundler needed)

Expected Behavior

When dataToEsm is called with includeArbitraryNames: true on data that has a
key named default, it should produce valid JavaScript. Since dataToEsm always
emits a trailing export default {...}, the default key can only be exposed
through that default export object — it must not also be emitted as a named
export.

Actual Behavior

dataToEsm emits export { _arbitrary0 as "default" } in addition to the
trailing export default {...}. Both forms declare the module's default export,
so the generated code is invalid:

SyntaxError: Duplicate export of 'default'

Generated output for the reproduction below:

const _arbitrary0 = "a";
export const normal = "b";
export {
	_arbitrary0 as "default"
};
export default {
	"default": "a",
	normal: normal
};

Additional Information

Reproduction (pure function — runs in Node, no bundler required):

import { dataToEsm } from '@rollup/pluginutils';

const code = dataToEsm(
  { default: 'a', normal: 'b' },
  { namedExports: true, preferConst: true, includeArbitraryNames: true }
);

// Throws: SyntaxError: Duplicate export of 'default'
await import('data:text/javascript,' + encodeURIComponent(code));

A default key falls into the includeArbitraryNames branch and is emitted as
export { _x as "default" }. But both the string form export { x as "default" }
and the identifier form export { x as default } create the module's default
export, which conflicts with the export default {...} that dataToEsm always
appends.

This surfaced while working on Vite's CSS-modules named exports
(vitejs/vite#22393): a .default {} class name compiled
for a modern target produces broken output.

A fix (skip a default key from named exports, keeping it object-only) with a
test is ready and will be opened as a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions