@vertz/ui-server 0.2.23 → 0.2.24
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/bun-dev-server.d.ts +19 -1
- package/dist/bun-dev-server.js +156 -22
- package/dist/bun-plugin/fast-refresh-dom-state.js +1 -1
- package/dist/bun-plugin/fast-refresh-runtime.js +6 -2
- package/dist/bun-plugin/index.js +138 -47
- package/dist/dom-shim/index.js +1 -1
- package/dist/index.js +2 -2
- package/dist/shared/{chunk-2qsqp9xj.js → chunk-eenfpa59.js} +20 -10
- package/dist/shared/{chunk-5cny4vzm.js → chunk-g0zqrb60.js} +7 -1
- package/dist/shared/{chunk-bm16zy8d.js → chunk-zs75v8qj.js} +19 -3
- package/dist/ssr/index.js +2 -2
- package/package.json +5 -5
package/dist/bun-dev-server.d.ts
CHANGED
|
@@ -82,6 +82,22 @@ interface BunDevServerOptions {
|
|
|
82
82
|
* @default false
|
|
83
83
|
*/
|
|
84
84
|
watchDeps?: boolean | string[];
|
|
85
|
+
/**
|
|
86
|
+
* Resolve theme from request for SSR. Returns the value for `data-theme`
|
|
87
|
+
* on the `<html>` tag and patches any `data-theme` attributes in the SSR body.
|
|
88
|
+
* Use this to read a theme cookie and eliminate dark→light flash on reload.
|
|
89
|
+
*/
|
|
90
|
+
themeFromRequest?: (request: Request) => string | null | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Called when the SSR module fails to recover from a broken state and a
|
|
93
|
+
* process restart is needed. Bun's ESM module cache retains failed imports
|
|
94
|
+
* process-wide — the only way to clear it is to restart the process.
|
|
95
|
+
*
|
|
96
|
+
* The dev server calls stop() before invoking this callback.
|
|
97
|
+
* Typically, the callback calls `process.exit(75)` and a supervisor
|
|
98
|
+
* script restarts the process.
|
|
99
|
+
*/
|
|
100
|
+
onRestartNeeded?: () => void;
|
|
85
101
|
}
|
|
86
102
|
interface ErrorDetail {
|
|
87
103
|
message: string;
|
|
@@ -157,11 +173,13 @@ interface SSRPageHtmlOptions {
|
|
|
157
173
|
headTags?: string;
|
|
158
174
|
/** Pre-built session + access set script tags for SSR injection. */
|
|
159
175
|
sessionScript?: string;
|
|
176
|
+
/** Theme value for `data-theme` attribute on `<html>`. */
|
|
177
|
+
htmlDataTheme?: string;
|
|
160
178
|
}
|
|
161
179
|
/**
|
|
162
180
|
* Generate a full SSR HTML page with the given content, CSS, SSR data, and script tag.
|
|
163
181
|
*/
|
|
164
|
-
declare function generateSSRPageHtml({ title, css, bodyHtml, ssrData, scriptTag, editor, headTags, sessionScript }: SSRPageHtmlOptions): string;
|
|
182
|
+
declare function generateSSRPageHtml({ title, css, bodyHtml, ssrData, scriptTag, editor, headTags, sessionScript, htmlDataTheme }: SSRPageHtmlOptions): string;
|
|
165
183
|
interface FetchInterceptorOptions {
|
|
166
184
|
apiHandler: (req: Request) => Promise<Response>;
|
|
167
185
|
origin: string;
|
package/dist/bun-dev-server.js
CHANGED
|
@@ -395,6 +395,58 @@ async function extractFontMetrics(fonts, rootDir) {
|
|
|
395
395
|
return result;
|
|
396
396
|
}
|
|
397
397
|
|
|
398
|
+
// src/ready-gate.ts
|
|
399
|
+
function createReadyGate(options) {
|
|
400
|
+
let ready = false;
|
|
401
|
+
const pendingClients = new Set;
|
|
402
|
+
let timeoutHandle = null;
|
|
403
|
+
function doOpen(currentError) {
|
|
404
|
+
if (ready)
|
|
405
|
+
return;
|
|
406
|
+
ready = true;
|
|
407
|
+
if (timeoutHandle) {
|
|
408
|
+
clearTimeout(timeoutHandle);
|
|
409
|
+
timeoutHandle = null;
|
|
410
|
+
}
|
|
411
|
+
for (const ws of pendingClients) {
|
|
412
|
+
try {
|
|
413
|
+
ws.sendText(JSON.stringify({ type: "connected" }));
|
|
414
|
+
if (currentError) {
|
|
415
|
+
ws.sendText(JSON.stringify({
|
|
416
|
+
type: "error",
|
|
417
|
+
category: currentError.category,
|
|
418
|
+
errors: currentError.errors
|
|
419
|
+
}));
|
|
420
|
+
}
|
|
421
|
+
} catch {}
|
|
422
|
+
}
|
|
423
|
+
pendingClients.clear();
|
|
424
|
+
}
|
|
425
|
+
if (options?.timeoutMs) {
|
|
426
|
+
timeoutHandle = setTimeout(() => {
|
|
427
|
+
if (!ready) {
|
|
428
|
+
options.onTimeoutWarning?.();
|
|
429
|
+
doOpen();
|
|
430
|
+
}
|
|
431
|
+
}, options.timeoutMs);
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
get isReady() {
|
|
435
|
+
return ready;
|
|
436
|
+
},
|
|
437
|
+
onOpen(ws) {
|
|
438
|
+
if (ready)
|
|
439
|
+
return false;
|
|
440
|
+
pendingClients.add(ws);
|
|
441
|
+
return true;
|
|
442
|
+
},
|
|
443
|
+
onClose(ws) {
|
|
444
|
+
pendingClients.delete(ws);
|
|
445
|
+
},
|
|
446
|
+
open: doOpen
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
398
450
|
// src/source-map-resolver.ts
|
|
399
451
|
import { readFileSync } from "fs";
|
|
400
452
|
import { resolve as resolvePath } from "path";
|
|
@@ -1113,19 +1165,35 @@ function installDomShim() {
|
|
|
1113
1165
|
cookie: ""
|
|
1114
1166
|
};
|
|
1115
1167
|
globalThis.document = fakeDocument;
|
|
1168
|
+
const windowStubs = {
|
|
1169
|
+
scrollTo: () => {},
|
|
1170
|
+
scroll: () => {},
|
|
1171
|
+
addEventListener: () => {},
|
|
1172
|
+
removeEventListener: () => {},
|
|
1173
|
+
dispatchEvent: () => true,
|
|
1174
|
+
getComputedStyle: () => ({}),
|
|
1175
|
+
matchMedia: () => ({ matches: false, addListener: () => {}, removeListener: () => {} })
|
|
1176
|
+
};
|
|
1116
1177
|
if (typeof window === "undefined") {
|
|
1117
1178
|
globalThis.window = {
|
|
1118
1179
|
location: { pathname: ssrStorage.getStore()?.url || "/", search: "", hash: "" },
|
|
1119
1180
|
history: {
|
|
1120
1181
|
pushState: () => {},
|
|
1121
1182
|
replaceState: () => {}
|
|
1122
|
-
}
|
|
1183
|
+
},
|
|
1184
|
+
...windowStubs
|
|
1123
1185
|
};
|
|
1124
1186
|
} else {
|
|
1125
|
-
globalThis.window
|
|
1126
|
-
|
|
1187
|
+
const win = globalThis.window;
|
|
1188
|
+
win.location = {
|
|
1189
|
+
...win.location || {},
|
|
1127
1190
|
pathname: ssrStorage.getStore()?.url || "/"
|
|
1128
1191
|
};
|
|
1192
|
+
for (const [key, val] of Object.entries(windowStubs)) {
|
|
1193
|
+
if (typeof win[key] !== "function") {
|
|
1194
|
+
win[key] = val;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1129
1197
|
}
|
|
1130
1198
|
globalThis.Node = SSRNode;
|
|
1131
1199
|
globalThis.HTMLElement = SSRElement;
|
|
@@ -1250,6 +1318,9 @@ function serializeToHtml(node) {
|
|
|
1250
1318
|
return node.html;
|
|
1251
1319
|
}
|
|
1252
1320
|
const { tag, attrs, children } = node;
|
|
1321
|
+
if (tag === "fragment") {
|
|
1322
|
+
return children.map((child) => serializeToHtml(child)).join("");
|
|
1323
|
+
}
|
|
1253
1324
|
const attrStr = serializeAttrs(attrs);
|
|
1254
1325
|
if (VOID_ELEMENTS.has(tag)) {
|
|
1255
1326
|
return `<${tag}${attrStr}>`;
|
|
@@ -1326,6 +1397,9 @@ function renderToStream(tree, options) {
|
|
|
1326
1397
|
return serializeToHtml(placeholder);
|
|
1327
1398
|
}
|
|
1328
1399
|
const { tag, attrs, children } = node;
|
|
1400
|
+
if (tag === "fragment") {
|
|
1401
|
+
return children.map((child) => walkAndSerialize(child)).join("");
|
|
1402
|
+
}
|
|
1329
1403
|
const isRawText = RAW_TEXT_ELEMENTS.has(tag);
|
|
1330
1404
|
const attrStr = Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeAttr2(v)}"`).join("");
|
|
1331
1405
|
if (VOID_ELEMENTS.has(tag)) {
|
|
@@ -1981,11 +2055,13 @@ function generateSSRPageHtml({
|
|
|
1981
2055
|
scriptTag,
|
|
1982
2056
|
editor = "vscode",
|
|
1983
2057
|
headTags = "",
|
|
1984
|
-
sessionScript = ""
|
|
2058
|
+
sessionScript = "",
|
|
2059
|
+
htmlDataTheme
|
|
1985
2060
|
}) {
|
|
1986
2061
|
const ssrDataScript = ssrData.length > 0 ? `<script>window.__VERTZ_SSR_DATA__=${safeSerialize(ssrData)};</script>` : "";
|
|
2062
|
+
const htmlAttrs = htmlDataTheme ? ` data-theme="${htmlDataTheme}"` : "";
|
|
1987
2063
|
return `<!doctype html>
|
|
1988
|
-
<html lang="en">
|
|
2064
|
+
<html lang="en"${htmlAttrs}>
|
|
1989
2065
|
<head>
|
|
1990
2066
|
<meta charset="UTF-8" />
|
|
1991
2067
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
@@ -2082,7 +2158,9 @@ function createBunDevServer(options) {
|
|
|
2082
2158
|
editor: editorOption,
|
|
2083
2159
|
headTags: headTagsOption = "",
|
|
2084
2160
|
sessionResolver,
|
|
2085
|
-
watchDeps
|
|
2161
|
+
watchDeps,
|
|
2162
|
+
themeFromRequest,
|
|
2163
|
+
onRestartNeeded
|
|
2086
2164
|
} = options;
|
|
2087
2165
|
const faviconTag = detectFaviconTag(projectRoot);
|
|
2088
2166
|
const headTags = [faviconTag, headTagsOption].filter(Boolean).join(`
|
|
@@ -2099,6 +2177,7 @@ function createBunDevServer(options) {
|
|
|
2099
2177
|
let srcWatcherRef = null;
|
|
2100
2178
|
let refreshTimeout = null;
|
|
2101
2179
|
let stopped = false;
|
|
2180
|
+
let ssrFallback = false;
|
|
2102
2181
|
const wsClients = new Set;
|
|
2103
2182
|
let currentError = null;
|
|
2104
2183
|
const sourceMapResolver = createSourceMapResolver(projectRoot);
|
|
@@ -2412,8 +2491,8 @@ function createBunDevServer(options) {
|
|
|
2412
2491
|
}
|
|
2413
2492
|
if (!pluginsRegistered) {
|
|
2414
2493
|
const { plugin: serverPlugin, updateManifest } = createVertzBunPlugin({
|
|
2415
|
-
hmr:
|
|
2416
|
-
fastRefresh:
|
|
2494
|
+
hmr: true,
|
|
2495
|
+
fastRefresh: true,
|
|
2417
2496
|
logger,
|
|
2418
2497
|
diagnostics
|
|
2419
2498
|
});
|
|
@@ -2424,16 +2503,34 @@ function createBunDevServer(options) {
|
|
|
2424
2503
|
const updateServerManifest = stableUpdateManifest;
|
|
2425
2504
|
let ssrMod;
|
|
2426
2505
|
try {
|
|
2427
|
-
|
|
2506
|
+
if (isRestarting) {
|
|
2507
|
+
mkdirSync(devDir, { recursive: true });
|
|
2508
|
+
const ssrBootPath = resolve(devDir, "ssr-reload-entry.ts");
|
|
2509
|
+
const ts = Date.now();
|
|
2510
|
+
writeFileSync2(ssrBootPath, `export * from '${entryPath}';
|
|
2511
|
+
`);
|
|
2512
|
+
ssrMod = await import(`${ssrBootPath}?t=${ts}`);
|
|
2513
|
+
} else {
|
|
2514
|
+
ssrMod = await import(entryPath);
|
|
2515
|
+
}
|
|
2516
|
+
ssrFallback = false;
|
|
2428
2517
|
if (logRequests) {
|
|
2429
2518
|
console.log("[Server] SSR module loaded");
|
|
2430
2519
|
}
|
|
2431
2520
|
} catch (e) {
|
|
2432
2521
|
console.error("[Server] Failed to load SSR module:", e);
|
|
2433
2522
|
if (isRestarting) {
|
|
2434
|
-
|
|
2523
|
+
ssrFallback = true;
|
|
2524
|
+
ssrMod = {};
|
|
2525
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
2526
|
+
const errStack = e instanceof Error ? e.stack : undefined;
|
|
2527
|
+
const { message: _, ...loc } = errStack ? parseSourceFromStack(errStack) : { message: "" };
|
|
2528
|
+
queueMicrotask(() => {
|
|
2529
|
+
broadcastError("ssr", [{ message: errMsg, ...loc, stack: errStack }]);
|
|
2530
|
+
});
|
|
2531
|
+
} else {
|
|
2532
|
+
process.exit(1);
|
|
2435
2533
|
}
|
|
2436
|
-
process.exit(1);
|
|
2437
2534
|
}
|
|
2438
2535
|
let fontFallbackMetrics;
|
|
2439
2536
|
if (ssrMod.theme?.fonts) {
|
|
@@ -2462,6 +2559,12 @@ if (import.meta.hot) import.meta.hot.accept();
|
|
|
2462
2559
|
setupOpenAPIWatcher();
|
|
2463
2560
|
let bundledScriptUrl = null;
|
|
2464
2561
|
let hmrBootstrapScript = null;
|
|
2562
|
+
const readyGate = createReadyGate({
|
|
2563
|
+
timeoutMs: 5000,
|
|
2564
|
+
onTimeoutWarning: () => {
|
|
2565
|
+
console.warn("[Server] HMR asset discovery timed out \u2014 unblocking clients");
|
|
2566
|
+
}
|
|
2567
|
+
});
|
|
2465
2568
|
const routes = {
|
|
2466
2569
|
"/__vertz_hmr": hmrShellModule
|
|
2467
2570
|
};
|
|
@@ -2605,6 +2708,7 @@ data: {}
|
|
|
2605
2708
|
if (logRequests) {
|
|
2606
2709
|
console.log(`[Server] SSR: ${pathname}`);
|
|
2607
2710
|
}
|
|
2711
|
+
const ssrTheme = themeFromRequest?.(request) ?? undefined;
|
|
2608
2712
|
try {
|
|
2609
2713
|
const interceptor = apiHandler ? createFetchInterceptor({
|
|
2610
2714
|
apiHandler,
|
|
@@ -2668,19 +2772,22 @@ data: {}
|
|
|
2668
2772
|
headers: { Location: result.redirect.to }
|
|
2669
2773
|
});
|
|
2670
2774
|
}
|
|
2775
|
+
const bodyHtml = ssrTheme ? result.html.replace(/data-theme="[^"]*"/, `data-theme="${ssrTheme}"`) : result.html;
|
|
2671
2776
|
const scriptTag = buildScriptTag(bundledScriptUrl, hmrBootstrapScript, clientSrc);
|
|
2672
2777
|
const combinedHeadTags = [headTags, result.headTags].filter(Boolean).join(`
|
|
2673
2778
|
`);
|
|
2674
2779
|
const html = generateSSRPageHtml({
|
|
2675
2780
|
title,
|
|
2676
2781
|
css: result.css,
|
|
2677
|
-
bodyHtml
|
|
2782
|
+
bodyHtml,
|
|
2678
2783
|
ssrData: result.ssrData,
|
|
2679
2784
|
scriptTag,
|
|
2680
2785
|
editor,
|
|
2681
2786
|
headTags: combinedHeadTags,
|
|
2682
|
-
sessionScript
|
|
2787
|
+
sessionScript,
|
|
2788
|
+
htmlDataTheme: ssrTheme
|
|
2683
2789
|
});
|
|
2790
|
+
clearError();
|
|
2684
2791
|
return new Response(html, {
|
|
2685
2792
|
status: 200,
|
|
2686
2793
|
headers: {
|
|
@@ -2704,7 +2811,8 @@ data: {}
|
|
|
2704
2811
|
ssrData: [],
|
|
2705
2812
|
scriptTag,
|
|
2706
2813
|
editor,
|
|
2707
|
-
headTags
|
|
2814
|
+
headTags,
|
|
2815
|
+
htmlDataTheme: ssrTheme
|
|
2708
2816
|
});
|
|
2709
2817
|
return new Response(fallbackHtml, {
|
|
2710
2818
|
status: 200,
|
|
@@ -2720,13 +2828,15 @@ data: {}
|
|
|
2720
2828
|
wsClients.add(ws);
|
|
2721
2829
|
diagnostics.recordWebSocketChange(wsClients.size);
|
|
2722
2830
|
logger.log("ws", "client-connected", { total: wsClients.size });
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2831
|
+
if (!readyGate.onOpen(ws)) {
|
|
2832
|
+
ws.sendText(JSON.stringify({ type: "connected" }));
|
|
2833
|
+
if (currentError) {
|
|
2834
|
+
ws.sendText(JSON.stringify({
|
|
2835
|
+
type: "error",
|
|
2836
|
+
category: currentError.category,
|
|
2837
|
+
errors: currentError.errors
|
|
2838
|
+
}));
|
|
2839
|
+
}
|
|
2730
2840
|
}
|
|
2731
2841
|
},
|
|
2732
2842
|
message(ws, msg) {
|
|
@@ -2818,6 +2928,7 @@ data: {}
|
|
|
2818
2928
|
},
|
|
2819
2929
|
close(ws) {
|
|
2820
2930
|
wsClients.delete(ws);
|
|
2931
|
+
readyGate.onClose(ws);
|
|
2821
2932
|
diagnostics.recordWebSocketChange(wsClients.size);
|
|
2822
2933
|
}
|
|
2823
2934
|
},
|
|
@@ -2829,7 +2940,13 @@ data: {}
|
|
|
2829
2940
|
if (logRequests) {
|
|
2830
2941
|
console.log(`[Server] SSR+HMR dev server running at http://${host}:${server.port}`);
|
|
2831
2942
|
}
|
|
2832
|
-
|
|
2943
|
+
try {
|
|
2944
|
+
await discoverHMRAssets();
|
|
2945
|
+
} finally {
|
|
2946
|
+
if (!readyGate.isReady) {
|
|
2947
|
+
readyGate.open(currentError);
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2833
2950
|
async function discoverHMRAssets() {
|
|
2834
2951
|
try {
|
|
2835
2952
|
const res = await fetch(`http://${host}:${server?.port}/__vertz_hmr`);
|
|
@@ -2927,6 +3044,19 @@ data: {}
|
|
|
2927
3044
|
}
|
|
2928
3045
|
if (stopped)
|
|
2929
3046
|
return;
|
|
3047
|
+
if (ssrFallback) {
|
|
3048
|
+
if (onRestartNeeded) {
|
|
3049
|
+
if (logRequests) {
|
|
3050
|
+
console.log("[Server] SSR in fallback mode \u2014 requesting process restart");
|
|
3051
|
+
}
|
|
3052
|
+
await devServer.stop();
|
|
3053
|
+
onRestartNeeded();
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
if (logRequests) {
|
|
3057
|
+
console.log("[Server] SSR in fallback mode \u2014 attempting re-import (best effort)");
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
2930
3060
|
const cacheCleared = clearSSRRequireCache();
|
|
2931
3061
|
logger.log("watcher", "cache-cleared", { entries: cacheCleared });
|
|
2932
3062
|
const ssrWrapperPath = resolve(devDir, "ssr-reload-entry.ts");
|
|
@@ -2937,6 +3067,7 @@ data: {}
|
|
|
2937
3067
|
try {
|
|
2938
3068
|
const freshMod = await import(`${ssrWrapperPath}?t=${Date.now()}`);
|
|
2939
3069
|
ssrMod = freshMod;
|
|
3070
|
+
ssrFallback = false;
|
|
2940
3071
|
if (freshMod.theme?.fonts) {
|
|
2941
3072
|
try {
|
|
2942
3073
|
fontFallbackMetrics = await extractFontMetrics(freshMod.theme.fonts, projectRoot);
|
|
@@ -2962,6 +3093,7 @@ data: {}
|
|
|
2962
3093
|
try {
|
|
2963
3094
|
const freshMod = await import(`${ssrWrapperPath}?t=${Date.now()}`);
|
|
2964
3095
|
ssrMod = freshMod;
|
|
3096
|
+
ssrFallback = false;
|
|
2965
3097
|
if (freshMod.theme?.fonts) {
|
|
2966
3098
|
try {
|
|
2967
3099
|
fontFallbackMetrics = await extractFontMetrics(freshMod.theme.fonts, projectRoot);
|
|
@@ -2982,6 +3114,7 @@ data: {}
|
|
|
2982
3114
|
logger.log("watcher", "ssr-reload", { status: "failed", error: errMsg });
|
|
2983
3115
|
const { message: _m, ...loc2 } = errStack ? parseSourceFromStack(errStack) : { message: "" };
|
|
2984
3116
|
broadcastError("ssr", [{ message: errMsg, ...loc2, stack: errStack }]);
|
|
3117
|
+
ssrFallback = true;
|
|
2985
3118
|
}
|
|
2986
3119
|
}
|
|
2987
3120
|
}, 100);
|
|
@@ -3048,6 +3181,7 @@ data: {}
|
|
|
3048
3181
|
lastBroadcastedError = "";
|
|
3049
3182
|
lastChangedFile = "";
|
|
3050
3183
|
clearGraceUntil = 0;
|
|
3184
|
+
ssrFallback = false;
|
|
3051
3185
|
terminalDedup.reset();
|
|
3052
3186
|
clearSSRRequireCache();
|
|
3053
3187
|
sourceMapResolver.invalidate();
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
captureDOMState,
|
|
4
4
|
restoreDOMState
|
|
5
|
-
} from "../shared/chunk-
|
|
5
|
+
} from "../shared/chunk-eenfpa59.js";
|
|
6
6
|
import"../shared/chunk-eb80r8e8.js";
|
|
7
7
|
|
|
8
8
|
// src/bun-plugin/fast-refresh-runtime.ts
|
|
@@ -40,9 +40,10 @@ function __$refreshReg(moduleId, name, factory, hash) {
|
|
|
40
40
|
return;
|
|
41
41
|
existing.factory = factory;
|
|
42
42
|
existing.hash = hash;
|
|
43
|
+
existing.dirty = true;
|
|
43
44
|
dirtyModules.add(moduleId);
|
|
44
45
|
} else {
|
|
45
|
-
mod.set(name, { factory, instances: [], hash });
|
|
46
|
+
mod.set(name, { factory, instances: [], hash, dirty: false });
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
function __$refreshTrack(moduleId, name, element, args, cleanups, contextScope, signals = []) {
|
|
@@ -68,6 +69,9 @@ function __$refreshPerform(moduleId) {
|
|
|
68
69
|
return;
|
|
69
70
|
performingRefresh = true;
|
|
70
71
|
for (const [name, record] of mod) {
|
|
72
|
+
if (!record.dirty)
|
|
73
|
+
continue;
|
|
74
|
+
record.dirty = false;
|
|
71
75
|
const { factory, instances } = record;
|
|
72
76
|
const updatedInstances = [];
|
|
73
77
|
for (const instance of instances) {
|
package/dist/bun-plugin/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
transformRouteSplitting
|
|
23
23
|
} from "@vertz/ui-compiler";
|
|
24
24
|
import MagicString3 from "magic-string";
|
|
25
|
-
import { Project as Project2, ts as
|
|
25
|
+
import { Project as Project2, ts as ts5 } from "ts-morph";
|
|
26
26
|
|
|
27
27
|
// src/bun-plugin/context-stable-ids.ts
|
|
28
28
|
import { ts } from "ts-morph";
|
|
@@ -72,19 +72,18 @@ function loadEntitySchema(schemaPath) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// src/bun-plugin/fast-refresh-codegen.ts
|
|
75
|
-
function generateRefreshPreamble(moduleId
|
|
75
|
+
function generateRefreshPreamble(moduleId) {
|
|
76
76
|
const escapedId = moduleId.replace(/['\\]/g, "\\$&");
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const noop = "() => {}";
|
|
78
|
+
const noopArr = "() => []";
|
|
79
|
+
const noopNull = "() => null";
|
|
80
|
+
const noopPassthrough = "(_m, _n, el) => el";
|
|
81
|
+
return `const __$fr = globalThis[Symbol.for('vertz:fast-refresh')] ?? {};
|
|
82
|
+
` + `const { ` + `__$refreshReg = ${noop}, ` + `__$refreshTrack = ${noopPassthrough}, ` + `__$refreshPerform = ${noop}, ` + `pushScope: __$pushScope = ${noopArr}, ` + `popScope: __$popScope = ${noop}, ` + `_tryOnCleanup: __$tryCleanup = ${noop}, ` + `runCleanups: __$runCleanups = ${noop}, ` + `getContextScope: __$getCtx = ${noopNull}, ` + `setContextScope: __$setCtx = ${noopNull}, ` + `startSignalCollection: __$startSigCol = ${noop}, ` + `stopSignalCollection: __$stopSigCol = ${noopArr} } = __$fr;
|
|
79
83
|
` + `const __$moduleId = '${escapedId}';
|
|
80
84
|
`;
|
|
81
|
-
if (contentHash) {
|
|
82
|
-
code += `const __$moduleHash = '${contentHash}';
|
|
83
|
-
`;
|
|
84
|
-
}
|
|
85
|
-
return code;
|
|
86
85
|
}
|
|
87
|
-
function generateRefreshWrapper(componentName) {
|
|
86
|
+
function generateRefreshWrapper(componentName, componentHash) {
|
|
88
87
|
return `
|
|
89
88
|
const __$orig_${componentName} = ${componentName};
|
|
90
89
|
` + `${componentName} = function(...__$args) {
|
|
@@ -99,20 +98,22 @@ const __$orig_${componentName} = ${componentName};
|
|
|
99
98
|
` + ` }
|
|
100
99
|
` + ` return __$refreshTrack(__$moduleId, '${componentName}', __$ret, __$args, __$scope, __$ctx, __$sigs);
|
|
101
100
|
` + `};
|
|
102
|
-
` + `__$refreshReg(__$moduleId, '${componentName}', ${componentName},
|
|
101
|
+
` + `__$refreshReg(__$moduleId, '${componentName}', ${componentName}, '${componentHash}');
|
|
103
102
|
`;
|
|
104
103
|
}
|
|
105
104
|
function generateRefreshPerform() {
|
|
106
105
|
return `__$refreshPerform(__$moduleId);
|
|
107
106
|
`;
|
|
108
107
|
}
|
|
109
|
-
function generateRefreshCode(moduleId, components,
|
|
108
|
+
function generateRefreshCode(moduleId, components, source) {
|
|
110
109
|
if (components.length === 0)
|
|
111
110
|
return null;
|
|
112
|
-
const preamble = generateRefreshPreamble(moduleId
|
|
111
|
+
const preamble = generateRefreshPreamble(moduleId);
|
|
113
112
|
let epilogue = "";
|
|
114
113
|
for (const comp of components) {
|
|
115
|
-
|
|
114
|
+
const body = source.slice(comp.bodyStart, comp.bodyEnd);
|
|
115
|
+
const hash = Bun.hash(body).toString(36);
|
|
116
|
+
epilogue += generateRefreshWrapper(comp.name, hash);
|
|
116
117
|
}
|
|
117
118
|
epilogue += generateRefreshPerform();
|
|
118
119
|
return { preamble, epilogue };
|
|
@@ -267,6 +268,8 @@ function resolveCrossFileFields(filePath, propFlows, options) {
|
|
|
267
268
|
if (childFields.hasOpaqueAccess) {
|
|
268
269
|
hasOpaqueAccess = true;
|
|
269
270
|
}
|
|
271
|
+
} else {
|
|
272
|
+
hasOpaqueAccess = true;
|
|
270
273
|
}
|
|
271
274
|
}
|
|
272
275
|
return { fields, hasOpaqueAccess };
|
|
@@ -274,9 +277,33 @@ function resolveCrossFileFields(filePath, propFlows, options) {
|
|
|
274
277
|
|
|
275
278
|
// src/bun-plugin/field-selection-manifest.ts
|
|
276
279
|
import { analyzeComponentPropFields } from "@vertz/ui-compiler";
|
|
280
|
+
import { ts as ts2 } from "ts-morph";
|
|
281
|
+
var RE_EXPORT_PATTERN = /export\s+(?:\{|\*)\s*.*?\bfrom\b/;
|
|
282
|
+
function parseReExports(sourceText, filePath) {
|
|
283
|
+
if (!RE_EXPORT_PATTERN.test(sourceText))
|
|
284
|
+
return [];
|
|
285
|
+
const sourceFile = ts2.createSourceFile(filePath, sourceText, ts2.ScriptTarget.Latest, true);
|
|
286
|
+
const reExports = [];
|
|
287
|
+
for (const stmt of sourceFile.statements) {
|
|
288
|
+
if (!ts2.isExportDeclaration(stmt) || !stmt.moduleSpecifier)
|
|
289
|
+
continue;
|
|
290
|
+
const source = stmt.moduleSpecifier.getText(sourceFile).replace(/^['"]|['"]$/g, "");
|
|
291
|
+
if (!stmt.exportClause) {
|
|
292
|
+
reExports.push({ name: "*", originalName: "*", source });
|
|
293
|
+
} else if (ts2.isNamedExports(stmt.exportClause)) {
|
|
294
|
+
for (const el of stmt.exportClause.elements) {
|
|
295
|
+
const exportedName = el.name.getText(sourceFile);
|
|
296
|
+
const originalName = el.propertyName ? el.propertyName.getText(sourceFile) : exportedName;
|
|
297
|
+
reExports.push({ name: exportedName, originalName, source });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return reExports;
|
|
302
|
+
}
|
|
277
303
|
|
|
278
304
|
class FieldSelectionManifest {
|
|
279
305
|
fileComponents = new Map;
|
|
306
|
+
fileReExports = new Map;
|
|
280
307
|
importResolver = () => {
|
|
281
308
|
return;
|
|
282
309
|
};
|
|
@@ -287,30 +314,68 @@ class FieldSelectionManifest {
|
|
|
287
314
|
registerFile(filePath, sourceText) {
|
|
288
315
|
const components = analyzeComponentPropFields(filePath, sourceText);
|
|
289
316
|
this.fileComponents.set(filePath, components);
|
|
317
|
+
const reExports = parseReExports(sourceText, filePath);
|
|
318
|
+
this.fileReExports.set(filePath, reExports);
|
|
290
319
|
this.resolvedCache.clear();
|
|
291
320
|
}
|
|
292
321
|
updateFile(filePath, sourceText) {
|
|
293
322
|
const oldComponents = this.fileComponents.get(filePath);
|
|
294
323
|
const newComponents = analyzeComponentPropFields(filePath, sourceText);
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
324
|
+
const componentsChanged = !componentsEqual(oldComponents, newComponents);
|
|
325
|
+
if (componentsChanged) {
|
|
297
326
|
this.fileComponents.set(filePath, newComponents);
|
|
327
|
+
}
|
|
328
|
+
const oldReExports = this.fileReExports.get(filePath);
|
|
329
|
+
const newReExports = parseReExports(sourceText, filePath);
|
|
330
|
+
const reExportsChanged = !reExportsEqual(oldReExports, newReExports);
|
|
331
|
+
if (reExportsChanged) {
|
|
332
|
+
this.fileReExports.set(filePath, newReExports);
|
|
333
|
+
}
|
|
334
|
+
const changed = componentsChanged || reExportsChanged;
|
|
335
|
+
if (changed) {
|
|
298
336
|
this.resolvedCache.clear();
|
|
299
337
|
}
|
|
300
338
|
return { changed };
|
|
301
339
|
}
|
|
302
340
|
deleteFile(filePath) {
|
|
303
341
|
this.fileComponents.delete(filePath);
|
|
342
|
+
this.fileReExports.delete(filePath);
|
|
304
343
|
this.resolvedCache.clear();
|
|
305
344
|
}
|
|
306
345
|
getComponentPropFields(filePath, componentName, propName) {
|
|
307
346
|
const components = this.fileComponents.get(filePath);
|
|
308
|
-
if (
|
|
347
|
+
if (components) {
|
|
348
|
+
const component = components.find((c) => c.componentName === componentName);
|
|
349
|
+
if (component)
|
|
350
|
+
return component.props[propName];
|
|
351
|
+
}
|
|
352
|
+
return this.followReExports(filePath, componentName, propName, new Set);
|
|
353
|
+
}
|
|
354
|
+
followReExports(filePath, componentName, propName, visited) {
|
|
355
|
+
if (visited.has(filePath))
|
|
309
356
|
return;
|
|
310
|
-
|
|
311
|
-
|
|
357
|
+
visited.add(filePath);
|
|
358
|
+
const reExports = this.fileReExports.get(filePath);
|
|
359
|
+
if (!reExports)
|
|
312
360
|
return;
|
|
313
|
-
|
|
361
|
+
for (const re of reExports) {
|
|
362
|
+
if (re.name !== componentName && re.name !== "*")
|
|
363
|
+
continue;
|
|
364
|
+
const targetPath = this.importResolver(re.source, filePath);
|
|
365
|
+
if (!targetPath)
|
|
366
|
+
continue;
|
|
367
|
+
const targetName = re.name === "*" ? componentName : re.originalName;
|
|
368
|
+
const targetComponents = this.fileComponents.get(targetPath);
|
|
369
|
+
if (targetComponents) {
|
|
370
|
+
const component = targetComponents.find((c) => c.componentName === targetName);
|
|
371
|
+
if (component)
|
|
372
|
+
return component.props[propName];
|
|
373
|
+
}
|
|
374
|
+
const result = this.followReExports(targetPath, targetName, propName, visited);
|
|
375
|
+
if (result)
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
return;
|
|
314
379
|
}
|
|
315
380
|
getResolvedPropFields(filePath, componentName, propName) {
|
|
316
381
|
const cacheKey = `${filePath}::${componentName}::${propName}`;
|
|
@@ -383,10 +448,37 @@ function componentsEqual(a, b) {
|
|
|
383
448
|
if (aFieldsSorted[k] !== bFieldsSorted[k])
|
|
384
449
|
return false;
|
|
385
450
|
}
|
|
451
|
+
if (aProp.forwarded.length !== bProp.forwarded.length)
|
|
452
|
+
return false;
|
|
453
|
+
for (let f = 0;f < aProp.forwarded.length; f++) {
|
|
454
|
+
const af = aProp.forwarded[f];
|
|
455
|
+
const bf = bProp.forwarded[f];
|
|
456
|
+
if (af.componentName !== bf.componentName)
|
|
457
|
+
return false;
|
|
458
|
+
if (af.importSource !== bf.importSource)
|
|
459
|
+
return false;
|
|
460
|
+
if (af.propName !== bf.propName)
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
386
463
|
}
|
|
387
464
|
}
|
|
388
465
|
return true;
|
|
389
466
|
}
|
|
467
|
+
function reExportsEqual(a, b) {
|
|
468
|
+
if (!a)
|
|
469
|
+
return b.length === 0;
|
|
470
|
+
if (a.length !== b.length)
|
|
471
|
+
return false;
|
|
472
|
+
for (let i = 0;i < a.length; i++) {
|
|
473
|
+
if (a[i].name !== b[i].name)
|
|
474
|
+
return false;
|
|
475
|
+
if (a[i].originalName !== b[i].originalName)
|
|
476
|
+
return false;
|
|
477
|
+
if (a[i].source !== b[i].source)
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
390
482
|
|
|
391
483
|
// src/bun-plugin/file-path-hash.ts
|
|
392
484
|
function filePathHash(filePath) {
|
|
@@ -461,7 +553,7 @@ async function processImage(opts) {
|
|
|
461
553
|
|
|
462
554
|
// src/bun-plugin/image-transform.ts
|
|
463
555
|
import MagicString2 from "magic-string";
|
|
464
|
-
import { Project, ts as
|
|
556
|
+
import { Project, ts as ts3 } from "ts-morph";
|
|
465
557
|
function escapeAttr(value) {
|
|
466
558
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
467
559
|
}
|
|
@@ -535,13 +627,13 @@ function findImageImportName(source) {
|
|
|
535
627
|
function findImageJsxElements(sourceFile, localName) {
|
|
536
628
|
const results = [];
|
|
537
629
|
function visit(node) {
|
|
538
|
-
if (
|
|
630
|
+
if (ts3.isJsxSelfClosingElement(node)) {
|
|
539
631
|
const tagName = node.tagName.getText(sourceFile.compilerNode);
|
|
540
632
|
if (tagName === localName) {
|
|
541
633
|
results.push(node);
|
|
542
634
|
}
|
|
543
635
|
}
|
|
544
|
-
|
|
636
|
+
ts3.forEachChild(node, visit);
|
|
545
637
|
}
|
|
546
638
|
visit(sourceFile.compilerNode);
|
|
547
639
|
return results;
|
|
@@ -549,7 +641,7 @@ function findImageJsxElements(sourceFile, localName) {
|
|
|
549
641
|
function extractStaticProps(element, sourceFile) {
|
|
550
642
|
const attrs = element.attributes;
|
|
551
643
|
for (const attr of attrs.properties) {
|
|
552
|
-
if (
|
|
644
|
+
if (ts3.isJsxSpreadAttribute(attr))
|
|
553
645
|
return null;
|
|
554
646
|
}
|
|
555
647
|
let src = null;
|
|
@@ -582,7 +674,7 @@ function extractStaticProps(element, sourceFile) {
|
|
|
582
674
|
"fit"
|
|
583
675
|
]);
|
|
584
676
|
for (const attr of attrs.properties) {
|
|
585
|
-
if (!
|
|
677
|
+
if (!ts3.isJsxAttribute(attr))
|
|
586
678
|
continue;
|
|
587
679
|
const name = attr.name.getText(sourceFile.compilerNode);
|
|
588
680
|
const value = attr.initializer;
|
|
@@ -686,15 +778,15 @@ function extractStaticProps(element, sourceFile) {
|
|
|
686
778
|
function extractStaticString(value, _sourceFile) {
|
|
687
779
|
if (!value)
|
|
688
780
|
return null;
|
|
689
|
-
if (
|
|
781
|
+
if (ts3.isStringLiteral(value)) {
|
|
690
782
|
return value.text;
|
|
691
783
|
}
|
|
692
|
-
if (
|
|
784
|
+
if (ts3.isJsxExpression(value) && value.expression) {
|
|
693
785
|
const expr = value.expression;
|
|
694
|
-
if (
|
|
786
|
+
if (ts3.isStringLiteral(expr)) {
|
|
695
787
|
return expr.text;
|
|
696
788
|
}
|
|
697
|
-
if (
|
|
789
|
+
if (ts3.isNoSubstitutionTemplateLiteral(expr)) {
|
|
698
790
|
return expr.text;
|
|
699
791
|
}
|
|
700
792
|
}
|
|
@@ -703,9 +795,9 @@ function extractStaticString(value, _sourceFile) {
|
|
|
703
795
|
function extractStaticNumber(value, _sourceFile) {
|
|
704
796
|
if (!value)
|
|
705
797
|
return null;
|
|
706
|
-
if (
|
|
798
|
+
if (ts3.isJsxExpression(value) && value.expression) {
|
|
707
799
|
const expr = value.expression;
|
|
708
|
-
if (
|
|
800
|
+
if (ts3.isNumericLiteral(expr)) {
|
|
709
801
|
return Number(expr.text);
|
|
710
802
|
}
|
|
711
803
|
}
|
|
@@ -714,18 +806,18 @@ function extractStaticNumber(value, _sourceFile) {
|
|
|
714
806
|
function extractStaticBoolean(value, _sourceFile) {
|
|
715
807
|
if (!value)
|
|
716
808
|
return null;
|
|
717
|
-
if (
|
|
809
|
+
if (ts3.isJsxExpression(value) && value.expression) {
|
|
718
810
|
const expr = value.expression;
|
|
719
|
-
if (expr.kind ===
|
|
811
|
+
if (expr.kind === ts3.SyntaxKind.TrueKeyword)
|
|
720
812
|
return true;
|
|
721
|
-
if (expr.kind ===
|
|
813
|
+
if (expr.kind === ts3.SyntaxKind.FalseKeyword)
|
|
722
814
|
return false;
|
|
723
815
|
}
|
|
724
816
|
return null;
|
|
725
817
|
}
|
|
726
818
|
|
|
727
819
|
// src/bun-plugin/island-id-inject.ts
|
|
728
|
-
import { ts as
|
|
820
|
+
import { ts as ts4 } from "ts-morph";
|
|
729
821
|
function injectIslandIds(source, sourceFile, relFilePath) {
|
|
730
822
|
const originalSource = source.original;
|
|
731
823
|
if (!originalSource.includes("<Island") && !originalSource.includes("Island")) {
|
|
@@ -759,20 +851,20 @@ function findIslandImportName(source) {
|
|
|
759
851
|
function findIslandJsxElements(sourceFile, localName) {
|
|
760
852
|
const results = [];
|
|
761
853
|
function visit(node) {
|
|
762
|
-
if (
|
|
854
|
+
if (ts4.isJsxSelfClosingElement(node)) {
|
|
763
855
|
const tagName = node.tagName.getText(sourceFile.compilerNode);
|
|
764
856
|
if (tagName === localName) {
|
|
765
857
|
results.push(node);
|
|
766
858
|
}
|
|
767
859
|
}
|
|
768
|
-
|
|
860
|
+
ts4.forEachChild(node, visit);
|
|
769
861
|
}
|
|
770
862
|
visit(sourceFile.compilerNode);
|
|
771
863
|
return results;
|
|
772
864
|
}
|
|
773
865
|
function hasIdProp(element, sourceFile) {
|
|
774
866
|
for (const attr of element.attributes.properties) {
|
|
775
|
-
if (
|
|
867
|
+
if (ts4.isJsxAttribute(attr)) {
|
|
776
868
|
const name = attr.name.getText(sourceFile.compilerNode);
|
|
777
869
|
if (name === "id")
|
|
778
870
|
return true;
|
|
@@ -782,7 +874,7 @@ function hasIdProp(element, sourceFile) {
|
|
|
782
874
|
}
|
|
783
875
|
function extractComponentName(element, sourceFile) {
|
|
784
876
|
for (const attr of element.attributes.properties) {
|
|
785
|
-
if (!
|
|
877
|
+
if (!ts4.isJsxAttribute(attr))
|
|
786
878
|
continue;
|
|
787
879
|
const name = attr.name.getText(sourceFile.compilerNode);
|
|
788
880
|
if (name !== "component")
|
|
@@ -790,8 +882,8 @@ function extractComponentName(element, sourceFile) {
|
|
|
790
882
|
const value = attr.initializer;
|
|
791
883
|
if (!value)
|
|
792
884
|
return null;
|
|
793
|
-
if (
|
|
794
|
-
if (
|
|
885
|
+
if (ts4.isJsxExpression(value) && value.expression) {
|
|
886
|
+
if (ts4.isIdentifier(value.expression)) {
|
|
795
887
|
return value.expression.text;
|
|
796
888
|
}
|
|
797
889
|
}
|
|
@@ -896,7 +988,7 @@ function createVertzBunPlugin(options) {
|
|
|
896
988
|
fieldSelectionManifest.setImportResolver(fieldSelectionResolveImport);
|
|
897
989
|
let fieldSelectionFileCount = 0;
|
|
898
990
|
for (const [filePath] of manifests) {
|
|
899
|
-
if (filePath.endsWith(".tsx")) {
|
|
991
|
+
if (filePath.endsWith(".tsx") || filePath.endsWith(".ts")) {
|
|
900
992
|
try {
|
|
901
993
|
const sourceText = readFileSync3(filePath, "utf-8");
|
|
902
994
|
fieldSelectionManifest.registerFile(filePath, sourceText);
|
|
@@ -953,7 +1045,7 @@ function createVertzBunPlugin(options) {
|
|
|
953
1045
|
const hydrationProject = new Project2({
|
|
954
1046
|
useInMemoryFileSystem: true,
|
|
955
1047
|
compilerOptions: {
|
|
956
|
-
jsx:
|
|
1048
|
+
jsx: ts5.JsxEmit.Preserve,
|
|
957
1049
|
strict: true
|
|
958
1050
|
}
|
|
959
1051
|
});
|
|
@@ -1066,8 +1158,7 @@ function createVertzBunPlugin(options) {
|
|
|
1066
1158
|
let refreshEpilogue = "";
|
|
1067
1159
|
if (fastRefresh) {
|
|
1068
1160
|
const components = componentAnalyzer.analyze(hydrationSourceFile);
|
|
1069
|
-
const
|
|
1070
|
-
const refreshCode = generateRefreshCode(args.path, components, contentHash);
|
|
1161
|
+
const refreshCode = generateRefreshCode(args.path, components, source);
|
|
1071
1162
|
if (refreshCode) {
|
|
1072
1163
|
refreshPreamble = refreshCode.preamble;
|
|
1073
1164
|
refreshEpilogue = refreshCode.epilogue;
|
|
@@ -1094,7 +1185,7 @@ function createVertzBunPlugin(options) {
|
|
|
1094
1185
|
}
|
|
1095
1186
|
if (hmr) {
|
|
1096
1187
|
contents += `
|
|
1097
|
-
import.meta.hot.accept();
|
|
1188
|
+
if (import.meta.hot) import.meta.hot.accept();
|
|
1098
1189
|
`;
|
|
1099
1190
|
}
|
|
1100
1191
|
contents += sourceMapComment;
|
|
@@ -1164,7 +1255,7 @@ import.meta.hot.accept();
|
|
|
1164
1255
|
if (changed) {
|
|
1165
1256
|
manifestsRecord = null;
|
|
1166
1257
|
}
|
|
1167
|
-
if (filePath.endsWith(".tsx")) {
|
|
1258
|
+
if (filePath.endsWith(".tsx") || filePath.endsWith(".ts")) {
|
|
1168
1259
|
fieldSelectionManifest.updateFile(filePath, sourceText);
|
|
1169
1260
|
}
|
|
1170
1261
|
if (logger?.isEnabled("manifest")) {
|
package/dist/dom-shim/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
ssrDiscoverQueries,
|
|
20
20
|
ssrRenderToString,
|
|
21
21
|
streamToString
|
|
22
|
-
} from "./shared/chunk-
|
|
22
|
+
} from "./shared/chunk-g0zqrb60.js";
|
|
23
23
|
import {
|
|
24
24
|
clearGlobalSSRTimeout,
|
|
25
25
|
createSSRAdapter,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
registerSSRQuery,
|
|
32
32
|
setGlobalSSRTimeout,
|
|
33
33
|
ssrStorage
|
|
34
|
-
} from "./shared/chunk-
|
|
34
|
+
} from "./shared/chunk-zs75v8qj.js";
|
|
35
35
|
|
|
36
36
|
// src/asset-pipeline.ts
|
|
37
37
|
function renderAssetTags(assets) {
|
|
@@ -7,17 +7,28 @@ function captureDOMState(element) {
|
|
|
7
7
|
scrollPositions: captureScrollPositions(element)
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
+
function formFieldKey(el, index) {
|
|
11
|
+
const name = el.getAttribute("name");
|
|
12
|
+
if (name)
|
|
13
|
+
return `name:${name}`;
|
|
14
|
+
const id = el.getAttribute("id");
|
|
15
|
+
if (id)
|
|
16
|
+
return `id:${id}`;
|
|
17
|
+
const placeholder = el.getAttribute("placeholder");
|
|
18
|
+
if (placeholder)
|
|
19
|
+
return `placeholder:${placeholder}`;
|
|
20
|
+
return `pos:${el.tagName.toLowerCase()}:${index}`;
|
|
21
|
+
}
|
|
10
22
|
function captureFormFields(element) {
|
|
11
23
|
const fields = new Map;
|
|
12
24
|
const inputs = element.querySelectorAll("input, textarea, select");
|
|
13
|
-
for (
|
|
14
|
-
const
|
|
15
|
-
if (!name)
|
|
16
|
-
continue;
|
|
25
|
+
for (let i = 0;i < inputs.length; i++) {
|
|
26
|
+
const el = inputs[i];
|
|
17
27
|
const type = el.type ?? "";
|
|
18
28
|
if (type === "file")
|
|
19
29
|
continue;
|
|
20
|
-
|
|
30
|
+
const key = formFieldKey(el, i);
|
|
31
|
+
fields.set(key, {
|
|
21
32
|
value: el.value ?? "",
|
|
22
33
|
checked: el.checked ?? false,
|
|
23
34
|
selectedIndex: el.selectedIndex ?? -1,
|
|
@@ -87,11 +98,10 @@ function restoreFormFields(element, fields) {
|
|
|
87
98
|
if (fields.size === 0)
|
|
88
99
|
return;
|
|
89
100
|
const inputs = element.querySelectorAll("input, textarea, select");
|
|
90
|
-
for (
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const saved = fields.get(name);
|
|
101
|
+
for (let i = 0;i < inputs.length; i++) {
|
|
102
|
+
const el = inputs[i];
|
|
103
|
+
const key = formFieldKey(el, i);
|
|
104
|
+
const saved = fields.get(key);
|
|
95
105
|
if (!saved)
|
|
96
106
|
continue;
|
|
97
107
|
if (saved.type === "file")
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
setGlobalSSRTimeout,
|
|
7
7
|
ssrStorage,
|
|
8
8
|
toVNode
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-zs75v8qj.js";
|
|
10
10
|
|
|
11
11
|
// src/html-serializer.ts
|
|
12
12
|
var VOID_ELEMENTS = new Set([
|
|
@@ -51,6 +51,9 @@ function serializeToHtml(node) {
|
|
|
51
51
|
return node.html;
|
|
52
52
|
}
|
|
53
53
|
const { tag, attrs, children } = node;
|
|
54
|
+
if (tag === "fragment") {
|
|
55
|
+
return children.map((child) => serializeToHtml(child)).join("");
|
|
56
|
+
}
|
|
54
57
|
const attrStr = serializeAttrs(attrs);
|
|
55
58
|
if (VOID_ELEMENTS.has(tag)) {
|
|
56
59
|
return `<${tag}${attrStr}>`;
|
|
@@ -141,6 +144,9 @@ function renderToStream(tree, options) {
|
|
|
141
144
|
return serializeToHtml(placeholder);
|
|
142
145
|
}
|
|
143
146
|
const { tag, attrs, children } = node;
|
|
147
|
+
if (tag === "fragment") {
|
|
148
|
+
return children.map((child) => walkAndSerialize(child)).join("");
|
|
149
|
+
}
|
|
144
150
|
const isRawText = RAW_TEXT_ELEMENTS.has(tag);
|
|
145
151
|
const attrStr = Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeAttr(v)}"`).join("");
|
|
146
152
|
if (VOID_ELEMENTS.has(tag)) {
|
|
@@ -568,19 +568,35 @@ function installDomShim() {
|
|
|
568
568
|
cookie: ""
|
|
569
569
|
};
|
|
570
570
|
globalThis.document = fakeDocument;
|
|
571
|
+
const windowStubs = {
|
|
572
|
+
scrollTo: () => {},
|
|
573
|
+
scroll: () => {},
|
|
574
|
+
addEventListener: () => {},
|
|
575
|
+
removeEventListener: () => {},
|
|
576
|
+
dispatchEvent: () => true,
|
|
577
|
+
getComputedStyle: () => ({}),
|
|
578
|
+
matchMedia: () => ({ matches: false, addListener: () => {}, removeListener: () => {} })
|
|
579
|
+
};
|
|
571
580
|
if (typeof window === "undefined") {
|
|
572
581
|
globalThis.window = {
|
|
573
582
|
location: { pathname: ssrStorage.getStore()?.url || "/", search: "", hash: "" },
|
|
574
583
|
history: {
|
|
575
584
|
pushState: () => {},
|
|
576
585
|
replaceState: () => {}
|
|
577
|
-
}
|
|
586
|
+
},
|
|
587
|
+
...windowStubs
|
|
578
588
|
};
|
|
579
589
|
} else {
|
|
580
|
-
globalThis.window
|
|
581
|
-
|
|
590
|
+
const win = globalThis.window;
|
|
591
|
+
win.location = {
|
|
592
|
+
...win.location || {},
|
|
582
593
|
pathname: ssrStorage.getStore()?.url || "/"
|
|
583
594
|
};
|
|
595
|
+
for (const [key, val] of Object.entries(windowStubs)) {
|
|
596
|
+
if (typeof win[key] !== "function") {
|
|
597
|
+
win[key] = val;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
584
600
|
}
|
|
585
601
|
globalThis.Node = SSRNode;
|
|
586
602
|
globalThis.HTMLElement = SSRElement;
|
package/dist/ssr/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
injectIntoTemplate,
|
|
4
4
|
ssrDiscoverQueries,
|
|
5
5
|
ssrRenderToString
|
|
6
|
-
} from "../shared/chunk-
|
|
7
|
-
import"../shared/chunk-
|
|
6
|
+
} from "../shared/chunk-g0zqrb60.js";
|
|
7
|
+
import"../shared/chunk-zs75v8qj.js";
|
|
8
8
|
|
|
9
9
|
// src/prerender.ts
|
|
10
10
|
async function discoverRoutes(module) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertz/ui-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Vertz UI server-side rendering runtime",
|
|
@@ -58,15 +58,15 @@
|
|
|
58
58
|
"@ampproject/remapping": "^2.3.0",
|
|
59
59
|
"@capsizecss/unpack": "^4.0.0",
|
|
60
60
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
61
|
-
"@vertz/core": "^0.2.
|
|
62
|
-
"@vertz/ui": "^0.2.
|
|
63
|
-
"@vertz/ui-compiler": "^0.2.
|
|
61
|
+
"@vertz/core": "^0.2.23",
|
|
62
|
+
"@vertz/ui": "^0.2.23",
|
|
63
|
+
"@vertz/ui-compiler": "^0.2.23",
|
|
64
64
|
"magic-string": "^0.30.0",
|
|
65
65
|
"sharp": "^0.34.5",
|
|
66
66
|
"ts-morph": "^27.0.2"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@vertz/codegen": "^0.2.
|
|
69
|
+
"@vertz/codegen": "^0.2.23",
|
|
70
70
|
"@vertz/ui-auth": "^0.2.19",
|
|
71
71
|
"bun-types": "^1.3.10",
|
|
72
72
|
"bunup": "^0.16.31",
|