From febec37fd1eff3470fa9b0dff5b8fa6c10f7ce5c Mon Sep 17 00:00:00 2001 From: Oto Macenauer Date: Tue, 23 Jun 2026 20:50:10 +0200 Subject: [PATCH] feat: add web-fragments skill Skill for building, embedding, debugging, and deploying micro-frontends with the Web Fragments framework (web-fragments npm package). - SKILL.md hub: mental model, exact v0.8.x API, workflow, gotchas (progressive disclosure, token-optimized) - references/: api-reference, host-integration (per-framework middleware), fragment-authoring, troubleshooting, css-and-styling, csp-and-iframe, piercing-and-performance, frameworks-astro - scripts/: scaffold-fragment.mjs (generate a Vite fragment + gateway snippet), doctor.mjs (static-check a host/fragment project for v0.8.x gotchas) - scripts/experiments/: reproducible Playwright experiments backing the verified CSS-isolation and Astro findings Knowledge verified against the library source and Playwright; includes the head-style-accumulation bug filed upstream as web-fragments#297 and a verified smooth-transition-without-ClientRouter workaround. --- skills/web-fragments/SKILL.md | 138 +++++++++++++ skills/web-fragments/evals/evals.json | 48 +++++ .../web-fragments/references/api-reference.md | 186 ++++++++++++++++++ .../references/csp-and-iframe.md | 43 ++++ .../references/css-and-styling.md | 63 ++++++ .../references/fragment-authoring.md | 91 +++++++++ .../references/frameworks-astro.md | 165 ++++++++++++++++ .../references/host-integration.md | 167 ++++++++++++++++ .../references/piercing-and-performance.md | 60 ++++++ .../references/troubleshooting.md | 130 ++++++++++++ skills/web-fragments/scripts/doctor.mjs | 166 ++++++++++++++++ .../scripts/experiments/README.md | 12 ++ .../astro-fragment/astro.config.mjs | 12 ++ .../experiments/astro-fragment/package.json | 12 ++ .../astro-fragment/public/css/a.css | 2 + .../astro-fragment/public/css/b.css | 2 + .../astro-fragment/public/css/c.css | 2 + .../astro-fragment/src/layouts/Layout.astro | 38 ++++ .../src/layouts/SmoothLayout.astro | 74 +++++++ .../astro-fragment/src/pages/[...path].astro | 55 ++++++ .../astro-fragment/src/pages/index.astro | 11 ++ .../src/pages/smooth/[site].astro | 8 + .../experiments/astro-host/package.json | 9 + .../scripts/experiments/astro-host/server.mjs | 54 +++++ .../css-vars-isolation/fragment.html | 43 ++++ .../experiments/css-vars-isolation/index.html | 56 ++++++ .../scripts/experiments/measure-astro.cjs | 84 ++++++++ .../scripts/experiments/measure-css.cjs | 61 ++++++ .../scripts/experiments/measure-head.cjs | 75 +++++++ .../scripts/experiments/measure-optout.cjs | 67 +++++++ .../scripts/experiments/measure-smooth.cjs | 54 +++++ .../scripts/scaffold-fragment.mjs | 123 ++++++++++++ 32 files changed, 2111 insertions(+) create mode 100644 skills/web-fragments/SKILL.md create mode 100644 skills/web-fragments/evals/evals.json create mode 100644 skills/web-fragments/references/api-reference.md create mode 100644 skills/web-fragments/references/csp-and-iframe.md create mode 100644 skills/web-fragments/references/css-and-styling.md create mode 100644 skills/web-fragments/references/fragment-authoring.md create mode 100644 skills/web-fragments/references/frameworks-astro.md create mode 100644 skills/web-fragments/references/host-integration.md create mode 100644 skills/web-fragments/references/piercing-and-performance.md create mode 100644 skills/web-fragments/references/troubleshooting.md create mode 100644 skills/web-fragments/scripts/doctor.mjs create mode 100644 skills/web-fragments/scripts/experiments/README.md create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/astro.config.mjs create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/package.json create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/public/css/a.css create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/public/css/b.css create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/public/css/c.css create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/src/layouts/Layout.astro create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/src/layouts/SmoothLayout.astro create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/src/pages/[...path].astro create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/src/pages/index.astro create mode 100644 skills/web-fragments/scripts/experiments/astro-fragment/src/pages/smooth/[site].astro create mode 100644 skills/web-fragments/scripts/experiments/astro-host/package.json create mode 100644 skills/web-fragments/scripts/experiments/astro-host/server.mjs create mode 100644 skills/web-fragments/scripts/experiments/css-vars-isolation/fragment.html create mode 100644 skills/web-fragments/scripts/experiments/css-vars-isolation/index.html create mode 100644 skills/web-fragments/scripts/experiments/measure-astro.cjs create mode 100644 skills/web-fragments/scripts/experiments/measure-css.cjs create mode 100644 skills/web-fragments/scripts/experiments/measure-head.cjs create mode 100644 skills/web-fragments/scripts/experiments/measure-optout.cjs create mode 100644 skills/web-fragments/scripts/experiments/measure-smooth.cjs create mode 100644 skills/web-fragments/scripts/scaffold-fragment.mjs diff --git a/skills/web-fragments/SKILL.md b/skills/web-fragments/SKILL.md new file mode 100644 index 0000000..b2ac312 --- /dev/null +++ b/skills/web-fragments/SKILL.md @@ -0,0 +1,138 @@ +--- +name: web-fragments +description: >- + Build, embed, debug, and deploy micro-frontends with the Web Fragments framework + (the `web-fragments` npm package by web-fragments.dev / Cloudflare). Use whenever the user + works with web-fragments, the `` element, `FragmentGateway`, + `registerFragment`, `getWebMiddleware` / `getNodeMiddleware`, fragment "piercing", or the + "reframed" iframe isolation — and more broadly when they want to incrementally migrate, + decompose, or compose a web frontend from independently deployed micro-frontends that + share one DOM, even if they don't name the library. Covers authoring a fragment, wiring it + into a host app, gateway/route-pattern config, styling across the shadow boundary, and + troubleshooting hydration/asset/type errors. Prefer this skill over guessing the API — the + framework is beta (v0.8.x) and several public docs are stale. +--- + +# Web Fragments + +Framework-/platform-agnostic micro-frontend architecture. Each micro-frontend's client JS +runs in an isolated context (a hidden iframe = *reframed*) while all fragments **share one +DOM, navigation, and history** — "containers for web frontends." Beta v0.8.x, in production +at Cloudflare. + +**Don't read `node_modules/web-fragments/` source for the API — it's captured here and in +`references/`.** web-fragments.dev docs are partly stale; when they disagree with this skill, +trust the skill (verify via the package's `exports` map in `node_modules/web-fragments/package.json`). + +## Mental model: 3 pieces + +1. **Fragment app** — a *standalone* app (any stack) at an HTTP endpoint serving its own + HTML + assets; doesn't know it's a fragment. → `references/fragment-authoring.md` +2. **Host (shell)** — the existing app that embeds fragments: calls `initializeWebFragments()` + once + places ``. → `references/host-integration.md` +3. **Gateway** — **mandatory** middleware on the host server (issue #278): proxies fragment + requests onto the host's single origin and *pierces* SSR markup into the shell. + +Flow: browser → host origin → gateway matches `routePatterns` → proxies to fragment +`endpoint` → response composed into the host page. + +## Public API (v0.8.x) — exactly three entry points + +There is **no** `web-fragments/middleware` entry point (a stale doc claims one). + +| Import | Exports | +|---|---| +| `web-fragments` | `initializeWebFragments()`, `WebFragment`, `WebFragmentHost` | +| `web-fragments/gateway` | `FragmentGateway`, `getWebMiddleware`, types `FragmentConfig`, `FragmentMiddlewareOptions` | +| `web-fragments/gateway/node` | `getNodeMiddleware` | + +**Client (host bootstrap):** +```ts +import { initializeWebFragments } from 'web-fragments'; +initializeWebFragments(); // defines the custom elements; call as early as possible +``` +```html + +``` +`fragment-id` is required (throws without it); `src` is optional. `` is +internal — you rarely author it. + +**Gateway (host server):** +```ts +import { FragmentGateway } from 'web-fragments/gateway'; +const gateway = new FragmentGateway(/* { piercingStyles?: string } */); +gateway.registerFragment({ // method is registerFragment, NOT register + fragmentId: 'party-button', // required; must match the element's fragment-id + endpoint: 'https://party-button.example.dev', // required; URL string OR a fetch-compatible fn + routePatterns: ['/__wf/party-button/:_*', '/'], // required (path-to-regexp v6): assets + host route(s) + piercing: true, // optional, default true; false = client-only + // piercingClassNames, forwardFragmentHeaders, iframeHeaders, onSsrFetchError — see api-reference +}); +``` +Full `FragmentConfig` + deprecated aliases (`upstream`→`endpoint`, +`prePiercingClassNames`→`piercingClassNames`): `references/api-reference.md`. + +**Middleware (pick ONE per host runtime):** +```ts +import { getWebMiddleware } from 'web-fragments/gateway'; // Web/Fetch: CF, Vercel, Netlify, Hono, SW +const mw = getWebMiddleware(gateway, { mode: 'development' }); // 'production' | 'development' + +import { getNodeMiddleware } from 'web-fragments/gateway/node'; // Node: Express / Connect +app.use(getNodeMiddleware(gateway)); +``` +Per-framework wiring: `references/host-integration.md`. + +## Workflow (add a fragment to an app) + +1. **Fragment app** serves its own HTML+assets, emitting assets under a **unique** path + (e.g. Vite `build.assetsDir: "__wf//"`) that lines up with the asset `routePattern`. +2. **Bootstrap** the host client: `initializeWebFragments()` at the earliest entry. +3. **Place** `` at the chosen host route. +4. **Register**: `new FragmentGateway()` + `registerFragment(...)` with two patterns (assets + + host route). The host-route pattern MUST match where the element lives (step 3). +5. **Install** the middleware matching the runtime (Web vs Node). +6. **Verify** (below), then deploy — fragment and host ship independently. + +## Verify + +Fragment renders as **nested shadow roots**: `` ▸ shadowRoot ▸ +`` ▸ shadowRoot ▸ ``, plus a hidden `