@hueest/xray 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/client.d.ts +42 -51
- package/dist/client.js +136 -142
- package/dist/core.d.ts +42 -34
- package/dist/core.js +39 -33
- package/dist/css-escape-DJ-BsrNm.js +47 -0
- package/dist/hud.d.ts +7 -8
- package/dist/hud.js +5 -5
- package/dist/index.d.ts +268 -250
- package/dist/index.js +369 -240
- package/dist/measure-CUQxB-Ic.d.ts +524 -0
- package/dist/{plate-BRR6d8Se.js → plate-CXIh5_OB.js} +61 -45
- package/dist/react.core-BS2yvqeh.js +301 -0
- package/dist/react.core-BkJoCgWJ.d.ts +115 -0
- package/dist/react.d.ts +11 -13
- package/dist/react.dev.d.ts +4 -6
- package/dist/react.dev.js +58 -64
- package/dist/react.js +27 -25
- package/dist/{project-BZosujs9.js → serialize-Cj-EHvMv.js} +877 -1027
- package/package.json +8 -6
- package/virtual.d.ts +25 -32
- package/dist/css-escape-N7bOusGW.js +0 -52
- package/dist/react.core-BC02ukac.js +0 -294
- package/dist/react.core-NhWc9qan.d.ts +0 -89
- package/dist/serialize-BgdGt34A.d.ts +0 -501
package/dist/index.d.ts
CHANGED
|
@@ -1,39 +1,34 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
|
-
|
|
3
2
|
//#region src/diagnostics.d.ts
|
|
4
3
|
/**
|
|
5
|
-
* Dev-only capture diagnostics: a small, serializable record of why a Plate may
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Dev-only capture diagnostics: a small, serializable record of why a Plate may be incomplete or
|
|
5
|
+
* lower-fidelity, plus the one shared formatter both the browser console (`client.ts`) and the Vite
|
|
6
|
+
* server output (`index.ts`) print.
|
|
8
7
|
*
|
|
9
|
-
* Motivation: the serializer silently swallows a handful of capture omissions
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* caller can log them — without the core performing any console side effects.
|
|
8
|
+
* Motivation: the serializer silently swallows a handful of capture omissions (an unreadable
|
|
9
|
+
* cross-origin stylesheet, skipped pseudo-elements, off-screen bones dropped at the fold, an
|
|
10
|
+
* over-the-limit subtree). Without these records, "why does this skeleton look wrong?" has no
|
|
11
|
+
* answer short of reading the serializer source. Diagnostics surface those omissions as data the
|
|
12
|
+
* capture returns, so a caller can log them; the core performs no console side effects.
|
|
15
13
|
*
|
|
16
|
-
* Strictly DEV-ONLY (
|
|
17
|
-
*
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* byte-identical to a capture that produced no diagnostics).
|
|
14
|
+
* Strictly DEV-ONLY (ADR 0024, ADR 0008): this type is NOT a public package export and MUST NEVER
|
|
15
|
+
* reach the persisted Plate JSON, the `GatedPlate`, or the production adapter. It rides on the
|
|
16
|
+
* TRANSIENT `ViewIR.diagnostics` field only, which `captureView` populates and the dev client
|
|
17
|
+
* strips before posting (so committed `plates/<name>.json` stays byte-identical to a capture that
|
|
18
|
+
* produced no diagnostics).
|
|
22
19
|
*
|
|
23
|
-
* Centralized on purpose:
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* so their warning text cannot drift.
|
|
20
|
+
* Centralized on purpose: invalid posted/committed plates (ADR 0023) reuse the same messaging, so
|
|
21
|
+
* the code table and formatter stay reusable. Browser and server share `formatDiagnostic` so their
|
|
22
|
+
* warning text cannot drift.
|
|
27
23
|
*
|
|
28
24
|
* @module
|
|
29
25
|
*/
|
|
30
26
|
/**
|
|
31
|
-
* One aggregated capture omission. Serializable on purpose: NO DOM nodes, NO
|
|
32
|
-
*
|
|
33
|
-
* optional
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* node.
|
|
27
|
+
* One aggregated capture omission. Serializable on purpose: NO DOM nodes, NO CSS bodies, NO
|
|
28
|
+
* captured text — only a stable `code`, a human message, an optional aggregate `count`, and an
|
|
29
|
+
* optional short `detail` (e.g. a plate name or a node count, never user content). `count`
|
|
30
|
+
* aggregates occurrences: there is at most one record per code per capture, never one per skipped
|
|
31
|
+
* selector or node.
|
|
37
32
|
*/
|
|
38
33
|
interface CaptureDiagnostic {
|
|
39
34
|
code: DiagnosticCode;
|
|
@@ -42,52 +37,59 @@ interface CaptureDiagnostic {
|
|
|
42
37
|
detail?: string;
|
|
43
38
|
}
|
|
44
39
|
/**
|
|
45
|
-
* The closed set of capture-omission codes. Each maps to one silent site in the
|
|
46
|
-
*
|
|
47
|
-
*
|
|
40
|
+
* The closed set of capture-omission codes. Each maps to one silent site in the serializer (or an
|
|
41
|
+
* existing oversized-capture warning folded into the same vocabulary). Kept as a const union so the
|
|
42
|
+
* message table is exhaustive.
|
|
48
43
|
*/
|
|
49
44
|
type DiagnosticCode = 'unreadable-stylesheet' | 'unreadable-import' | 'skipped-dynamic-pseudo' | 'skipped-pseudo-element' | 'unsupported-rule' | 'dropped-tag' | 'dropped-subset' | 'dropped-cropped' | 'too-large' | 'invalid-plate-file';
|
|
50
45
|
//#endregion
|
|
51
46
|
//#region src/plate.d.ts
|
|
52
|
-
type LeafKind = 'text' | 'text-block' | 'media' | 'box';
|
|
53
47
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
* `hidden` is EXPLICIT-ONLY (a `data-xr-bone-kind` hint or a walker `ctx.bone({ kind: 'hidden'
|
|
49
|
+
* })`), never inferred: a bone that holds its measured box in the layout but paints nothing — the
|
|
50
|
+
* space-preserving complement to `data-xr-ignore`, which drops the box entirely.
|
|
51
|
+
*/
|
|
52
|
+
type LeafKind = 'text-line' | 'text-block' | 'media' | 'box' | 'hidden';
|
|
53
|
+
/**
|
|
54
|
+
* The shipped structural capture of a component's rendered DOM — the TREE artifact a Skeleton
|
|
55
|
+
* renders from (see the glossary: xray-js.dev/glossary). A Plate carries structure ONLY (ADR 0026):
|
|
56
|
+
* its scoped CSS is an INDEPENDENT sibling artifact — the plugin serves it through Vite's own CSS
|
|
57
|
+
* pipeline (`virtual:xray/plates/<name>.css`, plus the shared `virtual:xray/base.css`, and an
|
|
58
|
+
* `export const css` on the virtual JS module for dev/programmatic reads), and the
|
|
59
|
+
* framework-neutral `core.ts` path hands it back separately (`captureElement` → `{ plate, css }`;
|
|
60
|
+
* `renderPlateHtml(plate, css)` receives it explicitly). Consumers decide how to render either
|
|
61
|
+
* part. Still self-contained in ADR 0003's sense: both artifacts originate from the capture and
|
|
62
|
+
* depend on nothing in the consumer's build. Built from the RenderNode tree at plugin load (see
|
|
63
|
+
* chunk.ts), so the adapter injects strings instead of walking a tree on the latency-critical first
|
|
64
|
+
* paint — and no per-framework serializer ships to the client (ADR 0008).
|
|
60
65
|
*/
|
|
61
66
|
interface Plate {
|
|
62
67
|
v: number;
|
|
63
68
|
/** Capture name; comes from the virtual-module specifier, never typed at a call site. */
|
|
64
69
|
name: string;
|
|
65
70
|
/**
|
|
66
|
-
* The root's children, pre-serialized (ADR 0008): a stitch-free run is one
|
|
67
|
-
*
|
|
68
|
-
*
|
|
71
|
+
* The root's children, pre-serialized (ADR 0008): a stitch-free run is one HTML `string`; a
|
|
72
|
+
* stitch is `{ r: name }`; a stitch-bearing element is `{ c: className, k: chunk[] }`. Null until
|
|
73
|
+
* first capture.
|
|
69
74
|
*/
|
|
70
75
|
chunks: Chunk[] | null;
|
|
71
76
|
/** The root node's own content classes (its inherited font context), if any. */
|
|
72
77
|
rootCls?: string;
|
|
73
|
-
/** Layout-relevant CSS (incl. `@media`) scoped under the plate root, paint stripped. */
|
|
74
|
-
css: string;
|
|
75
78
|
/**
|
|
76
|
-
* Child plates named by the chunks' `{ r }` stitches, resolved through the
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
79
|
+
* Child plates named by the chunks' `{ r }` stitches, resolved through the import graph (ADR
|
|
80
|
+
* 0006). Populated by the loader's generated imports, never serialized into the plates JSON;
|
|
81
|
+
* absent in production when there are no stitches. In dev the live store takes precedence, so
|
|
82
|
+
* this need not be present.
|
|
80
83
|
*/
|
|
81
84
|
refs?: Record<string, Plate>;
|
|
82
85
|
}
|
|
83
86
|
/**
|
|
84
|
-
* One serialized child of a plate root (or of a stitch-bearing node): a
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* mounts a child plate at each stitch, and repeats each template (ADR 0008).
|
|
87
|
+
* One serialized child of a plate root (or of a stitch-bearing node): a stitch-free HTML run
|
|
88
|
+
* (`string`), a stitch to a child plate (`{ r: name }`), a stitch-bearing element kept real so its
|
|
89
|
+
* inner stitches can mount (`{ c: className, k: chunk[] }`), or a templated uniform run (`{ t:
|
|
90
|
+
* html, n }`): the cell's HTML once plus a repeat count the adapter expands to N copies (Template,
|
|
91
|
+
* ADR 0022). The framework-neutral render contract: an adapter injects the strings, mounts a child
|
|
92
|
+
* plate at each stitch, and repeats each template (ADR 0008).
|
|
91
93
|
*/
|
|
92
94
|
type Chunk = string | {
|
|
93
95
|
r: string;
|
|
@@ -99,13 +101,12 @@ type Chunk = string | {
|
|
|
99
101
|
n: number;
|
|
100
102
|
};
|
|
101
103
|
/**
|
|
102
|
-
* A plate after the in-browser Serialize (emit +
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* load (`serializePlate`). Never shipped to the client.
|
|
104
|
+
* A plate after the in-browser Serialize (emit + gate + classify) but before chunk serialization:
|
|
105
|
+
* the build-time RenderNode tree plus its scoped CSS. Produced by `serializePlateIR` (the
|
|
106
|
+
* structural part of `StoredPlate`) and the single-View `capture`, then serialized into the shipped
|
|
107
|
+
* `Plate` (chunks) at load (`serializePlate`). Never shipped to the client.
|
|
107
108
|
*/
|
|
108
|
-
interface
|
|
109
|
+
interface GatedPlate {
|
|
109
110
|
v: number;
|
|
110
111
|
name: string;
|
|
111
112
|
tree: RenderNode | null;
|
|
@@ -117,37 +118,38 @@ interface PlateNode {
|
|
|
117
118
|
/** Present on paint leaves; absent on layout containers. */
|
|
118
119
|
leaf?: LeafKind;
|
|
119
120
|
/**
|
|
120
|
-
* A stitch: render the named child plate's skeleton here instead of own
|
|
121
|
-
*
|
|
122
|
-
*
|
|
121
|
+
* A stitch: render the named child plate's skeleton here instead of own structure (ADR 0006).
|
|
122
|
+
* Mutually exclusive with `leaf`/`kids`. Resolved against `Plate.refs` (prod) or the live store
|
|
123
|
+
* (dev).
|
|
123
124
|
*/
|
|
124
125
|
ref?: string;
|
|
125
126
|
/**
|
|
126
|
-
* A templated uniform run (
|
|
127
|
-
*
|
|
128
|
-
*
|
|
127
|
+
* A templated uniform run (Template, ADR 0022): render this node's subtree `count` times. The
|
|
128
|
+
* serializer emits the subtree's HTML once plus the count; the adapter expands it to N copies at
|
|
129
|
+
* render. Absent on ordinary nodes.
|
|
129
130
|
*/
|
|
130
131
|
count?: number;
|
|
131
132
|
kids?: PlateNode[];
|
|
132
133
|
}
|
|
133
134
|
/**
|
|
134
|
-
* A node in the shipped tree, after classify (ADR 0007). Carries the
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* `nodeKey`) is gone. `cls` is a space-joined class-token list.
|
|
135
|
+
* A node in the shipped tree, after classify (ADR 0007). Carries the content-addressed style
|
|
136
|
+
* classes it needs instead of an id — the CSS targets those classes, not a per-node `data-xr`
|
|
137
|
+
* value, so no per-node scoping key is needed. `cls` is a space-joined class-token list.
|
|
138
138
|
*/
|
|
139
139
|
interface RenderNode {
|
|
140
140
|
leaf?: LeafKind;
|
|
141
141
|
ref?: string;
|
|
142
142
|
cls?: string;
|
|
143
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* A templated uniform run (Template, ADR 0022): serialize this subtree once + a count the adapter
|
|
145
|
+
* repeats.
|
|
146
|
+
*/
|
|
144
147
|
count?: number;
|
|
145
148
|
kids?: RenderNode[];
|
|
146
149
|
}
|
|
147
150
|
/**
|
|
148
|
-
* A captured style rule in id form — selectors are generated
|
|
149
|
-
*
|
|
150
|
-
* targets the plate root.
|
|
151
|
+
* A captured style rule in id form — selectors are generated downstream, so Serialize can remap
|
|
152
|
+
* node ids without string surgery. `ids: []` targets the plate root.
|
|
151
153
|
*/
|
|
152
154
|
interface PlateRule {
|
|
153
155
|
ids: number[];
|
|
@@ -161,12 +163,10 @@ interface PlateRule {
|
|
|
161
163
|
order: number;
|
|
162
164
|
}
|
|
163
165
|
/**
|
|
164
|
-
* One capture of a component within one viewport view — `[min, max)` in px,
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* framework-neutral per-View capture shape, exported for consumers reading the
|
|
169
|
-
* id-form projection directly.
|
|
166
|
+
* One capture of a component within one viewport view — `[min, max)` in px, either side open-ended
|
|
167
|
+
* when undefined. The id-form `{ tree, rules }` shape `emit` projects a measured View into (ADR
|
|
168
|
+
* 0004). The disk/wire shape is `StoredPlate` (below); this is the framework-neutral per-View
|
|
169
|
+
* capture shape, exported for consumers reading the id-form projection directly.
|
|
170
170
|
*/
|
|
171
171
|
interface ViewCapture {
|
|
172
172
|
/** Viewport width at capture time. */
|
|
@@ -176,37 +176,32 @@ interface ViewCapture {
|
|
|
176
176
|
tree: PlateNode;
|
|
177
177
|
rules: PlateRule[];
|
|
178
178
|
/**
|
|
179
|
-
* TRANSIENT, dev-only capture diagnostics (why this view may be lower
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* envelope keeps it in a SIBLING field that never reaches the stored artifact
|
|
186
|
-
* (ADR 0008). Absent in production (the prod adapter ships no capture). See
|
|
187
|
-
* diagnostics.ts and ADR 0008.
|
|
179
|
+
* TRANSIENT, dev-only capture diagnostics (why this view may be lower fidelity). Captured in the
|
|
180
|
+
* browser (mirrored onto `ViewIR.diagnostics`); the dev client logs it and posts it alongside the
|
|
181
|
+
* `StoredPlate` (so the Vite server can print the same text). It MUST NEVER be persisted: it is
|
|
182
|
+
* not part of the committed `StoredPlate` disk shape, the validator does not carry it, and the
|
|
183
|
+
* POST envelope keeps it in a SIBLING field that never reaches the stored artifact (ADR 0008).
|
|
184
|
+
* Absent in production (the prod adapter ships no capture). See diagnostics.ts and ADR 0008.
|
|
188
185
|
*/
|
|
189
186
|
diagnostics?: CaptureDiagnostic[];
|
|
190
187
|
}
|
|
191
188
|
/**
|
|
192
|
-
* The committed `plates/<name>.json` shape
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* at module-load, leaving the Tailwind/Bundle passthrough a clean gen-side seam.
|
|
200
|
-
* Replaces `PlateFile` (+ `ViewCapture`) on disk and on the `/__xray` wire.
|
|
189
|
+
* The committed `plates/<name>.json` shape (ADR 0022): the whole Plate already projected in the
|
|
190
|
+
* browser (the in-browser Serialize folds emit + the multi-View gating + classify in one session),
|
|
191
|
+
* so disk holds ONE gated, content-addressed tree + css rather than per-View captures assembled at
|
|
192
|
+
* load. It is a `GatedPlate` (the structural `{tree, css}` `serializePlate` consumes) PLUS the
|
|
193
|
+
* `breakpoints` the HUD coverage reads — the analysis-only geometry never crosses the wire (ADR
|
|
194
|
+
* 0021). The gen-side runs `serializePlate(stored) → Plate` (chunks) at module-load, leaving the
|
|
195
|
+
* Tailwind/Bundle passthrough a clean gen-side seam.
|
|
201
196
|
*/
|
|
202
|
-
interface StoredPlate extends
|
|
197
|
+
interface StoredPlate extends GatedPlate {
|
|
203
198
|
/** Width thresholds (view boundaries); the HUD coverage derives its bands from these. */
|
|
204
199
|
breakpoints: number[];
|
|
205
200
|
}
|
|
206
201
|
/**
|
|
207
|
-
* A dev-only sticky boolean toggle (get/set/subscribe), persisted per tab.
|
|
208
|
-
*
|
|
209
|
-
*
|
|
202
|
+
* A dev-only sticky boolean toggle (get/set/subscribe), persisted per tab. Used for both "light
|
|
203
|
+
* box" (render every `<Skeleton>` regardless of readiness) and "capture" (whether browsing
|
|
204
|
+
* re-captures plates).
|
|
210
205
|
*/
|
|
211
206
|
interface ToggleStore {
|
|
212
207
|
get: () => boolean;
|
|
@@ -214,19 +209,17 @@ interface ToggleStore {
|
|
|
214
209
|
subscribe: (onChange: () => void) => () => void;
|
|
215
210
|
}
|
|
216
211
|
/**
|
|
217
|
-
* Dev-only store of the freshest plate per name, updated in place when a
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* boundary and re-fire the capture, a feedback loop.
|
|
212
|
+
* Dev-only store of the freshest plate per name, updated in place when a capture lands.
|
|
213
|
+
* `<Skeleton>` reads through it so a new plate re-renders the site rather than reloading the module
|
|
214
|
+
* — which would remount the capture boundary and re-fire the capture, a feedback loop.
|
|
221
215
|
*/
|
|
222
216
|
interface PlateStore {
|
|
223
217
|
get: (name: string) => Plate | undefined;
|
|
224
218
|
subscribe: (name: string, onChange: () => void) => () => void;
|
|
225
219
|
/**
|
|
226
|
-
* Register a plate imported via the ref graph if the store has none yet — so a
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* live capture.
|
|
220
|
+
* Register a plate imported via the ref graph if the store has none yet — so a stitch resolves
|
|
221
|
+
* even before its child is re-captured, and survives a parent hot-swap (whose pushed plate
|
|
222
|
+
* carries no resolved `refs`). Never overwrites a live capture.
|
|
230
223
|
*/
|
|
231
224
|
seed: (name: string, plate: Plate) => void;
|
|
232
225
|
}
|
|
@@ -236,34 +229,31 @@ interface Span {
|
|
|
236
229
|
max?: number;
|
|
237
230
|
}
|
|
238
231
|
/**
|
|
239
|
-
* Dev-only Fixture store (ADR 0015): stored render-INPUT `data` per Plate,
|
|
240
|
-
*
|
|
241
|
-
*
|
|
232
|
+
* Dev-only Fixture store (ADR 0015): stored render-INPUT `data` per Plate, recorded to and replayed
|
|
233
|
+
* from a `plates/<name>.fixture.json` sidecar. Entirely dev-only — devalue and this store never
|
|
234
|
+
* reach the production bundle.
|
|
235
|
+
*
|
|
236
|
+
* Two cooperating halves, both flowing through the render-prop `data` seam (ADR 0014):
|
|
242
237
|
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
* it). `has(name)` reports whether a Fixture exists (HUD coverage marker), and
|
|
251
|
-
* `read(name)` returns the parsed Fixture `data` for Replay to substitute in
|
|
252
|
-
* front of the render prop.
|
|
238
|
+
* - The dev adapter (`react.dev.tsx`) calls `register(name, data)` at `loading=false` with the live
|
|
239
|
+
* `data` it is about to render, so the latest recordable input for each mounted Plate is always
|
|
240
|
+
* in scope for Record.
|
|
241
|
+
* - `record(name)` serializes that registered live `data` with devalue and POSTs it to the sidecar
|
|
242
|
+
* (the HUD button and the `first-ready`/`always` modes call it). `has(name)` reports whether a
|
|
243
|
+
* Fixture exists (HUD coverage marker), and `read(name)` returns the parsed Fixture `data` for
|
|
244
|
+
* Replay to substitute in front of the render prop.
|
|
253
245
|
*
|
|
254
|
-
* The store holds DECODED values (the dev client owns the devalue parse, since it
|
|
255
|
-
*
|
|
256
|
-
* devalue string.
|
|
246
|
+
* The store holds DECODED values (the dev client owns the devalue parse, since it has the live
|
|
247
|
+
* runtime); only the on-disk sidecar and the wire carry the opaque devalue string.
|
|
257
248
|
*/
|
|
258
249
|
interface FixtureStore {
|
|
259
250
|
/**
|
|
260
|
-
* Record the latest live `data` the dev adapter is about to render for `name`,
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* mounted, the live value is the most-recently-registered still-mounted instance.
|
|
251
|
+
* Record the latest live `data` the dev adapter is about to render for `name`, so Record always
|
|
252
|
+
* has the current recordable input in scope. A `register` with the same value is cheap; the
|
|
253
|
+
* adapter calls it on every ready render. Returns a disposer the adapter runs on unmount so an
|
|
254
|
+
* unmounted Skeleton's `data` never lingers in the store: an unmounted instance must never be
|
|
255
|
+
* recorded or shadow a still-mounted one (ADR 0015). With several Skeletons of the same plate
|
|
256
|
+
* name mounted, the live value is the most-recently-registered still-mounted instance.
|
|
267
257
|
*/
|
|
268
258
|
register: (name: string, data: unknown) => () => void;
|
|
269
259
|
/** True once a recorded Fixture exists for `name` (drives the HUD coverage marker). */
|
|
@@ -273,25 +263,22 @@ interface FixtureStore {
|
|
|
273
263
|
data: unknown;
|
|
274
264
|
} | undefined;
|
|
275
265
|
/**
|
|
276
|
-
* Serialize the registered live `data` for `name` with devalue and POST it to
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* registered (a plain-children `<Skeleton>` has none).
|
|
266
|
+
* Serialize the registered live `data` for `name` with devalue and POST it to the sidecar.
|
|
267
|
+
* Returns a promise that resolves once the write is server-confirmed (so the HUD can surface a
|
|
268
|
+
* failed Record). Throws loudly when the live `data` is unrecordable (devalue's contract) or no
|
|
269
|
+
* live `data` was registered (a plain-children `<Skeleton>` has none).
|
|
281
270
|
*/
|
|
282
271
|
record: (name: string) => Promise<void>;
|
|
283
272
|
/**
|
|
284
|
-
* Record every Skeleton that currently has live `data` registered (the HUD's
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
* rejected write surfaces to the HUD.
|
|
273
|
+
* Record every Skeleton that currently has live `data` registered (the HUD's single "Record
|
|
274
|
+
* fixture" button — one click captures the inputs of all mounted render-prop Skeletons). Resolves
|
|
275
|
+
* once all writes are server-confirmed; a rejected write surfaces to the HUD.
|
|
288
276
|
*/
|
|
289
277
|
recordAll: () => Promise<void>;
|
|
290
278
|
/**
|
|
291
|
-
* Seed the store from the on-disk sidecars on boot: a `{ <name>: devalueString }`
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* session survives a re-seed.
|
|
279
|
+
* Seed the store from the on-disk sidecars on boot: a `{ <name>: devalueString }` map (the opaque
|
|
280
|
+
* strings the server serves). The client decodes each with devalue. Existing entries are not
|
|
281
|
+
* clobbered, so a Fixture recorded this session survives a re-seed.
|
|
295
282
|
*/
|
|
296
283
|
seed: (encoded: Record<string, string>) => void;
|
|
297
284
|
/** React subscription so the HUD re-renders when a Fixture is recorded or seeded. */
|
|
@@ -303,10 +290,10 @@ interface PlateCoverage {
|
|
|
303
290
|
spans: Span[];
|
|
304
291
|
}
|
|
305
292
|
/**
|
|
306
|
-
* Dev-only per-plate coverage, sourced from the committed plate files (not the
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
293
|
+
* Dev-only per-plate coverage, sourced from the committed plate files (not the session): the
|
|
294
|
+
* breakpoints detected so far and which view spans are captured. The HUD renders every band —
|
|
295
|
+
* covered ones lit, the rest dim — and the capture-all sweep derives its target widths from the
|
|
296
|
+
* breakpoints.
|
|
310
297
|
*/
|
|
311
298
|
interface CoverageStore {
|
|
312
299
|
get: () => ReadonlyMap<string, PlateCoverage>;
|
|
@@ -314,9 +301,9 @@ interface CoverageStore {
|
|
|
314
301
|
subscribe: (onChange: () => void) => () => void;
|
|
315
302
|
}
|
|
316
303
|
/**
|
|
317
|
-
* Dev-only capture hook, installed by the dev client before the app boots.
|
|
318
|
-
*
|
|
319
|
-
*
|
|
304
|
+
* Dev-only capture hook, installed by the dev client before the app boots. Absent in production
|
|
305
|
+
* builds, so `<Skeleton>` carries zero capture weight. `captured` returns a dispose callback (stop
|
|
306
|
+
* observing this site).
|
|
320
307
|
*/
|
|
321
308
|
interface CaptureHook {
|
|
322
309
|
captured: (name: string, el: Element, opts?: {
|
|
@@ -342,20 +329,18 @@ interface CaptureHook {
|
|
|
342
329
|
/** Dev-only per-plate breakpoints + captured spans, from disk; fed by the bootstrap. */
|
|
343
330
|
coverage?: CoverageStore;
|
|
344
331
|
/**
|
|
345
|
-
* Replay toggle (ADR 0015): when active, the dev adapter substitutes a recorded
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* `missing-only`) is carried alongside in `replayMode`.
|
|
332
|
+
* Replay toggle (ADR 0015): when active, the dev adapter substitutes a recorded Fixture's `data`
|
|
333
|
+
* for the live `data` at `loading=false`. The boolean is the coarse on/off the HUD owns per tab;
|
|
334
|
+
* the per-mode policy (`prefer` vs `missing-only`) is carried alongside in `replayMode`.
|
|
349
335
|
*/
|
|
350
336
|
replay?: ToggleStore;
|
|
351
337
|
/** Dev-only Replay policy: how a Fixture substitutes for live `data` (ADR 0015). */
|
|
352
338
|
replayMode?: 'prefer' | 'missing-only';
|
|
353
339
|
/**
|
|
354
|
-
* Dev-only Record policy (ADR 0015): when the dev adapter records the live
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
* render.
|
|
340
|
+
* Dev-only Record policy (ADR 0015): when the dev adapter records the live `data` it is about to
|
|
341
|
+
* render. `'manual'` (the default) records nothing automatically — only the HUD button does;
|
|
342
|
+
* `'first-ready'` records once when a Skeleton goes ready and has no Fixture yet; `'always'`
|
|
343
|
+
* records on every ready render.
|
|
359
344
|
*/
|
|
360
345
|
recordMode?: 'manual' | 'first-ready' | 'always';
|
|
361
346
|
/** Dev-only Fixture record/replay store (ADR 0015); never present in production. */
|
|
@@ -367,40 +352,36 @@ declare global {
|
|
|
367
352
|
//#endregion
|
|
368
353
|
//#region src/chunk.d.ts
|
|
369
354
|
/**
|
|
370
|
-
* Distinct plate names referenced by the tree's stitches, in first-seen order.
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* `mergeViews`/`addCapture` removal (the multi-View merge/gate now lives in the
|
|
376
|
-
* in-browser `serializePlateIR`, project.ts).
|
|
355
|
+
* Distinct plate names referenced by the tree's stitches, in first-seen order. Walks a `RenderNode`
|
|
356
|
+
* tree (the stored, post-classify shape), so it drives the gen-side stitch import graph straight
|
|
357
|
+
* off a `StoredPlate.tree` (`renderPlateModule`, index.ts). The one node-side primitive needed at
|
|
358
|
+
* build time; multi-View gating happens in the in-browser `serializePlateIR` (serialize.ts, ADR
|
|
359
|
+
* 0022).
|
|
377
360
|
*/
|
|
378
361
|
declare function collectRefs(tree: RenderNode | null): string[];
|
|
379
362
|
//#endregion
|
|
380
363
|
//#region src/name.d.ts
|
|
381
364
|
/**
|
|
382
|
-
* Plate-name validation, shared by the Vite plugin (`index.ts`) and the
|
|
383
|
-
*
|
|
365
|
+
* Plate-name validation, shared by the Vite plugin (`index.ts`) and the Node-only POST validator
|
|
366
|
+
* (`validate.ts`).
|
|
384
367
|
*
|
|
385
|
-
* Lives in its own dependency-free module so `validate.ts` can reuse it without
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
* ref-graph emitter all gate on.
|
|
368
|
+
* Lives in its own dependency-free module so `validate.ts` can reuse it without importing the
|
|
369
|
+
* plugin entry (which would be a cycle), and so the regex stays the single source of truth for what
|
|
370
|
+
* a plate name may be — the same rule the loader, the file watcher, the coverage reader, the POST
|
|
371
|
+
* endpoint, and the ref-graph emitter all gate on.
|
|
390
372
|
*
|
|
391
373
|
* @module
|
|
392
374
|
*/
|
|
393
375
|
/**
|
|
394
376
|
* Names come from import specifiers and POST bodies — keep them inside the plates dir.
|
|
395
377
|
*
|
|
396
|
-
* Each path segment is `\w+(-\w+)*` — word chars with single interior hyphens,
|
|
397
|
-
* never
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* distinct prefixes (else e.g. `a/-b` and `a-/b` would both encode to `a---b`).
|
|
378
|
+
* Each path segment is `\w+(-\w+)*` — word chars with single interior hyphens, never doubled and
|
|
379
|
+
* never at a segment edge — and segments are joined by `/`. The class-prefix encoder
|
|
380
|
+
* (`classify.ts`) renders `/` as `--` to keep nested names readable, and that prefix is the
|
|
381
|
+
* isolation boundary across stitched plates (ADR 0007), so the encoding must be injective. Banning
|
|
382
|
+
* a literal `--` and any edge hyphen guarantees no `-` ever abuts a `/`, so every `--` in the
|
|
383
|
+
* prefix came from exactly one `/` — making distinct names always map to distinct prefixes (else
|
|
384
|
+
* e.g. `a/-b` and `a-/b` would both encode to `a---b`).
|
|
404
385
|
*
|
|
405
386
|
* @internal
|
|
406
387
|
*/
|
|
@@ -411,32 +392,38 @@ declare function isValidPlateName(name: string): boolean;
|
|
|
411
392
|
* Options for `xrayVitePlugin()`.
|
|
412
393
|
*
|
|
413
394
|
* Fixed conventions are intentionally not configurable: Plate names come from
|
|
414
|
-
* `virtual:xray/plates/<name>`, files live under `platesDir`, and responsive
|
|
415
|
-
*
|
|
416
|
-
* page evaluates.
|
|
395
|
+
* `virtual:xray/plates/<name>`, files live under `platesDir`, and responsive breakpoints are
|
|
396
|
+
* derived from captured CSS plus the `matchMedia` queries the page evaluates.
|
|
417
397
|
*/
|
|
418
398
|
interface XrayOptions {
|
|
419
|
-
/**
|
|
399
|
+
/**
|
|
400
|
+
* Directory where Plate JSON files are written and read, relative to the Vite root. Default:
|
|
401
|
+
* `plates`.
|
|
402
|
+
*/
|
|
420
403
|
platesDir?: string;
|
|
421
404
|
/** Mount the dev HUD for coverage, Capture, Light Box, and capture-all controls. Default: `false`. */
|
|
422
405
|
hud?: boolean;
|
|
423
406
|
/**
|
|
424
|
-
* Initial state of the browse-time Capture toggle in dev. Keep this off for
|
|
425
|
-
*
|
|
426
|
-
* Capture on per tab. Default: `false`.
|
|
407
|
+
* Initial state of the browse-time Capture toggle in dev. Keep this off for normal browsing and
|
|
408
|
+
* let the HUD, capture-all flow, or `?xray-capture` turn Capture on per tab. Default: `false`.
|
|
427
409
|
*/
|
|
428
410
|
capture?: boolean;
|
|
429
|
-
/**
|
|
411
|
+
/**
|
|
412
|
+
* Settle delay in milliseconds before capturing a ready Skeleton; override one boundary with the
|
|
413
|
+
* `delay` prop. Default: `200`.
|
|
414
|
+
*/
|
|
430
415
|
delay?: number;
|
|
431
|
-
/**
|
|
416
|
+
/**
|
|
417
|
+
* Upper bound in milliseconds on waiting for a busy subtree to go quiet before capturing anyway.
|
|
418
|
+
* Default: `5000`.
|
|
419
|
+
*/
|
|
432
420
|
settleCap?: number;
|
|
433
421
|
/**
|
|
434
|
-
* Collect-stage limits (ADR 0022): refuse to capture a boundary whose measured
|
|
435
|
-
*
|
|
436
|
-
* `
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
* boundary with the flat `maxNodes`/`maxBreadth`/`maxDepth` `<Skeleton>` props.
|
|
422
|
+
* Collect-stage limits (ADR 0022): refuse to capture a boundary whose measured tree exceeds any
|
|
423
|
+
* axis — too big means the Skeleton sits too high in the tree. `maxNodes` caps total surviving
|
|
424
|
+
* nodes (default `4096`), `maxBreadth` the widest level (default `512`), `maxDepth` the nesting
|
|
425
|
+
* depth (default `32`). Omit `maxNodes` and it derives as `round(maxBreadth × maxDepth / 4)`.
|
|
426
|
+
* Override one boundary with the flat `maxNodes`/`maxBreadth`/`maxDepth` `<Skeleton>` props.
|
|
440
427
|
*/
|
|
441
428
|
collect?: {
|
|
442
429
|
maxNodes?: number;
|
|
@@ -445,31 +432,30 @@ interface XrayOptions {
|
|
|
445
432
|
};
|
|
446
433
|
/**
|
|
447
434
|
* Dev-only Fixtures (ADR 0015): record a `<Skeleton>`'s render-input `data` to a
|
|
448
|
-
* `plates/<name>.fixture.json` sidecar and replay it in place of live data so
|
|
449
|
-
*
|
|
450
|
-
*
|
|
435
|
+
* `plates/<name>.fixture.json` sidecar and replay it in place of live data so capture is
|
|
436
|
+
* deterministic. Boot state only — the HUD is per-tab authority, just like `capture`. Entirely
|
|
437
|
+
* dev-only; nothing here ships in production.
|
|
451
438
|
*/
|
|
452
439
|
fixtures?: {
|
|
453
440
|
/**
|
|
454
|
-
* When to record the live `data`: `'manual'` (HUD button only — the default,
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
441
|
+
* When to record the live `data`: `'manual'` (HUD button only — the default, so live app data
|
|
442
|
+
* is never silently committed), `'first-ready'` (record once the first time a Skeleton goes
|
|
443
|
+
* ready with no Fixture yet), or `'always'` (record on every ready render). Default:
|
|
444
|
+
* `'manual'`.
|
|
458
445
|
*/
|
|
459
446
|
record?: 'manual' | 'first-ready' | 'always';
|
|
460
447
|
/**
|
|
461
|
-
* Whether to replay a recorded Fixture in place of live `data`: `false` (off,
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
* capturable). Default: `false`.
|
|
448
|
+
* Whether to replay a recorded Fixture in place of live `data`: `false` (off, the default),
|
|
449
|
+
* `'prefer'` (always use the Fixture when one exists), or `'missing-only'` (use the Fixture
|
|
450
|
+
* only when live `data` is nullish — `missing ≡ nullish`, so an empty array/object is present
|
|
451
|
+
* and stays capturable). Default: `false`.
|
|
466
452
|
*/
|
|
467
453
|
replay?: false | 'prefer' | 'missing-only';
|
|
468
454
|
};
|
|
469
455
|
}
|
|
470
456
|
/**
|
|
471
|
-
* Create the Vite plugins that resolve committed Plates and, during dev,
|
|
472
|
-
*
|
|
457
|
+
* Create the Vite plugins that resolve committed Plates and, during dev, capture new Plates from
|
|
458
|
+
* rendered `<Skeleton>` boundaries.
|
|
473
459
|
*
|
|
474
460
|
* Typical setup:
|
|
475
461
|
*
|
|
@@ -482,8 +468,10 @@ interface XrayOptions {
|
|
|
482
468
|
* ```
|
|
483
469
|
*
|
|
484
470
|
* Returns two plugins:
|
|
471
|
+
*
|
|
485
472
|
* - `xray:data` resolves `virtual:xray/plates/<name>` from committed Plate files in dev and build.
|
|
486
|
-
* - `xray:dev` runs only during `vite serve`; it injects the capture client, receives Captures,
|
|
473
|
+
* - `xray:dev` runs only during `vite serve`; it injects the capture client, receives Captures,
|
|
474
|
+
* writes Plate files, and hot-updates the page.
|
|
487
475
|
*/
|
|
488
476
|
declare function xrayVitePlugin(options?: XrayOptions): Plugin[];
|
|
489
477
|
interface CaptureRequest {
|
|
@@ -500,27 +488,37 @@ interface CaptureResponse {
|
|
|
500
488
|
interface PlateBroadcaster {
|
|
501
489
|
send(payload: unknown): void;
|
|
502
490
|
}
|
|
503
|
-
/** The subset of Vite's logger
|
|
491
|
+
/** The subset of Vite's logger used here; it preserves the formatted string verbatim. */
|
|
504
492
|
interface ServerLogger {
|
|
505
493
|
warn(message: string): void;
|
|
506
494
|
}
|
|
507
495
|
interface CaptureServer {
|
|
508
496
|
ws: PlateBroadcaster;
|
|
509
497
|
/**
|
|
510
|
-
* Vite's logger (`server.config.logger`). When present its `warn` prints the
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
* used, so server output matches the browser console exactly.
|
|
498
|
+
* Vite's logger (`server.config.logger`). When present its `warn` prints the diagnostic text to
|
|
499
|
+
* the server output; otherwise `console.warn` is the fallback. Either way the SAME shared
|
|
500
|
+
* formatter (diagnostics.ts) is used, so server output matches the browser console exactly.
|
|
514
501
|
*/
|
|
515
502
|
config?: {
|
|
516
503
|
logger?: ServerLogger;
|
|
517
504
|
};
|
|
505
|
+
/**
|
|
506
|
+
* The subset of Vite's dev server needed to keep BOTH of a plate's virtual modules fresh after a
|
|
507
|
+
* plate file changes (capture POST, hand edit, git checkout). Optional — absent in the unit tests
|
|
508
|
+
* that stub a minimal `server`. `getModuleById`/`invalidateModule`/`reloadModule` mirror
|
|
509
|
+
* `ViteDevServer`'s real shape (a subset, so this module stays free of a hard `vite` import at
|
|
510
|
+
* the type level beyond the `Plugin` type already used elsewhere).
|
|
511
|
+
*/
|
|
512
|
+
moduleGraph?: {
|
|
513
|
+
getModuleById(id: string): unknown;
|
|
514
|
+
invalidateModule(mod: unknown): void;
|
|
515
|
+
};
|
|
516
|
+
reloadModule?(mod: unknown): Promise<void>;
|
|
518
517
|
}
|
|
519
518
|
/**
|
|
520
|
-
* Per-plate breakpoints + derived coverage bands, read from the committed
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
* widths in one session, so its coverage is complete).
|
|
519
|
+
* Per-plate breakpoints + derived coverage bands, read from the committed StoredPlate files. The
|
|
520
|
+
* `spans` derive from each plate's `breakpoints` (ADR 0022: a StoredPlate sweeps all widths in one
|
|
521
|
+
* session, so its coverage is complete).
|
|
524
522
|
*
|
|
525
523
|
* @internal
|
|
526
524
|
*/
|
|
@@ -529,54 +527,74 @@ declare function readCoverage(dir: string): Record<string, {
|
|
|
529
527
|
spans: Span[];
|
|
530
528
|
}>;
|
|
531
529
|
/**
|
|
532
|
-
* All recorded Fixtures as `{ <name>: <devalueString> }`, read from the
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
* these distinct from Plate files (`isValidPlateName` rejects the dotted name, so
|
|
530
|
+
* All recorded Fixtures as `{ <name>: <devalueString> }`, read from the `<name>.fixture.json`
|
|
531
|
+
* sidecars (ADR 0015). The map values are the OPAQUE devalue strings exactly as written — the node
|
|
532
|
+
* side never parses them; the browser dev client owns the devalue decode. The `.fixture.json`
|
|
533
|
+
* suffix keeps these distinct from Plate files (`isValidPlateName` rejects the dotted name, so
|
|
537
534
|
* `readCoverage` never picks them up — Fixtures never leak into Plate coverage).
|
|
538
535
|
*
|
|
539
536
|
* @internal
|
|
540
537
|
*/
|
|
541
538
|
declare function readFixtures(dir: string): Record<string, string>;
|
|
542
539
|
/**
|
|
543
|
-
* Write a recorded Fixture sidecar (ADR 0015). Reuses the capture endpoint's
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
* so the persisted Plate stays purely structural.
|
|
540
|
+
* Write a recorded Fixture sidecar (ADR 0015). Reuses the capture endpoint's front-door checks
|
|
541
|
+
* (method, content type, declared/streamed size cap) and the `isValidPlateName` gate, but treats
|
|
542
|
+
* the devalue `data` payload as OPAQUE TEXT: it is validated only as a string and written verbatim,
|
|
543
|
+
* never eval'd or parsed server-side. The sidecar lives NEXT TO the Plate but is never merged into
|
|
544
|
+
* it, so the persisted Plate stays purely structural.
|
|
549
545
|
*
|
|
550
546
|
* @internal
|
|
551
547
|
*/
|
|
552
548
|
declare function handleFixturePost(req: CaptureRequest, res: CaptureResponse, fixturePath: (name: string) => string): void;
|
|
553
549
|
/**
|
|
554
|
-
* Validate a posted `StoredPlate` envelope, write it AS-IS, and hot-swap the
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
* `
|
|
558
|
-
*
|
|
559
|
-
* never reaches the stored artifact (ADR 0008).
|
|
550
|
+
* Validate a posted `StoredPlate` envelope, write it AS-IS, and hot-swap the plate in place. The
|
|
551
|
+
* dev client posts a finished StoredPlate (the whole Plate already projected in the browser, ADR
|
|
552
|
+
* 0022) inside a `{ plate, diagnostics? }` envelope; there is NO server-side accumulation/merge.
|
|
553
|
+
* `diagnostics` is a SIBLING field the server logs and then drops; it never reaches the stored
|
|
554
|
+
* artifact (ADR 0008).
|
|
560
555
|
*
|
|
561
556
|
* @internal
|
|
562
557
|
*/
|
|
563
558
|
declare function handleCapturePost(req: CaptureRequest, res: CaptureResponse, server: CaptureServer, platePath: (name: string) => string): void;
|
|
564
559
|
/**
|
|
565
|
-
* Render a plate as the virtual module's source. Each stitch (`ref` node) becomes
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
560
|
+
* Render a plate as the virtual module's source. Each stitch (`ref` node) becomes a real import of
|
|
561
|
+
* that child's virtual module, wired into a `refs` map on the default export — so the bundler
|
|
562
|
+
* builds the actual reference graph and chunks the transitive closure a page uses, with no runtime
|
|
563
|
+
* registry (ADR 0006). A stitchless plate is just its JSON. Self-references are dropped (a module
|
|
564
|
+
* can't import itself); an unknown child resolves to its own empty plate, never a build break.
|
|
565
|
+
*
|
|
566
|
+
* `name` defaults to the plate's own `name`, but the loader passes the PATH-derived name so a
|
|
567
|
+
* hand-edited StoredPlate whose `name` field drifted from its filename still serializes and
|
|
568
|
+
* self-references under the canonical name (`collectRefs` reads `stored.tree`, a RenderNode).
|
|
569
|
+
*
|
|
570
|
+
* Two-artifact module shape (ADR 0026):
|
|
571
|
+
*
|
|
572
|
+
* ```js
|
|
573
|
+
* import "virtual:xray/base.css"
|
|
574
|
+
* import "virtual:xray/plates/<name>.css"
|
|
575
|
+
* export default { tree-only plate JSON }
|
|
576
|
+
* export const css = "<the plate's scoped css string>"
|
|
577
|
+
* ```
|
|
578
|
+
*
|
|
579
|
+
* The default export is the TREE artifact (`Plate` carries no css field); the page's styling flows
|
|
580
|
+
* through Vite's own CSS pipeline via the two side-effect imports (dev inject + HMR, build
|
|
581
|
+
* extraction into the chunk's `.css` asset). `export const css` is the plate's css as data, for dev
|
|
582
|
+
* tooling / programmatic consumers that want the string itself — production adapters import only
|
|
583
|
+
* the default, so Rollup TREE-SHAKES the unused named export out of built chunks (verified
|
|
584
|
+
* empirically; the side-effect css imports do not pin it).
|
|
572
585
|
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
586
|
+
* BASE_CSS rides as a JS-level import of the SHARED `virtual:xray/base.css` module (not an
|
|
587
|
+
* `@import` inside each plate's css): Vite dedupes JS module imports by id, so the base rules reach
|
|
588
|
+
* the page exactly once no matter how many plates (nested/stitched included — every plate module
|
|
589
|
+
* emits this import, module identity collapses them) a page mounts, and at build a multi-chunk app
|
|
590
|
+
* gets it hoisted/shared rather than copied per chunk. An `@import` inside each plate's `.css`
|
|
591
|
+
* would instead be INLINED per importer by Vite's postcss-import at build, duplicating BASE_CSS
|
|
592
|
+
* into every plate's asset — the opposite of the dedupe this design locks in. Base rides before the
|
|
593
|
+
* plate's css module so a plate rule still beats a base rule at equal specificity by source order
|
|
594
|
+
* (the `${BASE_CSS}\n${css}` composition order).
|
|
577
595
|
*
|
|
578
596
|
* @internal
|
|
579
597
|
*/
|
|
580
|
-
declare function renderPlateModule(merged:
|
|
598
|
+
declare function renderPlateModule(merged: GatedPlate, name?: string): string;
|
|
581
599
|
//#endregion
|
|
582
600
|
export { type LeafKind, type Plate, type PlateNode, type PlateRule, type StoredPlate, type ViewCapture, XrayOptions, collectRefs, handleCapturePost, handleFixturePost, isValidPlateName, readCoverage, readFixtures, renderPlateModule, xrayVitePlugin };
|