fix: ship implementation libraries as dependencies, not peers (Issue epam/ai-dial-chat#8719) - #871
Conversation
…he host `@floating-ui/react`, `classnames` and `@tabler/icons-react` were required peers, so every consuming application had to add three packages it never imports to its own package.json just to satisfy the peer graph. All three are eagerly reachable from every entry point — the root, `./grid`, `./file-manager` and `./editors` alike — so they are implementation detail of this package and now ship as `dependencies`. The editor packages go the other way. `@monaco-editor/react`, `monaco-editor` and `@uiw/react-md-editor` are reachable only behind the `Lazy*` wrappers the `./editors` subpath exports, so a consumer that never mounts an editor has no use for them. They become optional peers: `npm install` stays quiet without them, and the kit reaches for them only when a lazy editor actually mounts. `@uiw/react-markdown-preview` is dropped from the peer list outright. Nothing in this package imports it, and `@uiw/react-md-editor` already depends on it, so requiring it of the host was asking for something it could not be missing. `react` and `react-dom` are now the only required peers. Nothing changes for a consumer that keeps its current package.json — the point is that it can now delete four to six entries from it. Reported by an embedding host in epam/ai-dial-chat#8719, whose audit found 25 packages it had to declare without importing any of them. Verified with `verify:distribution`: all 10 fixtures pass end-to-end, including `consumer-markdown-editor` and `consumer-json-editor`, which install the editor packages, and `consumer-esm` and `consumer-mixed-grid-editors-subpath`, which install none of them — the latter importing from `./editors` and still building, which is what makes the optional declaration accurate rather than a required peer with its warning suppressed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Making `@monaco-editor/react`, `monaco-editor` and `@uiw/react-md-editor` optional peers stopped npm installing them here: npm auto-installs required peers but not optional ones, so a clean `npm ci` left this package without modules its own source imports. `typecheck` failed with TS2307 and the build with `[MISSING_EXPORT] "Editor" is not exported by "__vite-optional-peer-dep:@monaco-editor/react"`. They are runtime-optional for a consumer and build-required for us, which is what `devDependencies` is for — the same shape `@modelcontextprotocol/sdk` already has here. `@uiw/react-markdown-preview` joins them: two stories import its stylesheet directly, so relying on it arriving through `@uiw/react-md-editor` would be depending on a transitive. The consumer contract is unchanged — the peer declarations are exactly as the previous commit left them. `package-lock.json` is updated with them, and was missing from the previous commit: CI installs with `npm ci`, which needs the lock to match. Verified against the CI condition rather than a warm tree: `rm -rf node_modules && npm ci` installs all four, then `typecheck`, `lint:check`, `test:run` (183 files, 2493 tests), `build` and `verify:distribution` (10 fixtures, export parity, pack contents) all pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Moving This preserves automatic dependency installation while allowing the application’s bundler to deduplicate them against direct imports. |
`external` was derived exclusively from `peerDependencies`, so moving `@floating-ui/react`, `@tabler/icons-react` and `classnames` to `dependencies` silently started bundling them into the kit. A consuming application that imports the same packages directly then ships a second copy its bundler cannot deduplicate - measured on the chat application as +10,425 bytes gzipped of initial JS and 93 -> 109 initial chunks, with duplicate Tabler modules in the output. Externalize them explicitly instead: the packages stay `dependencies`, so `npm install` still brings them in without the host declaring anything, while the build leaves the import bare for the host bundler to resolve and deduplicate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Description and UI changes:
No UI changes — packaging only. No component, style or runtime behaviour is
touched.
reactandreact-domare now the only required peers of this package.An embedding host audited what it has to declare in its own
package.jsontorender a DIAL chat column and found 25 packages it never imports, several of
them ours. This is the ui kit's half of that report.
Implementation libraries the kit renders with →
dependencies@floating-ui/reactclassnames@tabler/icons-reactThese are implementation detail of this package — a host does not name them, it
just renders a
Button. Requiring them as peers meant every consumingapplication carried three entries it never imported, and a missing one only
showed up as an install warning.
Editor packages → optional peers
@monaco-editor/react,monaco-editorand@uiw/react-md-editorarereachable only behind the
Lazy*wrappers the./editorssubpath exports, so aconsumer that never mounts an editor has no use for them. As optional peers,
npm installstays quiet without them and the kit reaches for them only when alazy editor actually mounts.
They deliberately stay peers rather than becoming
dependencies: Monaco islarge, and npm cannot scope a dependency to one entry point, so making them
dependencies would push the whole editor stack into every consumer that only
wants a button.
@uiw/react-markdown-preview→ droppedNothing in this package imports it, and
@uiw/react-md-editoralready dependson it, so requiring it of the host was asking for something that could not be
missing in the first place.
What a consumer does
Nothing, unless they want to. An existing
package.jsonkeeps workingunchanged — the point is that four to six entries can now be deleted from it.
Issues:
Verification:
npm run verify:distribution— all 10 fixtures pass end-to-end, the exportsurface matches its baseline (342 exports), root/
./grid/./file-manager/./editorskeep export parity in ESM and CJS, and all 14exportstargets arepresent in the pack.
Two of those fixtures install the editor packages (
consumer-markdown-editor,consumer-json-editor) and two install none of them (consumer-esm,consumer-mixed-grid-editors-subpath) — the latter importing from./editorsand still building. That is what makes the optional declaration accurate rather
than a required peer with its warning suppressed.
Also green:
typecheck,lint:check,test:run(183 files, 2493 tests),build,format.Checklist:
(Issue #<TICKET_ID>)(comma-separated list of issues) — the issue lives inepam/ai-dial-chat, so the title carries the cross-repository reference🤖 Generated with Claude Code