Skip to content

feat(ui): build @d2e/ui as a distributable component library - #3251

Merged
khairul-syazwan merged 2 commits into
khairul-syazwan/d2e-ui-libraryfrom
khairul-syazwan/d2e-ui-packaging
Sep 2, 2026
Merged

feat(ui): build @d2e/ui as a distributable component library#3251
khairul-syazwan merged 2 commits into
khairul-syazwan/d2e-ui-libraryfrom
khairul-syazwan/d2e-ui-packaging

Conversation

@khairul-syazwan

Copy link
Copy Markdown
Collaborator

Stack 2 of 5 for the D2E data-exploration redesign (#3116). Stacked on #3204 — review that first.

Packages @d2e/ui as a built library so the portal can share it once it moves to Vue, instead of every consumer compiling the Vue SFCs itself.

What changed

  • vite lib mode -> dist/index.js + dist/index.css, types via vue-tsc. Not the rollup/babel chain libs/portal-components uses: that is rollup 2 plus six babel packages for React/TSX, and vite handles Vue SFCs natively.
  • vue and vuetify stay external as peer dependencies.
  • Components import the Vuetify pieces they use, so a consumer no longer needs vite-plugin-vuetify.
  • Entry points move to dist. ./tokens.css stays on source — it is generated from tokens.ts and guarded by tokens:check.
  • scripts/verify-dist.mjs checks the artifact, wired into the CI step added in feat(ui): add the d2e component library and the Histoire explorer #3204.

Two things worth a reviewer's attention

Adding the Vuetify imports broke three unit tests: they imported their constant maps from the .vue files, so they began loading Vuetify's CSS under vitest's node environment. The maps moved into plain modules (buttonVariants, iconButtonSizes, statusChipVariants, explorationCardStatus), following the existing dialogSizes.ts pattern. Public API unchanged.

The obvious smoke test — importing dist in plain node — cannot work, because vuetify's ESM pulls in .css. verify:dist checks statically instead and asserts positively that vue and vuetify are still imported: when a peer gets bundled it stops appearing as an import at all, so checking only for unexpected imports misses the case that matters. Verified by dropping vuetify from external — it fails on both the missing import and a 197 kB bundle against the 150 kB ceiling.

Not in scope
The vite aliases in apps/vue-mri-ui-lib stay. The package is private and unpublished, so the ATLAS job's npm install --workspaces=false cannot resolve it from the registry regardless of a dist. The application keeps consuming source, which also preserves hot reload.

Validation
25 library tests, tokens:check, verify:dist, all three vue-mri build variants, explorer 8 stories / 30 variants, and every component re-checked in the browser with no console errors.

The portal is moving to Vue and will share these components, so the
library needs a real contract rather than a source export that every
consumer compiles itself.

- Build with vite lib mode into `dist/index.js` + `dist/index.css`, types
  via `vue-tsc`. Not the rollup/babel chain libs/portal-components uses:
  that is rollup 2 plus six babel packages for React/TSX, and vite handles
  Vue SFCs natively.
- `vue` and `vuetify` stay external as peer dependencies.
- Components now import the Vuetify pieces they use, so the package works
  without the consumer running vite-plugin-vuetify.
- Entry points move to dist; `./tokens.css` stays on source because it is
  generated from tokens.ts and guarded by tokens:check.
- `scripts/verify-dist.mjs` checks the artifact in CI.

Two things this surfaced:

Adding the Vuetify imports broke three unit tests, which imported their
constant maps from the `.vue` files and so began loading Vuetify's CSS
under vitest's node environment. Moved those maps into plain modules
(`buttonVariants`, `iconButtonSizes`, `statusChipVariants`,
`explorationCardStatus`), following the existing `dialogSizes.ts`
pattern. The public API is unchanged; tests no longer touch Vuetify.

The obvious smoke test — importing dist in plain node — cannot work,
because vuetify's ESM pulls in .css. `verify:dist` checks statically
instead, and asserts *positively* that vue and vuetify are still
imported: when a peer gets bundled it stops appearing as an import, so
looking only for unexpected imports misses the case that matters.
Verified by dropping vuetify from `external` — the check fails on both
the missing import and a 197 kB bundle against the 150 kB ceiling.

Verified: 25 lib tests, tokens:check, dist verify, all three vue-mri
build variants, explorer 8 stories / 30 variants, and every component
still renders in the browser with no console errors.
@khairul-syazwan
khairul-syazwan marked this pull request as ready for review September 2, 2026 02:15
`verify-dist.mjs` checked 13 names while `src/index.ts` exports 17 values. The
check is a subset test, so the four constant maps this branch added —
VARIANT_MAP, SIZE_MAP, STATUS_CHIP_VARIANT_MAP and ICON_BUTTON_SIZE_MAP — went
unguarded. Dropping or renaming any of them would not have failed the build.
The guard now reports 17 exports.

The README header still said the application uses the source and there is no
build step, directly above the new section on consuming the built package.
Say what is true of both: the application reads source through vite aliases,
and every other consumer uses the artifact.

Found in review of #3251.
@khairul-syazwan
khairul-syazwan merged commit 751d245 into khairul-syazwan/d2e-ui-library Sep 2, 2026
60 of 63 checks passed
@khairul-syazwan
khairul-syazwan deleted the khairul-syazwan/d2e-ui-packaging branch September 2, 2026 03:28
@khairul-syazwan

Copy link
Copy Markdown
Collaborator Author

Folded into #3204 rather than reviewed separately.

The packaging change was small — 25 files, +323/-121 — against #3204's +7448, and 8 of those files are components #3204 itself introduces. Splitting them meant a reviewer read those SFCs twice: once with the constant maps inline, then again with the maps extracted for the packaging refactor. The final state is clearer reviewed once.

The commits are unchanged and now sit on khairul-syazwan/d2e-ui-library. Nothing is lost; #3204 was fast-forwarded, not force-pushed. #3253 is retargeted onto #3204 and the stack renumbered to 4.

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