fix(chat): lifecycle-guaranteed root token injection (production regression)#375
Merged
Merged
Conversation
…ession) `ensureChatRootStyles()` injects the chat lib's root CSS custom properties — `--ngaf-chat-bg`, `--ngaf-chat-surface`, `--ngaf-chat-radius-input`, `--ngaf-chat-sidenav-width-expanded`, `--ngaf-chat-font-family`, the edge-claim primitive, the data-ngaf-chat-theme attribute mappings, and reduced-motion overrides. Every host-encapsulated chat lib style references these via `var()`. It was wired as a module-evaluation side effect (auto-call at the bottom of chat-tokens.ts). The published artifact's `sideEffects` glob was `["**/chat-tokens.ts", "**/*.css"]` — the chat-tokens.ts glob matches the *source* tree (workspace TS paths in this repo) but matches nothing in the bundled `dist/libs/chat/fesm2022/ngaf-chat.mjs` artifact. When a consumer's bundler does aggressive production tree-shaking it sees no side-effect-marked files in the published package and treats the entire bundle as side-effect-free. Result: the module-eval call is dropped, the style element is never injected, and every chat surface renders without chrome — sidenav has no width, input has no border, chips have no pill background, suggestions look like plain text on the page bg. This shipped in production at https://demo.cacheplane.ai but doesn't reproduce locally (dev mode skips tree-shaking; workspace TS paths match the source glob). Verified live: manual injection of the root tokens via browser console restored every chrome element instantly. Fix: - Call `ensureChatRootStyles()` from the constructors of every top-level chat composition (`ChatComponent`, `ChatPopupComponent`, `ChatSidebarComponent`, `ChatDebugComponent`). The function is idempotent (early-returns if the style element already exists). Constructors are reachable from user code, so bundlers can't tree-shake the call. - Extend `libs/chat/package.json` `sideEffects` to also match `./fesm2022/ngaf-chat.mjs` — defense-in-depth for any consumer bundler that DOES respect the field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the chrome-less production demo: sidenav too narrow, no border on the input, suggestion chips without pill background, etc. Root cause is `ensureChatRootStyles()` being tree-shaken out of the production bundle.
Root cause (verified live + via manual style injection)
`ensureChatRootStyles()` is the function that injects `<style id="ngaf-chat-root-tokens">` into ``. That style element defines:
Every host-encapsulated chat lib style references these via `var()`. Without them, sidenav has no width, input has no border, chips have no pill background, suggestions look like plain text on the page bg.
The function is wired as a module-evaluation side effect. The published artifact's `sideEffects` glob is `["/chat-tokens.ts", "/*.css"]` — the chat-tokens.ts glob matches the source tree (workspace TS paths in this repo) but matches nothing in the bundled `dist/libs/chat/fesm2022/ngaf-chat.mjs` artifact. Production bundlers see no side-effect-marked files in the published package, treat the entire bundle as side-effect-free, and drop the call.
Manual proof: injecting the root tokens by hand via browser console at https://demo.cacheplane.ai restored every chrome element instantly.
This doesn't reproduce locally because dev mode skips tree-shaking and workspace TS paths match the source glob — which is exactly why we missed it in code review.
Fix
Lifecycle-guaranteed call. Invoke `ensureChatRootStyles()` from the constructors of every top-level chat composition: `ChatComponent`, `ChatPopupComponent`, `ChatSidebarComponent`, `ChatDebugComponent`. The function is idempotent (early-returns if the style element already exists). Constructors are reachable from user code, so bundlers can't tree-shake the call.
Defense-in-depth on the package manifest. Extend `libs/chat/package.json` `sideEffects` to also include `./fesm2022/ngaf-chat.mjs` for any consumer bundler that DOES respect the field.
Test plan
Out of scope (separate follow-up)
🤖 Generated with Claude Code