Skip to content

fix(web-components): minify tagged templates in the ESM build#36387

Open
AKnassa wants to merge 1 commit into
microsoft:masterfrom
AKnassa:fix/36298-wc-esm-template-whitespace
Open

fix(web-components): minify tagged templates in the ESM build#36387
AKnassa wants to merge 1 commit into
microsoft:masterfrom
AKnassa:fix/36298-wc-esm-template-whitespace

Conversation

@AKnassa

@AKnassa AKnassa commented Jul 10, 2026

Copy link
Copy Markdown

Previous Behavior

The ESM build (dist/esm, plain tsc output) ships html/css tagged templates with the literal newlines and indentation used in the source for readability. Those whitespace-only text nodes land in every component's shadow DOM, and when an app sets a CSS white-space value other than normal on an ancestor, they suddenly render — components like Label, Listbox and TextInput grow stray gaps and look broken.

The rollup bundles (dist/web-components*.js) never had this problem, because rollup.config.js runs rollup-plugin-fast-tagged-templates, which minifies the templates. So the two builds of the same package behaved differently.

New Behavior

The compile step now runs that exact same plugin transform over the tsc output (new scripts/minify-tagged-templates.js, called from scripts/compile.js). Both builds now ship byte-identical template content — verified quasi-by-quasi across the affected components. Sourcemaps are re-mapped (@jridgewell/remapping) so dist/esm still traces back to the TypeScript sources.

To keep the bug from coming back, scripts/verify-packaging.js (already wired into CI with dependsOn: build) now asserts that re-running the transform over every shipped dist/esm/**/*.js file is a no-op. Before this fix that check failed with 85 files; now the whole tree is a fixed point.

Verified locally:

  • All template strings in the ESM output are byte-identical to the rollup bundle versions.
  • In-browser check: a required Label under white-space: pre has zero whitespace-only text nodes and identical dimensions to white-space: normal, while the pre-fix template shows 3 stray text nodes and +19px height.
  • label/text-input/listbox Playwright specs pass in both CSR and SSR modes (170 tests), plus lint, type-check, and a clean uncached build.

Notes for reviewers:

  • Single spaces adjacent to inline elements (e.g. between the two fallback <svg>s in Option's checked indicator) are deliberately preserved by html-minifier-terser — identical to what the bundles ship today.
  • Source *.template.ts files are untouched; authoring stays readable. The dev harness (vite/storybook, served from src) is also unaffected.
  • Known adjacent gap, intentionally out of scope: the generated SSR *.template.html files still contain prettier-formatted whitespace, so declarative-shadow-DOM output is still whitespace-sensitive. Happy to file a follow-up issue for that render path if wanted.
  • @radium-v this reuses your rollup-plugin-fast-tagged-templates as-is for parity — and since the issue is assigned to you, apologies if this crosses work you already had in flight; glad to adjust or hand off.

Related Issue(s)

The ESM build (plain tsc output) shipped html/css tagged templates with
literal newlines and indentation. Those whitespace-only text nodes render
when a consumer sets a non-normal CSS white-space on an ancestor, breaking
layout (observed on Label, Listbox, TextInput). The rollup bundles never
had this problem because rollup.config.js runs
rollup-plugin-fast-tagged-templates.

Run that exact same transform over the tsc output in the compile step, so
both builds ship byte-identical template content. Sourcemaps are remapped
so dist/esm still traces back to the TypeScript sources. verify-packaging
now asserts the shipped ESM is a fixed point of the transform, keeping the
regression out for good.

Fixes microsoft#36298
@AKnassa AKnassa marked this pull request as ready for review July 10, 2026 19:02
@AKnassa AKnassa requested review from a team as code owners July 10, 2026 19:02
@radium-v

Copy link
Copy Markdown
Contributor

Hi @AKnassa, thanks for contributing. There's more to this issue than simply minifying the templates - it's a multi-part concern surrounding a few bugs. The original context for the linked issue is #36282, with #36298 and #36299 spawning off of it.

Because of these similar-looking situations, I'd rather we go through the templates and try to adjust the existing whitespace in ways that can be safely mechanically minified. One possibility is changing indentation and newlines to be within tags (between attribute boundaries) so that we can retain readability in the source, while allowing for downstream consumers to decide how they want to process their bundles. This would alleviate any formatting ambiguity in the template structure, and help us identify places where whitespace in the shadow DOM is potentially meaningful so we can account for it in the CSS.

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.

[Bug]: ESM templates contain whitespace not present in minified build

2 participants