From f452c29acde5bb52873725f93cdd76c64edf37b3 Mon Sep 17 00:00:00 2001 From: dev Date: Sat, 6 Jun 2026 02:31:24 +0200 Subject: [PATCH] docs(bundle): mark Phases 2-4 complete + record final numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 83 recipes code-split across 5 batches; index.css foundation-only. Monolith 850,879→335,100 raw / 113,489→54,429 gz (−59 KB gz every page). Documented the coupling pattern (composite renders soma markup → must import the eidos recipe; composite mounts eidos component → auto-loads) with the toggle-group/picker fixes. @layer stayed unnecessary. Co-Authored-By: Claude Opus 4.8 (1M context) --- optimize-bundle.md | 58 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/optimize-bundle.md b/optimize-bundle.md index 9007b5661..ce8c63264 100644 --- a/optimize-bundle.md +++ b/optimize-bundle.md @@ -19,7 +19,7 @@ excediendo** — y es un problema *estructural* (un agregado monolítico), no de | JS por página | ✅ Sano | entry 10.4 KB gz · runtime ~35 KB gz · componente mediana 7.3 KB gz | | CSS por página | ⚠️ Exceso | **113.5 KB gz / 851 KB raw** en *toda* página `/uix` | | Code-splitting JS | ✅ Correcto | color engine, sema y componentes se cargan bajo demanda | -| Code-splitting CSS | ⏳ En progreso | Fase 0 hecha (−4.5 KB gz/página, doble-carga eliminada); 94 recipes aún en el agregado | +| Code-splitting CSS | ✅ Resuelto | 93 recipes code-split; index.css foundation-only. **113.5 → 54.4 KB gz/página** (−59 KB). Pendiente: Fase 5 (podar base.css) | --- @@ -63,9 +63,9 @@ monta la página. Ese eje decide la Fase 1 (`@layer` o no). | --- | --- | --- | --- | | **0** ✅ | Des-duplicar los 10 (quitar de `index.css`; ya auto-importan) | nulo | hecho — ver resultado | | **1** ✅ | Piloto `dialog` (compuesto + portalizado): import en la raíz · tokens cross-portal OK · **`@layer` descartado** | medio | hecho — ver resultado | -| **2** | Partials compartidos (`menu-indicator`) + primitivas layout se quedan en foundation; auditar colisiones a igual especificidad | medio | eidos-lint | -| **3** | Propagar a los ~94 restantes **por lotes** por familia (overlays·pickers·menús·forms·data·tipografía); nunca en cascada | medio | build+lint+visual/lote | -| **4** | `index.css` = foundation-only; medir CSS/página | bajo | build | +| **2** ✅ | Partials compartidos (`menu-indicator` order-independent por especificidad) + primitivas layout en foundation | medio | hecho | +| **3** ✅ | Propagar a los 83 restantes **por lotes** por familia; couplings arreglados (toggle-group, pickers) | medio | hecho | +| **4** ✅ | `index.css` = foundation-only (−59 KB gz/página) | bajo | hecho | | **5** | (track aparte) podar `base.css` a roles tematizados + calendarios no-gregorianos dynamic import | alto | build | **Cross-coupling a vigilar** (recipes agregados que referencian un componente @@ -93,7 +93,7 @@ Evaluado con evidencia, no en teoría. **No se adopta `@layer`**: - Cada recipe ya scopea a `[data-{component}]` (doctrina CLAUDE.md) → las colisiones cross-componente a igual especificidad están **estructuralmente prevenidas**. La única dependencia de orden real (`menu-indicator`, partial - compartido) se resuelve dejándolo en foundation (Fase 2). + compartido) se resolvió por **especificidad** (Fase 2), no por orden. El scoping por `data-*` ya da el determinismo que daría `@layer`, sin su coste (envolver 104 ficheros) ni su riesgo (invertir 16 `!important`). `@layer` queda @@ -114,6 +114,54 @@ scoping no resuelva. portalizado (fuera de `[data-dialog]`) sigue **completamente estilado** (bg `oklch(0.285 0 0)`, radius 16px, sombra, padding 20px) — tokens de `base.css` global + recipe del chunk. El portal no rompe nada. + +### Fases 2–4 — barrido completo (COMPLETADO) + +83 recipes splitteados en 5 lotes (build+navegador+commit por lote). `index.css` +quedó **foundation-only**: `base.css` + `archetypes` + `events` + las 10 +primitivas de layout (box/flex/grid/stack/group/wrap/container/section/aspect- +ratio/auto-grid — se quedan: uso ubicuo + las recipes layerean sobre ellas). + +| Lote | Qué | Δ monolito (gz) | +| --- | --- | --- | +| 1 (35) | tipografía·inline·overlays·feedback·misc | 107.8 → 90.4 KB | +| 2 (7) | menús + `menu-indicator` order-independent | 90.4 → 86.5 KB | +| 3 (15) | form controls | 86.5 → 74.7 KB | +| 4 (16) | familia de pickers | 74.7 → 63.5 KB | +| 5 (10) | data·service·`words` | 63.5 → **54.4 KB** | + +**Resultado final: monolito 850 879 → 335 100 raw · 113 489 → 54 429 gz** — +**−515 KB raw / −59 KB gz en TODA página**. Una página de 5 componentes ahora +paga ~54 KB foundation + sus chunks (dialog 1.6 KB, toggle 0.45 KB, …) en vez de +113.5 KB fijos. El piso = `base.css` (52 KB gz), tal como predijo la auditoría. + +**Patrón de acoplamiento (lección clave)** — un compuesto que **renderiza el +markup** de otro componente (vía partes soma o `import type`) pero **no monta el +componente eidos** no arrastra su recipe. Hay que importarla explícitamente (leaf +primero, para que el compuesto la pueda sobreescribir). Casos encontrados y +arreglados, verificados en navegador: + +- `toggle-group` → `toggle` (los ítems son DOM-equivalentes a `` por + identidad estructural). Sin el fix: botones crudos (bg `#f0f0f0`, borde outset). +- `date-picker` → `calendar` + `month-grid` + `year-grid` (vistas con `import + type`). Sin el fix: calendario en `display:table` crudo. +- `date-range-picker` → `range-calendar`; `date-range-field` → `date-field`; + `time-range-field` → `time-field`. +- `color/time/time-range-picker` → `slider` (usan partes soma Slider). Sin el fix: + thumb 0px. +- `picker-shell` → `popover` (contenido en un Popover soma). + +Un compuesto que **monta** el componente eidos (p. ej. `words` monta Button/Icon/ +NumberField/ColorPicker/TextArea) NO necesita el import — el recipe llega solo. + +> **Coste residual aceptado**: si una página usa a la vez un compuesto y el leaf +> standalone (p. ej. date-picker + un Calendar suelto), el recipe del leaf viaja +> en 2 chunks (doble-carga menor, combo raro). Eliminarlo requeriría que el +> compuesto montara el componente eidos en vez de markup soma — refactor de +> componente, fuera del alcance de este split. + +`@layer` siguió sin necesitarse: cero colisiones cross-componente en todo el +barrido (el scoping `[data-{component}]` lo confirma en la práctica). - `check` 0 errores. ## Metodología