chore(webpack): better development sourcemaps - #7147
Merged
Conversation
GiladShoham
approved these changes
Mar 14, 2023
GiladShoham
enabled auto-merge (squash)
March 14, 2023 12:04
GiladShoham
disabled auto-merge
March 14, 2023 13:15
GiladShoham
added a commit
that referenced
this pull request
Aug 18, 2026
…10628) Part 1 of #10596. Cuts the shipped `@teambit/ui` pre-bundle from **58 MB to 24 MB**, and fixes scope SSR, which turned out to have been throwing on every request for months. The workspace/scope single-compilation dedupe (~8 MB) is deliberately left for a follow-up PR — it needs an artifact-layout and `.hash` redesign, and mixing it in would make the SSR fix hard to verify. ## Size: 58 MB → 24 MB | | before | after | | --- | --- | --- | | `ui-bundle/scope/public/bit/ssr/index.js` | 37 MB | **6.8 MB** | | `ui-bundle/scope` | 50 MB | 16 MB | | `ui-bundle/workspace` | 8.2 MB | 8.2 MB | | **total** | **58 MB** | **24 MB** | Two causes, both in `rspack.ssr.config.ts`: - `devtool: 'eval-cheap-module-source-map'` wrapped every module in `eval('…')` with an inlined base64 source map — 2,566 of them, 23.4 MB, 60% of the file. It entered as `'eval-cheap-source-map', // TODO` and was later retuned in #7147 as a *development* sourcemap change; it was never a deliberate choice for a shipped artifact. Now `shouldUseSourceMap ? 'source-map' : false`, matching the browser config's opt-in. - The SSR build had no `optimization.minimizer` at all. It now mirrors the browser build's `SwcJsMinimizerRspackPlugin`. ## Scope SSR was dead, and it took three fixes Only `scope.ui-root.ts` sets `ssr: true`. The middleware catches any render error and calls `next()`, falling through to the static `index.html` — which looks completely normal in a browser. So the failure was invisible: `curl /` and `curl '/?rendering=client'` returned byte-identical 1,027-byte responses with an empty `<div id="root"></div>`. Three independent defects were stacked: 1. **`cjs` missing from the SSR asset catch-all.** The browser config excludes `/\.(cjs|js|mjs|jsx|ts|tsx)$/`; the SSR config omitted `cjs`, so every `.cjs` module was emitted as an `asset/resource` whose module value is the file's URL. A component imported from one reached React as a tag name → `Minified React error #65` = *"Invalid tag: /public/ssr/<hash>.cjs"*. Introduced by the webpack→rspack migration (#10187), which replaced a shared base config with two hand-written ones and added `cjs` to only one. 2. **`use-user-agent` present at two versions** (0.0.199 and 0.0.200). Each copy calls `createContext`, so `ui.ui.runtime.tsx` provided `ssrBrowserContext` on one instance while `Tooltip`'s `useUserAgent` read the other, got `undefined`, took the browser fallback and dereferenced `window` on the server. Fixed by adding it to `resolveAlias` — the list that exists for exactly this class of bug. Aliasing the hook fixes every consumer, so the duplicated `Tooltip` copies need no aliasing of their own. 3. **`window` in a `useEffect` dependency array** — `useCurrentUser` had `}, [window.location.href]);`. The effect *body* never runs on the server, but a dependency array is evaluated on every render, including the server one. All routes now render server-side and the log shows zero SSR failures: | route | before | after | | --- | --- | --- | | `/` | 1,027 B (fallback) | 27,178 B | | `/ui/button` | 1,027 B (fallback) | 51,726 B | | `/ui/button/~code` | 1,027 B (fallback) | 61,246 B | A visible side effect: the document title was the build-time placeholder (`bit-local-88bfe855`) and is now the actual scope name. ## Browser runtime effect This turns SSR on for the first time in months, so it is a real runtime change. Bare scope on localhost, 7 runs, median, SSR vs `?rendering=client`: | | SSR | client | delta | | --- | --- | --- | --- | | FCP, warm cache | **72 ms** | 384 ms | **−312 ms** | | FCP, cold cache | 584 ms | 376 ms | +208 ms | | TTFB | 24 ms | 2 ms | +22 ms | SSR is ~5× faster to first paint on a repeat visit, and ~200 ms slower on a cold first load where the 6.4 MB of JS dominates and the larger HTML delays stylesheet discovery. Server startup is unchanged (~1.77 s); the first request drops from 0.79 s to 0.49 s while now doing a real render instead of throwing. Note localhost has ~0 latency, which flatters client rendering — over a network SSR's margin widens. ## Testing New e2e `e2e/harmony/ui-ssr.e2e.ts` asserts on the served HTML, since a browser cannot distinguish a working SSR render from the fallback. It runs `bit start --rebuild`, which matters: `getBundleUiPath` resolves through `getAspectDirFromBvm`, so without `--rebuild` the server serves the pre-bundle from the installed bvm version and the test would assert on whatever bit release happens to be installed rather than on this code. `HttpHelper` gained an optional extra-args parameter for this. Verified the test actually catches the bug — with the `cjs` fix reverted, 2 of the 3 assertions fail. (The third, an assertion that the scope name appears anywhere in the document, passed in both states because `--rebuild` puts the scope name in the static `<title>`; it now asserts inside `#root` instead.) Manual verification on both UI roots, with the freshly built artifact swapped into the bvm install and the released `.hash` files preserved (a `.hash` mismatch makes `bit start` silently rebuild locally instead of serving the artifact). Confirmed the new bundle was genuinely served by diffing content-hashed asset names against the originals. Both roots checked in a real browser: workspace and scope home, component page, code tab, API reference — no console errors. The one error found (`componentChanged` subscription missing on a bare scope) reproduces identically on the original bundle and is pre-existing. ## Bundle analysis tooling `BIT_UI_BUNDLE_STATS=1` makes the UI build write an rspack stats file per compilation, and `scripts/analyze-bundle.mjs` (`npm run analyze-bundle`) summarizes assets plus the heaviest packages and workspace scopes. No new dependency. This is what found defect 2 above. It also surfaced that **81–86 packages appear at more than one version** in a single bundle (`@teambit/design.ui.tooltip` at eight). That is only ~0.6 MB (~3% of module bytes), so it is a React-context correctness risk rather than a size lever — worth tracking separately. ## Not in scope The six env preview pre-bundles (`@teambit/{react,node,mdx,env,aspect,readme}/artifacts/env-template`) are 37.9 MB with only 6.4 MB of unique content — 31.5 MB is byte-identical across the six. That is now the largest single remaining item, bigger than the workspace/scope dedupe, and is not covered by #10596 as written.
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.
Proposed Changes
Change sourcemaps to better quality