@luna_ui/luna 0.7.3 → 0.17.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/dist/api-DAWeanTX.js +1 -0
- package/dist/api-qXll116-.d.ts +80 -0
- package/dist/cli.mjs +27 -22
- package/dist/css/index.js +1 -0
- package/dist/event-utils.d.ts +1 -1
- package/dist/event-utils.js +1 -1
- package/dist/{index-vO066aMd.d.ts → index-VY8G32hr.d.ts} +16 -76
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/dist/raw.d.ts +2 -0
- package/dist/raw.js +1 -0
- package/dist/resource.d.ts +41 -0
- package/dist/resource.js +1 -0
- package/dist/router-lite.d.ts +44 -0
- package/dist/router-lite.js +1 -0
- package/dist/signals-shared.d.ts +12 -0
- package/dist/signals-shared.js +1 -0
- package/dist/signals.d.ts +50 -0
- package/dist/signals.js +1 -0
- package/dist/vite-plugin.d.ts +7708 -2
- package/dist/vite-plugin.js +7 -6
- package/package.json +34 -11
- package/dist/event-utils-C_M2XBNj.js +0 -1
- package/dist/src-BbjOW18q.js +0 -1
- package/src/css/extract.ts +0 -798
- package/src/css/index.ts +0 -10
- package/src/css/inject.ts +0 -205
- package/src/css/inline.ts +0 -182
- package/src/css/minify.ts +0 -70
- package/src/css/optimizer.ts +0 -6
- package/src/css/runtime.ts +0 -344
- package/src/css-optimizer/README.md +0 -353
- package/src/css-optimizer/cooccurrence.ts +0 -100
- package/src/css-optimizer/core.ts +0 -263
- package/src/css-optimizer/extractors.ts +0 -243
- package/src/css-optimizer/hash.ts +0 -54
- package/src/css-optimizer/index.ts +0 -129
- package/src/css-optimizer/merge.ts +0 -109
- package/src/css-optimizer/moonbit-analyzer.ts +0 -210
- package/src/css-optimizer/parser.ts +0 -120
- package/src/css-optimizer/pattern.ts +0 -171
- package/src/css-optimizer/transformers.ts +0 -301
- package/src/css-optimizer/types.ts +0 -128
- package/src/event-utils.ts +0 -227
- package/src/hydration/createHydrator.ts +0 -62
- package/src/hydration/delegate.ts +0 -62
- package/src/hydration/drag.ts +0 -214
- package/src/hydration/index.ts +0 -12
- package/src/hydration/keyboard.ts +0 -64
- package/src/hydration/toggle.ts +0 -101
- package/src/index.ts +0 -908
- package/src/jsx-dev-runtime.ts +0 -2
- package/src/jsx-runtime.ts +0 -398
- package/src/vite-plugin.ts +0 -718
- package/tests/__screenshots__/apg.test.ts/APG-Components---Accessibility-Tests-Button-Pattern-disabled-button-has-aria-disabled-1.png +0 -0
- package/tests/apg.test.ts +0 -466
- package/tests/context.test.ts +0 -118
- package/tests/css-optimizer-extractors.test.ts +0 -264
- package/tests/css-optimizer-integration.test.ts +0 -566
- package/tests/css-optimizer-transformers.test.ts +0 -301
- package/tests/css-optimizer.test.ts +0 -646
- package/tests/css-runtime.bench.ts +0 -442
- package/tests/css-runtime.test.ts +0 -342
- package/tests/debounced.test.ts +0 -165
- package/tests/dom.test.ts +0 -873
- package/tests/integration.test.ts +0 -405
- package/tests/issue-11-show-null-to-truthy.test.ts +0 -176
- package/tests/issue-5-for-infinite-loop.test.ts +0 -516
- package/tests/jsx-runtime.test.tsx +0 -393
- package/tests/lifecycle.test.ts +0 -833
- package/tests/move-before.bench.ts +0 -304
- package/tests/preact-signals-comparison.test.ts +0 -1608
- package/tests/resource.test.ts +0 -160
- package/tests/router.test.ts +0 -117
- package/tests/show-initial-mount-leak.test.tsx +0 -182
- package/tests/solidjs-api.test.ts +0 -660
- package/tests/static-perf.bench.ts +0 -64
- package/tests/store.test.ts +0 -263
- package/tests/tsx-syntax.test.tsx +0 -404
- /package/dist/{event-utils-Cd5f3Njd.d.ts → event-utils-BvAf0NwN.d.ts} +0 -0
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSS Performance Benchmark
|
|
3
|
-
*
|
|
4
|
-
* Compares zero-runtime CSS (Luna's approach) vs runtime CSS-in-JS patterns.
|
|
5
|
-
*
|
|
6
|
-
* Key metrics:
|
|
7
|
-
* 1. Initial render with pre-generated CSS (static) vs runtime-generated CSS (dynamic)
|
|
8
|
-
* 2. Style updates: class switching vs inline style mutation
|
|
9
|
-
* 3. CSSOM manipulation overhead
|
|
10
|
-
*
|
|
11
|
-
* References:
|
|
12
|
-
* - https://calendar.perfplanet.com/2019/the-unseen-performance-costs-of-css-in-js-in-react-apps/
|
|
13
|
-
* - https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { bench, describe } from "vitest";
|
|
17
|
-
|
|
18
|
-
// =============================================================================
|
|
19
|
-
// Test Helpers
|
|
20
|
-
// =============================================================================
|
|
21
|
-
|
|
22
|
-
function createContainer(): HTMLDivElement {
|
|
23
|
-
const container = document.createElement("div");
|
|
24
|
-
document.body.appendChild(container);
|
|
25
|
-
return container;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function createStyleSheet(): { styleEl: HTMLStyleElement; sheet: CSSStyleSheet } {
|
|
29
|
-
const styleEl = document.createElement("style");
|
|
30
|
-
document.head.appendChild(styleEl);
|
|
31
|
-
return { styleEl, sheet: styleEl.sheet! };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// =============================================================================
|
|
35
|
-
// CSS Generation Helpers
|
|
36
|
-
// =============================================================================
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Simulate Luna's zero-runtime approach:
|
|
40
|
-
* CSS is pre-generated at SSR time, only class names are applied at runtime
|
|
41
|
-
*/
|
|
42
|
-
function generateStaticCSS(count: number): { css: string; classMap: Map<string, string> } {
|
|
43
|
-
const classMap = new Map<string, string>();
|
|
44
|
-
let css = "";
|
|
45
|
-
|
|
46
|
-
const properties = [
|
|
47
|
-
["display", "flex"],
|
|
48
|
-
["align-items", "center"],
|
|
49
|
-
["justify-content", "space-between"],
|
|
50
|
-
["padding", "1rem"],
|
|
51
|
-
["margin", "0.5rem"],
|
|
52
|
-
["background", "#f5f5f5"],
|
|
53
|
-
["border-radius", "0.5rem"],
|
|
54
|
-
["font-size", "1rem"],
|
|
55
|
-
["color", "#333"],
|
|
56
|
-
["box-shadow", "0 1px 3px rgba(0,0,0,0.1)"],
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < count; i++) {
|
|
60
|
-
const [prop, val] = properties[i % properties.length];
|
|
61
|
-
const decl = `${prop}:${val}`;
|
|
62
|
-
if (!classMap.has(decl)) {
|
|
63
|
-
const className = `_${classMap.size.toString(36)}`;
|
|
64
|
-
classMap.set(decl, className);
|
|
65
|
-
css += `.${className}{${decl}}`;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return { css, classMap };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Simulate runtime CSS-in-JS:
|
|
74
|
-
* CSS is generated and inserted during component render
|
|
75
|
-
*/
|
|
76
|
-
function runtimeGenerateAndInsert(sheet: CSSStyleSheet, property: string, value: string): string {
|
|
77
|
-
const className = `_r${Math.random().toString(36).slice(2, 8)}`;
|
|
78
|
-
const rule = `.${className}{${property}:${value}}`;
|
|
79
|
-
sheet.insertRule(rule, sheet.cssRules.length);
|
|
80
|
-
return className;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Simulate styled-components pattern:
|
|
85
|
-
* Hash-based class generation with style injection
|
|
86
|
-
*/
|
|
87
|
-
function styledComponentsPattern(sheet: CSSStyleSheet, styles: Record<string, string>): string {
|
|
88
|
-
const hash = Object.entries(styles)
|
|
89
|
-
.map(([k, v]) => `${k}:${v}`)
|
|
90
|
-
.join(";");
|
|
91
|
-
const className = `sc-${hash.split("").reduce((a, c) => ((a << 5) - a + c.charCodeAt(0)) | 0, 0).toString(36)}`;
|
|
92
|
-
|
|
93
|
-
const rule = `.${className}{${Object.entries(styles).map(([k, v]) => `${k}:${v}`).join(";")}}`;
|
|
94
|
-
try {
|
|
95
|
-
sheet.insertRule(rule, sheet.cssRules.length);
|
|
96
|
-
} catch {
|
|
97
|
-
// Rule might already exist
|
|
98
|
-
}
|
|
99
|
-
return className;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// =============================================================================
|
|
103
|
-
// Benchmark: Initial Render
|
|
104
|
-
// =============================================================================
|
|
105
|
-
|
|
106
|
-
describe("Initial Render: Static vs Dynamic CSS", () => {
|
|
107
|
-
const ELEMENT_COUNT = 100;
|
|
108
|
-
|
|
109
|
-
describe(`${ELEMENT_COUNT} elements`, () => {
|
|
110
|
-
// Pre-generate CSS for static approach
|
|
111
|
-
const { classMap } = generateStaticCSS(ELEMENT_COUNT);
|
|
112
|
-
const classNames = Array.from(classMap.values());
|
|
113
|
-
|
|
114
|
-
bench("Static CSS (Luna zero-runtime)", () => {
|
|
115
|
-
const container = createContainer();
|
|
116
|
-
// CSS is already in <style>, just apply class names
|
|
117
|
-
const fragment = document.createDocumentFragment();
|
|
118
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
119
|
-
const div = document.createElement("div");
|
|
120
|
-
div.className = classNames[i % classNames.length];
|
|
121
|
-
fragment.appendChild(div);
|
|
122
|
-
}
|
|
123
|
-
container.appendChild(fragment);
|
|
124
|
-
container.remove();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
bench("Runtime CSS-in-JS (insertRule per element)", () => {
|
|
128
|
-
const container = createContainer();
|
|
129
|
-
const { styleEl, sheet } = createStyleSheet();
|
|
130
|
-
const properties = [
|
|
131
|
-
["display", "flex"],
|
|
132
|
-
["padding", "1rem"],
|
|
133
|
-
["margin", "0.5rem"],
|
|
134
|
-
["background", "#f5f5f5"],
|
|
135
|
-
["border-radius", "0.5rem"],
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
const fragment = document.createDocumentFragment();
|
|
139
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
140
|
-
const [prop, val] = properties[i % properties.length];
|
|
141
|
-
const className = runtimeGenerateAndInsert(sheet, prop, val);
|
|
142
|
-
const div = document.createElement("div");
|
|
143
|
-
div.className = className;
|
|
144
|
-
fragment.appendChild(div);
|
|
145
|
-
}
|
|
146
|
-
container.appendChild(fragment);
|
|
147
|
-
container.remove();
|
|
148
|
-
styleEl.remove();
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
bench("Inline styles (no CSS classes)", () => {
|
|
152
|
-
const container = createContainer();
|
|
153
|
-
const properties = [
|
|
154
|
-
{ display: "flex" },
|
|
155
|
-
{ padding: "1rem" },
|
|
156
|
-
{ margin: "0.5rem" },
|
|
157
|
-
{ background: "#f5f5f5" },
|
|
158
|
-
{ borderRadius: "0.5rem" },
|
|
159
|
-
];
|
|
160
|
-
|
|
161
|
-
const fragment = document.createDocumentFragment();
|
|
162
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
163
|
-
const div = document.createElement("div");
|
|
164
|
-
Object.assign(div.style, properties[i % properties.length]);
|
|
165
|
-
fragment.appendChild(div);
|
|
166
|
-
}
|
|
167
|
-
container.appendChild(fragment);
|
|
168
|
-
container.remove();
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// =============================================================================
|
|
174
|
-
// Benchmark: Style Updates
|
|
175
|
-
// =============================================================================
|
|
176
|
-
|
|
177
|
-
describe("Style Updates: Class Toggle vs Inline Mutation", () => {
|
|
178
|
-
const UPDATE_COUNT = 1000;
|
|
179
|
-
|
|
180
|
-
bench("Class toggle (zero-runtime pattern)", () => {
|
|
181
|
-
const container = createContainer();
|
|
182
|
-
const div = document.createElement("div");
|
|
183
|
-
div.className = "_a";
|
|
184
|
-
container.appendChild(div);
|
|
185
|
-
|
|
186
|
-
for (let i = 0; i < UPDATE_COUNT; i++) {
|
|
187
|
-
div.className = i % 2 === 0 ? "_a" : "_b";
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
container.remove();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
bench("classList.toggle", () => {
|
|
194
|
-
const container = createContainer();
|
|
195
|
-
const div = document.createElement("div");
|
|
196
|
-
div.className = "_a";
|
|
197
|
-
container.appendChild(div);
|
|
198
|
-
|
|
199
|
-
for (let i = 0; i < UPDATE_COUNT; i++) {
|
|
200
|
-
div.classList.toggle("_active");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
container.remove();
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
bench("Inline style mutation", () => {
|
|
207
|
-
const container = createContainer();
|
|
208
|
-
const div = document.createElement("div");
|
|
209
|
-
container.appendChild(div);
|
|
210
|
-
|
|
211
|
-
for (let i = 0; i < UPDATE_COUNT; i++) {
|
|
212
|
-
div.style.backgroundColor = i % 2 === 0 ? "#f5f5f5" : "#e5e5e5";
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
container.remove();
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
bench("style.cssText replacement", () => {
|
|
219
|
-
const container = createContainer();
|
|
220
|
-
const div = document.createElement("div");
|
|
221
|
-
container.appendChild(div);
|
|
222
|
-
|
|
223
|
-
for (let i = 0; i < UPDATE_COUNT; i++) {
|
|
224
|
-
div.style.cssText = i % 2 === 0 ? "background:#f5f5f5" : "background:#e5e5e5";
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
container.remove();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// =============================================================================
|
|
232
|
-
// Benchmark: CSSOM Operations
|
|
233
|
-
// =============================================================================
|
|
234
|
-
|
|
235
|
-
describe("CSSOM: insertRule vs innerHTML", () => {
|
|
236
|
-
const RULE_COUNT = 100;
|
|
237
|
-
|
|
238
|
-
bench("CSSStyleSheet.insertRule (one by one)", () => {
|
|
239
|
-
const style = document.createElement("style");
|
|
240
|
-
document.head.appendChild(style);
|
|
241
|
-
const sheet = style.sheet!;
|
|
242
|
-
|
|
243
|
-
for (let i = 0; i < RULE_COUNT; i++) {
|
|
244
|
-
sheet.insertRule(`._x${i}{color:#${i.toString(16).padStart(6, "0")}}`, sheet.cssRules.length);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
style.remove();
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
bench("style.textContent (batch)", () => {
|
|
251
|
-
const style = document.createElement("style");
|
|
252
|
-
document.head.appendChild(style);
|
|
253
|
-
|
|
254
|
-
let css = "";
|
|
255
|
-
for (let i = 0; i < RULE_COUNT; i++) {
|
|
256
|
-
css += `._x${i}{color:#${i.toString(16).padStart(6, "0")}}`;
|
|
257
|
-
}
|
|
258
|
-
style.textContent = css;
|
|
259
|
-
|
|
260
|
-
style.remove();
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
bench("style.innerHTML (batch)", () => {
|
|
264
|
-
const style = document.createElement("style");
|
|
265
|
-
document.head.appendChild(style);
|
|
266
|
-
|
|
267
|
-
let css = "";
|
|
268
|
-
for (let i = 0; i < RULE_COUNT; i++) {
|
|
269
|
-
css += `._x${i}{color:#${i.toString(16).padStart(6, "0")}}`;
|
|
270
|
-
}
|
|
271
|
-
style.innerHTML = css;
|
|
272
|
-
|
|
273
|
-
style.remove();
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// =============================================================================
|
|
278
|
-
// Benchmark: styled-components Pattern Simulation
|
|
279
|
-
// =============================================================================
|
|
280
|
-
|
|
281
|
-
describe("styled-components Pattern Overhead", () => {
|
|
282
|
-
const COMPONENT_COUNT = 50;
|
|
283
|
-
|
|
284
|
-
bench("Pre-computed class names (Luna)", () => {
|
|
285
|
-
const container = createContainer();
|
|
286
|
-
// Simulate: classes are computed at SSR, just apply them
|
|
287
|
-
const classes = ["_a _b _c", "_d _e _f", "_g _h _i", "_j _k _l", "_m _n _o"];
|
|
288
|
-
|
|
289
|
-
const fragment = document.createDocumentFragment();
|
|
290
|
-
for (let i = 0; i < COMPONENT_COUNT; i++) {
|
|
291
|
-
const div = document.createElement("div");
|
|
292
|
-
div.className = classes[i % classes.length];
|
|
293
|
-
fragment.appendChild(div);
|
|
294
|
-
}
|
|
295
|
-
container.appendChild(fragment);
|
|
296
|
-
container.remove();
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
bench("Hash + insertRule per component (styled-components)", () => {
|
|
300
|
-
const container = createContainer();
|
|
301
|
-
const { styleEl, sheet } = createStyleSheet();
|
|
302
|
-
const styleVariants = [
|
|
303
|
-
{ display: "flex", padding: "1rem", background: "#fff" },
|
|
304
|
-
{ display: "grid", padding: "0.5rem", background: "#f5f5f5" },
|
|
305
|
-
{ display: "block", padding: "2rem", background: "#e5e5e5" },
|
|
306
|
-
{ display: "inline-flex", padding: "0.25rem", background: "#ddd" },
|
|
307
|
-
{ display: "flex", padding: "1.5rem", background: "#ccc" },
|
|
308
|
-
];
|
|
309
|
-
|
|
310
|
-
const fragment = document.createDocumentFragment();
|
|
311
|
-
for (let i = 0; i < COMPONENT_COUNT; i++) {
|
|
312
|
-
const styles = styleVariants[i % styleVariants.length];
|
|
313
|
-
const className = styledComponentsPattern(sheet, styles);
|
|
314
|
-
const div = document.createElement("div");
|
|
315
|
-
div.className = className;
|
|
316
|
-
fragment.appendChild(div);
|
|
317
|
-
}
|
|
318
|
-
container.appendChild(fragment);
|
|
319
|
-
container.remove();
|
|
320
|
-
styleEl.remove();
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// =============================================================================
|
|
325
|
-
// Benchmark: Large Scale Rendering
|
|
326
|
-
// =============================================================================
|
|
327
|
-
|
|
328
|
-
describe("Large Scale: 1000 Elements", () => {
|
|
329
|
-
const ELEMENT_COUNT = 1000;
|
|
330
|
-
|
|
331
|
-
bench("Static CSS + class names only", () => {
|
|
332
|
-
const container = createContainer();
|
|
333
|
-
const classes = ["_a", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "_j"];
|
|
334
|
-
|
|
335
|
-
const fragment = document.createDocumentFragment();
|
|
336
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
337
|
-
const div = document.createElement("div");
|
|
338
|
-
div.className = classes[i % classes.length];
|
|
339
|
-
fragment.appendChild(div);
|
|
340
|
-
}
|
|
341
|
-
container.appendChild(fragment);
|
|
342
|
-
container.remove();
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
bench("Runtime insertRule + class names", () => {
|
|
346
|
-
const container = createContainer();
|
|
347
|
-
const { styleEl, sheet } = createStyleSheet();
|
|
348
|
-
const props = ["padding", "margin", "color", "background", "display"];
|
|
349
|
-
const vals = ["1rem", "0.5rem", "#333", "#fff", "flex"];
|
|
350
|
-
|
|
351
|
-
const fragment = document.createDocumentFragment();
|
|
352
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
353
|
-
const className = runtimeGenerateAndInsert(
|
|
354
|
-
sheet,
|
|
355
|
-
props[i % props.length],
|
|
356
|
-
vals[i % vals.length]
|
|
357
|
-
);
|
|
358
|
-
const div = document.createElement("div");
|
|
359
|
-
div.className = className;
|
|
360
|
-
fragment.appendChild(div);
|
|
361
|
-
}
|
|
362
|
-
container.appendChild(fragment);
|
|
363
|
-
container.remove();
|
|
364
|
-
styleEl.remove();
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
bench("Inline styles only", () => {
|
|
368
|
-
const container = createContainer();
|
|
369
|
-
const styles = [
|
|
370
|
-
{ padding: "1rem" },
|
|
371
|
-
{ margin: "0.5rem" },
|
|
372
|
-
{ color: "#333" },
|
|
373
|
-
{ background: "#fff" },
|
|
374
|
-
{ display: "flex" },
|
|
375
|
-
];
|
|
376
|
-
|
|
377
|
-
const fragment = document.createDocumentFragment();
|
|
378
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
379
|
-
const div = document.createElement("div");
|
|
380
|
-
Object.assign(div.style, styles[i % styles.length]);
|
|
381
|
-
fragment.appendChild(div);
|
|
382
|
-
}
|
|
383
|
-
container.appendChild(fragment);
|
|
384
|
-
container.remove();
|
|
385
|
-
});
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
// =============================================================================
|
|
389
|
-
// Benchmark: Deduplication Efficiency
|
|
390
|
-
// =============================================================================
|
|
391
|
-
|
|
392
|
-
describe("Deduplication: Repeated Styles", () => {
|
|
393
|
-
const ELEMENT_COUNT = 200;
|
|
394
|
-
const UNIQUE_STYLES = 10; // Only 10 unique styles, repeated
|
|
395
|
-
|
|
396
|
-
bench("Luna: deduplicated (10 classes for 200 elements)", () => {
|
|
397
|
-
const container = createContainer();
|
|
398
|
-
// Pre-computed: same style = same class
|
|
399
|
-
const classes: string[] = [];
|
|
400
|
-
for (let i = 0; i < UNIQUE_STYLES; i++) {
|
|
401
|
-
classes.push(`_${i.toString(36)}`);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const fragment = document.createDocumentFragment();
|
|
405
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
406
|
-
const div = document.createElement("div");
|
|
407
|
-
div.className = classes[i % UNIQUE_STYLES];
|
|
408
|
-
fragment.appendChild(div);
|
|
409
|
-
}
|
|
410
|
-
container.appendChild(fragment);
|
|
411
|
-
container.remove();
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
bench("No dedup: 200 insertRule calls", () => {
|
|
415
|
-
const container = createContainer();
|
|
416
|
-
const { styleEl, sheet } = createStyleSheet();
|
|
417
|
-
const props = [
|
|
418
|
-
"display:flex",
|
|
419
|
-
"padding:1rem",
|
|
420
|
-
"margin:0.5rem",
|
|
421
|
-
"background:#fff",
|
|
422
|
-
"color:#333",
|
|
423
|
-
"border-radius:4px",
|
|
424
|
-
"font-size:1rem",
|
|
425
|
-
"line-height:1.5",
|
|
426
|
-
"gap:0.5rem",
|
|
427
|
-
"justify-content:center",
|
|
428
|
-
];
|
|
429
|
-
|
|
430
|
-
const fragment = document.createDocumentFragment();
|
|
431
|
-
for (let i = 0; i < ELEMENT_COUNT; i++) {
|
|
432
|
-
const className = `_r${i}`;
|
|
433
|
-
sheet.insertRule(`.${className}{${props[i % UNIQUE_STYLES]}}`, sheet.cssRules.length);
|
|
434
|
-
const div = document.createElement("div");
|
|
435
|
-
div.className = className;
|
|
436
|
-
fragment.appendChild(div);
|
|
437
|
-
}
|
|
438
|
-
container.appendChild(fragment);
|
|
439
|
-
container.remove();
|
|
440
|
-
styleEl.remove();
|
|
441
|
-
});
|
|
442
|
-
});
|