Skip to content

fix(package): use ESM build for browser entry - #974

Open
rbardini wants to merge 2 commits into
algolia:masterfrom
rbardini:fix/browser-esm-entry
Open

rbardini wants to merge 2 commits into
algolia:masterfrom
rbardini:fix/browser-esm-entry

Conversation

@rbardini

@rbardini rbardini commented Sep 14, 2026

Copy link
Copy Markdown

Summary

The browser field points to the CommonJS build (dist/cjs/index.js). Browser-targeting bundlers that read browser therefore resolve the CJS build, which can break default-export interop. For example, building a Storybook 11 addon with Vite/Rolldown that imports this package throws:

Uncaught TypeError: import_cjs.default is not a function

and, once the CJS build is inlined, its require('react') becomes a runtime require that fails in the browser:

Uncaught Error: Calling `require` for "react" in an environment that doesn't expose the `require` function.

Relates to rbardini/storybook-addon-playroom#88.

Change

  • Point browser at the ESM build (dist/esm/index.js).
  • Add an exports map so modern resolvers use the ESM build for import/browser and the CJS build for require, while keeping main/module/types for older tooling.
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"browser": "dist/esm/index.js",
"types": "index.d.ts",
"exports": {
  ".": {
    "types": "./index.d.ts",
    "browser": "./dist/esm/index.js",
    "import": "./dist/esm/index.js",
    "require": "./dist/cjs/index.js",
    "default": "./dist/esm/index.js"
  },
  "./package.json": "./package.json"
}

Note

Adding exports encapsulates the package: deep imports such as react-element-to-jsx-string/dist/cjs/index.js will no longer resolve. Happy to expose those subpaths if you consider them part of the public API.

Verification

Resolution checked locally with Node (no build changes needed):

  • require('react-element-to-jsx-string')dist/cjs/index.js
  • import 'react-element-to-jsx-string'dist/esm/index.js
  • import with --conditions=browserdist/esm/index.js
  • require('react-element-to-jsx-string/package.json') → resolves
  • TypeScript (moduleResolution: nodenext) resolves index.d.ts

The `browser` field pointed to the CommonJS build, so browser-targeting
bundlers resolved `dist/cjs/index.js` and could mis-handle its default
export interop (e.g. Rolldown's `import_cjs.default is not a function`).

Point `browser` at the ESM build and add an `exports` map so modern
resolvers use the ESM build for `import`/browser and the CJS build for
`require`.

Note: adding `exports` encapsulates the package, so deep imports such as
`react-element-to-jsx-string/dist/cjs/index.js` are no longer available.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity

Metric Results
Complexity 0

View in Codacy

TIP This summary will be updated as you push new changes.

@rbardini
rbardini marked this pull request as ready for review September 15, 2026 00:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants