Skip to content

lighthouse: tree-shake bundled libs and ship only used Radix color scales#6563

Open
FarhanAliRaza wants to merge 2 commits into
reflex-dev:mainfrom
FarhanAliRaza:lighthouse-pr4-pr5
Open

lighthouse: tree-shake bundled libs and ship only used Radix color scales#6563
FarhanAliRaza wants to merge 2 commits into
reflex-dev:mainfrom
FarhanAliRaza:lighthouse-pr4-pr5

Conversation

@FarhanAliRaza
Copy link
Copy Markdown
Contributor

@FarhanAliRaza FarhanAliRaza commented May 25, 2026

Replace the blanket import * as of every bundled library with per-library named imports collected from the app's actual static usage (plus tags captured during dynamic-component serialization), so Rolldown can drop unused exports. Keep star imports for internal $/utils/* modules, react/@emotion/react, and any tag set that isn't a valid JS identifier.

Plumb theme_roots through the Radix Themes plugin and the Tailwind v3/v4 root style so only the Radix CSS token files for accent/gray colors referenced by Theme components are emitted, with the monolithic stylesheet retained as a fallback for state-driven or unrecognized colors.

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

New Feature Submission:

  • Does your submission pass the tests?
  • Have you linted your code locally prior to submission?

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

fixes ENG-9323
image

Replace the blanket `import * as` of every bundled library with per-library
named imports collected from the app's actual static usage (plus tags
captured during dynamic-component serialization), so Rolldown can drop
unused exports. Keep star imports for internal `$/utils/*` modules,
`react`/`@emotion/react`, and any tag set that isn't a valid JS identifier.

Plumb `theme_roots` through the Radix Themes plugin and the Tailwind v3/v4
root style so only the Radix CSS token files for accent/gray colors
referenced by `Theme` components are emitted, with the monolithic
stylesheet retained as a fallback for state-driven or unrecognized colors.
@FarhanAliRaza FarhanAliRaza requested a review from a team as a code owner May 25, 2026 19:48
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 25, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing FarhanAliRaza:lighthouse-pr4-pr5 (b485c49) with main (dc8a23c)

Open in CodSpeed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR optimizes the frontend bundle by (1) replacing blanket import * as of every bundled library with named imports derived from each app's actual static usage (so Rolldown can tree-shake unused exports), and (2) emitting only the Radix CSS token files for the accent/gray color scales that Theme components actually reference, falling back to the monolithic stylesheet whenever a color is state-driven or unrecognized.

  • Tree-shaking window.__reflex: collect_window_library_imports walks static page/app-root imports and compile-time-serialized dynamic-component imports to build a per-library named-export map; _render_window_reflex_block emits import { Foo as __reflex_lib_Foo } lines instead of star imports, with a star-import fallback for internal $/utils/* modules, react/@emotion/react, and any tag that isn't a valid JS identifier.
  • Granular Radix CSS: get_radix_themes_stylesheets walks Theme component trees for literal accent_color/gray_color props, resolves the natural gray pairings, and emits only tokens/base.css + the required per-color CSS files + components.css + utilities.css; falls back to styles.css for state-driven or unknown colors.
  • Plugin plumbing: theme_roots is threaded from compile_app through PreCompileContext and both Tailwind (v3/v4) plugins, and strip_radix_theme_imports replaces the single-path Radix import check in add_tailwind_to_css_file to handle the new multi-file import shape.

Confidence Score: 4/5

Safe to merge with minor follow-up; the two findings are edge cases that don't affect the typical Radix/React component usage covered by the new tests.

The color-detection and named-import logic is well-tested and handles all the important fallback cases. Two edge cases are not covered: accent_color=gray produces a duplicate gray.css entry (self-referential pairing in _RADIX_ACCENT_TO_AUTO_GRAY), and any bundled external library whose components exclusively use default imports will be absent from window.__reflex because only named tags are collected. Neither affects the common Radix component usage path, but both would produce unexpected output in the specific scenarios described.

packages/reflex-components-radix/src/reflex_components_radix/plugin.py (duplicate color entry) and reflex/compiler/compiler.py (default-import-only library exclusion)

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/compiler/templates.py Refactors window.__reflex template generation from blanket star-imports to named-import blocks via new _render_window_reflex_block helper; falls back to star import for internal libs or invalid JS identifiers.
packages/reflex-base/src/reflex_base/components/dynamic.py Adds module-level dynamic_component_imports dict and reset function; captures named ImportVars during dynamic Component serialization so the compiler can union them into the window.__reflex named-import surface.
packages/reflex-base/src/reflex_base/plugins/base.py Adds optional theme_roots field (NotRequired) to PreCompileContext so plugins can receive page component roots without breaking plugins that don't read it.
packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py Adds strip_radix_theme_imports regex helper to remove all @radix-ui/themes @import lines (both monolithic and granular) from a stylesheet, used by the v3/v4 tailwind plugins.
packages/reflex-base/src/reflex_base/plugins/tailwind_v3.py Plumbs theme_roots into compile_root_style and updates add_tailwind_to_css_file to strip any Radix @import (not just the one monolithic path) before inserting the Tailwind block.
packages/reflex-base/src/reflex_base/plugins/tailwind_v4.py Same theme_roots plumbing and strip_radix_theme_imports migration as tailwind_v3; generates granular @import lines with layer(components) when color scales are statically known.
packages/reflex-components-radix/src/reflex_components_radix/plugin.py New color-detection logic (_collect_radix_theme_colors, get_radix_themes_stylesheets) walks Theme component trees to emit only the referenced Radix color-scale CSS files; contains a duplicate-entry bug when accent_color="gray" (self-referential pairing).
reflex/compiler/compiler.py Replaces _normalize_library_name with collect_window_library_imports that builds a per-library named-export map from static and dynamic imports; wires theme_roots and window_library_imports through compile_app.
tests/units/compiler/test_compiler.py Comprehensive new tests covering granular stylesheet selection, named-import generation, fallback conditions, and the _isolate_dynamic_imports fixture for isolation.
tests/units/test_app.py Updates two assertions from monolithic styles.css to granular per-color CSS paths to reflect the new default compilation output.

Comments Outside Diff (1)

  1. reflex/compiler/compiler.py, line 773-781 (link)

    P2 Bundled external lib silently absent from window.__reflex when only default imports exist

    collect_window_library_imports only records a library in the result when at least one non-default named tag is found in the static or dynamic-component imports. A library that is bundle_library'd but whose component only exposes a default export (is_default=True) will produce no entry in per_lib_tags, skip the if tags: guard, and be omitted from window_library_imports entirely. The old code unconditionally emitted import * as alias from "lib" for every entry in bundled_libraries, guaranteeing the library was present on window.__reflex. Any dynamic eval'd component that relies on window.__reflex["that-lib"] would fail silently at runtime.

Reviews (1): Last reviewed commit: "perf: tree-shake bundled libs and ship o..." | Re-trigger Greptile

When accent_color and its paired gray resolve to the same scale (e.g.
accent_color="gray"), the tokens CSS file was imported twice. Subtract
accents from grays before extending the sheet list so each color file
is emitted only once.
@FarhanAliRaza
Copy link
Copy Markdown
Contributor Author

Add more tests for dynamic components.

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