diff --git a/package.json b/package.json index c09a7f053d..30a4df4575 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,8 @@ }, "workspaces": { "packages": [ - "packages/*" + "packages/*", + "spikes/*" ] } } diff --git a/spikes/panda-mf-poc/.gitignore b/spikes/panda-mf-poc/.gitignore new file mode 100644 index 0000000000..bd9e772318 --- /dev/null +++ b/spikes/panda-mf-poc/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +styled-system/ +dist/ +src/ui/gamut.css +.mf/ diff --git a/spikes/panda-mf-poc/README.md b/spikes/panda-mf-poc/README.md new file mode 100644 index 0000000000..0889406ea0 --- /dev/null +++ b/spikes/panda-mf-poc/README.md @@ -0,0 +1,86 @@ +# Rspack + Module Federation spike (GMT-1715) + +Branch: `cass-GMT-1715`. A yarn workspace + nx project. Answers: **does Rspack + +Module Federation (platform's setup) affect the styling-engine decision?** + +A minimal MF pair — **host** (`variant="primary"`) + **remote** (exposes a +`Widget` using `variant="danger"`, a variant the host never renders) — both using +a Panda-built Gamut `Button`. The host imports the **one complete** Gamut static +stylesheet; the remote is federated in at runtime. + +## Run it + +``` +yarn install +yarn nx run panda-mf-poc:build # codegen + cssgen + rspack MF build (host + remote) +# to see it live (dist is static): serve each and open the host +npx http-server dist/remote -p 3001 --cors & +npx http-server dist/host -p 3000 & +# open http://localhost:3000 → host renders its own primary button + the federated remote danger button +``` + +## Answer: does MF affect the styling engine? — Yes, but it's satisfiable, and Panda is _safer_ here than the alternatives + +### The one real requirement (and why) + +A **zero-runtime** engine emits static CSS and tree-shakes to what each build +uses. Module Federation loads a remote's components into a host **at runtime** — +so the remote's styles must already be in the document. A host's own build won't +include CSS for a variant only the remote uses. + +**→ Gamut must ship a COMPLETE static stylesheet** (all recipe variants via +`staticCss`), imported once by the host. Then every federated remote's Gamut +components are covered regardless of what the host itself renders. + +**Proven here:** the host build emits `gmt-button--variant_danger` even though the +host only renders `variant="primary"` — because `staticCss: { recipes: { button: +['*'] } }` force-emits every variant. The remote's `danger` widget is styled by +the host's sheet. (This is the same `staticCss` requirement documented in +BREAKING-CHANGES §2/§3.) + +### Why Panda is actually SAFER across MF than some alternatives + +- **Deterministic, content-based class names** — `gmt-button--variant_danger`, + `.bg_primary` (recipe-name + property_value), identical across independent + builds. Federated host/remote builds produce the **same** class for the same + style, so duplicate CSS is idempotent and there are **no collisions**. Contrast + **CSS Modules**, which hash class names **per build** → federated host/remotes + get mismatched/duplicated names (a known MF hazard). Zero-runtime _atomic_ CSS + is a good fit for MF. +- **Tokens at `:root`** — `--colors-*` are defined once (host's sheet); remote + components reference the same vars. No per-remote theme runtime needed. + +### Coexistence / version notes + +- Keep **Gamut a shared singleton** across host + remotes (MF `shared`) so class + names + tokens match. **Version skew** (host on Gamut vX, remote on vY) is the + real risk — different generated classes/tokens → visual drift. Same discipline + MF already needs for React. +- Contrast **Emotion (today)**: runtime injection means each remote self-styles + (works out of the box), but MF apps commonly hit **multiple Emotion caches** + across remotes (duplicate `