Skip to content

fix(build): emit ESM bundle so consumers can tree-shake externals#767

Open
jackiejou wants to merge 1 commit into
box:masterfrom
jackiejou:esm-output
Open

fix(build): emit ESM bundle so consumers can tree-shake externals#767
jackiejou wants to merge 1 commit into
box:masterfrom
jackiejou:esm-output

Conversation

@jackiejou

Copy link
Copy Markdown
Collaborator

Summary

Switches the webpack build to emit an ES module bundle so that consumer bundlers can tree-shake the @box/* packages this library declares as externals.

Since #743 the published bundle loaded its externals via require() calls. A consuming bundler treats require("@box/blueprint-web") as opaque namespace access and marks the entire package barrel as used, so unrelated Blueprint components (Table, Calendar, GridList, and others) were retained in consumer bundles even though this library uses only two Blueprint exports.

Changes

  • scripts/webpack.config.js: emit ESM output (experiments.outputModule, output.library.type: 'module') with per-request external types:
    • @box/* and @tiptap/* packages are externalized as module, so the bundle contains named ESM imports (import { BlueprintModernizationProvider, TooltipProvider } from '@box/blueprint-web') that downstream bundlers can tree-shake.
    • react, react-dom, react-intl, and react-redux stay commonjs. With module externals webpack assumes the external is spec ESM at build time and compiles away Babel's __esModule interop from bundled CJS code (e.g. react-tether); consumers that provide a CJS-shaped react then crash on namespace.default access during module evaluation, which leaves globalThis.BoxAnnotations unassigned.
  • index.js: import the default export from dist/annotations.js directly. The bundle now has a real export default; previously the entry re-exported an undeclared identifier resolved from the global at runtime.
  • package.json: add sideEffects. ./dist/annotations.js is listed because it assigns globalThis.BoxAnnotations, which is how existing consumers access the library; without the entry a consumer bundler could prune the import.

Testing

  • tsc and eslint pass
  • All 1059 unit tests across 117 suites pass
  • Production and development webpack builds compile
  • Verified in a consuming application against a dev environment: the annotations bundle loads and evaluates, annotation creation, popup reply, delete, and resolve flows work, and the consumer build resolves Blueprint to individual module files rather than the package barrel

Notes

@jackiejou
jackiejou requested a review from a team as a code owner July 17, 2026 23:30
Switch webpack output to module format with ESM externals. The
bundle previously loaded externals via require(), which consumer
bundlers treat as opaque namespace access and retain entire
package barrels. Named imports restore tree-shaking. Add
sideEffects since dist/annotations.js assigns globalThis.
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.

1 participant