@vertz/ui-server 0.2.38 → 0.2.41
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.js +356 -45
- package/dist/index.d.ts +38 -3
- package/dist/index.js +153 -9
- package/dist/node-handler.d.ts +7 -1
- package/dist/node-handler.js +2 -2
- package/dist/shared/{chunk-2ymwre0k.js → chunk-15kac8x8.js} +194 -24
- package/dist/shared/{chunk-d1a3ygv6.js → chunk-gqvkycnj.js} +5 -3
- package/dist/shared/{chunk-595trxsn.js → chunk-j18fewkf.js} +19 -4
- package/dist/ssr/index.d.ts +7 -1
- package/dist/ssr/index.js +2 -2
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -281,6 +281,8 @@ interface SSRAotContext {
|
|
|
281
281
|
session: PrefetchSession | undefined;
|
|
282
282
|
/** Route params for the current request. */
|
|
283
283
|
params: Record<string, string>;
|
|
284
|
+
/** URL search params for the current request (used by AOT functions with ${sp:name} keys). */
|
|
285
|
+
searchParams: URLSearchParams | undefined;
|
|
284
286
|
}
|
|
285
287
|
/** An AOT render function: takes props/data and context, returns HTML string. */
|
|
286
288
|
type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
|
|
@@ -292,6 +294,8 @@ interface AotRouteEntry {
|
|
|
292
294
|
holes: string[];
|
|
293
295
|
/** Query cache keys this route reads via ctx.getData(). */
|
|
294
296
|
queryKeys?: string[];
|
|
297
|
+
/** Pre-filtered CSS rules for this route, determined at build time (#1988). */
|
|
298
|
+
css?: string[];
|
|
295
299
|
}
|
|
296
300
|
/**
|
|
297
301
|
* AOT manifest — maps route patterns to pre-compiled render functions.
|
|
@@ -301,6 +305,8 @@ interface AotRouteEntry {
|
|
|
301
305
|
interface AotManifest {
|
|
302
306
|
/** Route pattern → AOT entry. */
|
|
303
307
|
routes: Record<string, AotRouteEntry>;
|
|
308
|
+
/** Root layout (App) entry — wraps page content via its RouterView hole. */
|
|
309
|
+
app?: AotRouteEntry;
|
|
304
310
|
}
|
|
305
311
|
/**
|
|
306
312
|
* Resolves custom data for AOT-rendered routes.
|
|
@@ -313,7 +319,7 @@ interface AotManifest {
|
|
|
313
319
|
* @param unresolvedKeys - Query keys not yet populated by entity prefetch
|
|
314
320
|
* @returns Map of cache key → data, or empty Map to skip
|
|
315
321
|
*/
|
|
316
|
-
type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[]) => Promise<Map<string, unknown>> | Map<string, unknown>;
|
|
322
|
+
type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[], searchParams?: URLSearchParams) => Promise<Map<string, unknown>> | Map<string, unknown>;
|
|
317
323
|
/** Options for `ssrRenderAot()`. */
|
|
318
324
|
interface SSRRenderAotOptions {
|
|
319
325
|
/** AOT manifest with pre-compiled render functions. */
|
|
@@ -369,6 +375,8 @@ declare function createHoles(holeNames: string[], module: SSRModule, url: string
|
|
|
369
375
|
declare function ssrRenderAot(module: SSRModule, url: string, options: SSRRenderAotOptions): Promise<SSRRenderResult>;
|
|
370
376
|
/** Check if VERTZ_DEBUG includes the 'aot' category. */
|
|
371
377
|
declare function isAotDebugEnabled(): boolean;
|
|
378
|
+
/** Reset the route CSS cache (used when module reloads in dev). */
|
|
379
|
+
declare function clearRouteCssCache(): void;
|
|
372
380
|
import { AccessSet } from "@vertz/ui/auth";
|
|
373
381
|
interface SessionData {
|
|
374
382
|
user: {
|
|
@@ -506,6 +514,8 @@ interface AotCompiledFile {
|
|
|
506
514
|
code: string;
|
|
507
515
|
/** Per-component AOT info from the compilation. */
|
|
508
516
|
components: AotComponentInfo[];
|
|
517
|
+
/** Extracted CSS rule blocks from static css() calls (#1989). */
|
|
518
|
+
css?: string[];
|
|
509
519
|
}
|
|
510
520
|
/** Route map entry for the AOT manifest JSON. */
|
|
511
521
|
interface AotRouteMapEntry {
|
|
@@ -517,12 +527,17 @@ interface AotRouteMapEntry {
|
|
|
517
527
|
queryKeys: string[];
|
|
518
528
|
/** Route param names referenced in queryKeys. Present only when queryKeys have ${...} placeholders. */
|
|
519
529
|
paramBindings?: string[];
|
|
530
|
+
/** Pre-filtered CSS rules for this route, determined at build time (#1988).
|
|
531
|
+
* Includes only rules whose class selectors appear in the component's __ssr_* function. */
|
|
532
|
+
css?: string[];
|
|
520
533
|
}
|
|
521
534
|
interface AotBuildManifest {
|
|
522
535
|
components: Record<string, AotBuildComponentEntry>;
|
|
523
536
|
/** Compiled files keyed by source file path. */
|
|
524
537
|
compiledFiles: Record<string, AotCompiledFile>;
|
|
525
538
|
classificationLog: string[];
|
|
539
|
+
/** Aggregated CSS from all compiled files (#1989). */
|
|
540
|
+
css: string[];
|
|
526
541
|
}
|
|
527
542
|
/**
|
|
528
543
|
* Scan all TSX files in srcDir and generate an AOT build manifest.
|
|
@@ -554,7 +569,27 @@ interface AotBarrelResult {
|
|
|
554
569
|
* Returns the barrel source code and a mapping of temp filenames → compiled code
|
|
555
570
|
* that must be written alongside the barrel for bundling.
|
|
556
571
|
*/
|
|
557
|
-
declare function generateAotBarrel(compiledFiles: Record<string, AotCompiledFile>, routeMap: Record<string, AotRouteMapEntry
|
|
572
|
+
declare function generateAotBarrel(compiledFiles: Record<string, AotCompiledFile>, routeMap: Record<string, AotRouteMapEntry>, appEntry?: AotRouteMapEntry): AotBarrelResult;
|
|
573
|
+
/**
|
|
574
|
+
* Find the root layout (App) component — the one with RouterView as a hole.
|
|
575
|
+
*
|
|
576
|
+
* Returns the component name and its AOT route map entry, or undefined if
|
|
577
|
+
* no component has a RouterView hole or it's a runtime-fallback.
|
|
578
|
+
*/
|
|
579
|
+
declare function findAppComponent(components: Record<string, AotBuildComponentEntry>): AotRouteMapEntry | undefined;
|
|
580
|
+
/**
|
|
581
|
+
* Attach pre-filtered CSS rules to each route entry at build time (#1988, #1989).
|
|
582
|
+
*
|
|
583
|
+
* Transitively collects CSS from the full component tree: the route's own
|
|
584
|
+
* `__ssr_*` function, all local child `__ssr_*` calls it invokes, AND all
|
|
585
|
+
* hole components (imported from other files). This is critical for non-Bun
|
|
586
|
+
* bundlers (esbuild/workerd) where `getInjectedCSS()` doesn't work because
|
|
587
|
+
* `css()` side effects land in a different module instance or are tree-shaken.
|
|
588
|
+
*
|
|
589
|
+
* Also attaches CSS to the app entry (root layout) so the runtime can
|
|
590
|
+
* merge app + route CSS with a simple concat.
|
|
591
|
+
*/
|
|
592
|
+
declare function attachPerRouteCss(compiledFiles: Record<string, AotCompiledFile>, routeMap: Record<string, AotRouteMapEntry>, appEntry?: AotRouteMapEntry): void;
|
|
558
593
|
/**
|
|
559
594
|
* Load AOT manifest and routes module from a server build directory.
|
|
560
595
|
*
|
|
@@ -1158,4 +1193,4 @@ declare function collectStreamChunks(stream: ReadableStream<Uint8Array>): Promis
|
|
|
1158
1193
|
* @param nonce - Optional CSP nonce to add to the inline script tag.
|
|
1159
1194
|
*/
|
|
1160
1195
|
declare function createTemplateChunk(slotId: number, resolvedHtml: string, nonce?: string): string;
|
|
1161
|
-
export { wrapWithHydrationMarkers, toPrefetchSession, streamToString, ssrStorage, ssrRenderToString, ssrRenderSinglePass, ssrRenderAot, ssrDiscoverQueries, setGlobalSSRTimeout, serializeToHtml, safeSerialize, resetSlotCounter, renderToStream, renderToHTMLStream, renderToHTML, renderPage, renderHeadToHtml, renderAssetTags, registerSSRQuery, reconstructDescriptors, rawHtml, matchUrlToPatterns, loadAotManifest, isInSSR, isAotDebugEnabled, inlineCriticalCss, getStreamingRuntimeScript, getSSRUrl, getSSRQueries, getGlobalSSRTimeout, getAccessSetForSSR, generateSSRHtml, generateAotBuildManifest, generateAotBarrel, extractRoutes, extractFontMetrics, evaluateAccessRule, encodeChunk, detectFallbackFont, createTemplateChunk, createSlotPlaceholder, createSessionScript, createSSRHandler, createSSRDataChunk, createSSRAdapter, createPrefetchManifestManager, createNodeHandler, createHoles, createAotManifestManager, createAccessSetScript, collectStreamChunks, clearGlobalSSRTimeout, buildAotRouteMap, __ssr_style_object, __ssr_spread, __esc_attr, __esc, VNode, SessionResolver, SessionData, SerializedAccessRule, SSRSinglePassOptions, SSRSessionInfo, SSRRenderResult, SSRRenderAotOptions, SSRQueryEntry2 as SSRQueryEntry, SSRPrefetchManifest, SSRModule, SSRHandlerOptions, SSRDiscoverResult, SSRAotContext, RenderToStreamOptions, RenderToHTMLStreamOptions, RenderToHTMLOptions, ReconstructedDescriptor, RawHtml, PrefetchSession, PrefetchManifestSnapshot, PrefetchManifestManagerOptions, PrefetchManifestManager, PageOptions, NodeHandlerOptions, MatchedRoute, MatchOptions, HydrationOptions, HeadEntry, HeadCollector, GenerateSSRHtmlOptions, FontFallbackMetrics7 as FontFallbackMetrics, FallbackFontName2 as FallbackFontName, ExtractedRoute, EntityAccessMap, AssetDescriptor, AotTier, AotRouteMapEntry, AotRouteEntry, AotRenderFn, AotManifestSnapshot, AotManifestManagerOptions, AotManifestManager, AotManifest, AotDivergenceEntry, AotDiagnosticsSnapshot, AotDiagnostics, AotDevManifest, AotDevComponentEntry, AotDataResolver, AotComponentDiagnostic, AotCompiledFile, AotBuildManifest, AotBuildComponentEntry, AotBarrelResult };
|
|
1196
|
+
export { wrapWithHydrationMarkers, toPrefetchSession, streamToString, ssrStorage, ssrRenderToString, ssrRenderSinglePass, ssrRenderAot, ssrDiscoverQueries, setGlobalSSRTimeout, serializeToHtml, safeSerialize, resetSlotCounter, renderToStream, renderToHTMLStream, renderToHTML, renderPage, renderHeadToHtml, renderAssetTags, registerSSRQuery, reconstructDescriptors, rawHtml, matchUrlToPatterns, loadAotManifest, isInSSR, isAotDebugEnabled, inlineCriticalCss, getStreamingRuntimeScript, getSSRUrl, getSSRQueries, getGlobalSSRTimeout, getAccessSetForSSR, generateSSRHtml, generateAotBuildManifest, generateAotBarrel, findAppComponent, extractRoutes, extractFontMetrics, evaluateAccessRule, encodeChunk, detectFallbackFont, createTemplateChunk, createSlotPlaceholder, createSessionScript, createSSRHandler, createSSRDataChunk, createSSRAdapter, createPrefetchManifestManager, createNodeHandler, createHoles, createAotManifestManager, createAccessSetScript, collectStreamChunks, clearRouteCssCache, clearGlobalSSRTimeout, buildAotRouteMap, attachPerRouteCss, __ssr_style_object, __ssr_spread, __esc_attr, __esc, VNode, SessionResolver, SessionData, SerializedAccessRule, SSRSinglePassOptions, SSRSessionInfo, SSRRenderResult, SSRRenderAotOptions, SSRQueryEntry2 as SSRQueryEntry, SSRPrefetchManifest, SSRModule, SSRHandlerOptions, SSRDiscoverResult, SSRAotContext, RenderToStreamOptions, RenderToHTMLStreamOptions, RenderToHTMLOptions, ReconstructedDescriptor, RawHtml, PrefetchSession, PrefetchManifestSnapshot, PrefetchManifestManagerOptions, PrefetchManifestManager, PageOptions, NodeHandlerOptions, MatchedRoute, MatchOptions, HydrationOptions, HeadEntry, HeadCollector, GenerateSSRHtmlOptions, FontFallbackMetrics7 as FontFallbackMetrics, FallbackFontName2 as FallbackFontName, ExtractedRoute, EntityAccessMap, AssetDescriptor, AotTier, AotRouteMapEntry, AotRouteEntry, AotRenderFn, AotManifestSnapshot, AotManifestManagerOptions, AotManifestManager, AotManifest, AotDivergenceEntry, AotDiagnosticsSnapshot, AotDiagnostics, AotDevManifest, AotDevComponentEntry, AotDataResolver, AotComponentDiagnostic, AotCompiledFile, AotBuildManifest, AotBuildComponentEntry, AotBarrelResult };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSSRHandler,
|
|
3
3
|
loadAotManifest
|
|
4
|
-
} from "./shared/chunk-
|
|
4
|
+
} from "./shared/chunk-j18fewkf.js";
|
|
5
5
|
import {
|
|
6
6
|
createNodeHandler
|
|
7
|
-
} from "./shared/chunk-
|
|
7
|
+
} from "./shared/chunk-gqvkycnj.js";
|
|
8
8
|
import {
|
|
9
|
+
clearRouteCssCache,
|
|
9
10
|
collectStreamChunks,
|
|
10
11
|
compileThemeCached,
|
|
11
12
|
createAccessSetScript,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
ssrRenderToString,
|
|
35
36
|
streamToString,
|
|
36
37
|
toPrefetchSession
|
|
37
|
-
} from "./shared/chunk-
|
|
38
|
+
} from "./shared/chunk-15kac8x8.js";
|
|
38
39
|
import {
|
|
39
40
|
clearGlobalSSRTimeout,
|
|
40
41
|
createSSRAdapter,
|
|
@@ -59,6 +60,7 @@ function generateAotBuildManifest(srcDir) {
|
|
|
59
60
|
const components = {};
|
|
60
61
|
const compiledFiles = {};
|
|
61
62
|
const classificationLog = [];
|
|
63
|
+
const cssSet = new Set;
|
|
62
64
|
const tsxFiles = collectTsxFiles(srcDir);
|
|
63
65
|
for (const filePath of tsxFiles) {
|
|
64
66
|
try {
|
|
@@ -74,9 +76,14 @@ function generateAotBuildManifest(srcDir) {
|
|
|
74
76
|
if (result.components.length > 0) {
|
|
75
77
|
compiledFiles[filePath] = {
|
|
76
78
|
code: result.code,
|
|
77
|
-
components: result.components
|
|
79
|
+
components: result.components,
|
|
80
|
+
css: result.css
|
|
78
81
|
};
|
|
79
82
|
}
|
|
83
|
+
if (result.css) {
|
|
84
|
+
for (const rule of result.css)
|
|
85
|
+
cssSet.add(rule);
|
|
86
|
+
}
|
|
80
87
|
} catch (e) {
|
|
81
88
|
classificationLog.push(`⚠ ${filePath}: ${e instanceof Error ? e.message : "compilation failed"}`);
|
|
82
89
|
}
|
|
@@ -101,7 +108,7 @@ function generateAotBuildManifest(srcDir) {
|
|
|
101
108
|
const pct = Math.round(aotCount / total * 100);
|
|
102
109
|
classificationLog.push(`Coverage: ${aotCount}/${total} components (${pct}%)`);
|
|
103
110
|
}
|
|
104
|
-
return { components, compiledFiles, classificationLog };
|
|
111
|
+
return { components, compiledFiles, classificationLog, css: [...cssSet] };
|
|
105
112
|
}
|
|
106
113
|
function buildAotRouteMap(components, routes) {
|
|
107
114
|
const routeMap = {};
|
|
@@ -128,11 +135,14 @@ function buildAotRouteMap(components, routes) {
|
|
|
128
135
|
}
|
|
129
136
|
return routeMap;
|
|
130
137
|
}
|
|
131
|
-
function generateAotBarrel(compiledFiles, routeMap) {
|
|
138
|
+
function generateAotBarrel(compiledFiles, routeMap, appEntry) {
|
|
132
139
|
const neededFns = new Set;
|
|
133
140
|
for (const entry of Object.values(routeMap)) {
|
|
134
141
|
neededFns.add(entry.renderFn);
|
|
135
142
|
}
|
|
143
|
+
if (appEntry) {
|
|
144
|
+
neededFns.add(appEntry.renderFn);
|
|
145
|
+
}
|
|
136
146
|
const fnToFile = new Map;
|
|
137
147
|
for (const [filePath, compiled] of Object.entries(compiledFiles)) {
|
|
138
148
|
for (const comp of compiled.components) {
|
|
@@ -156,13 +166,15 @@ function generateAotBarrel(compiledFiles, routeMap) {
|
|
|
156
166
|
for (const [filePath, fns] of fileToFns) {
|
|
157
167
|
const moduleName = basename(filePath, ".tsx").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
158
168
|
const tempFileName = `__aot_${fileIndex}_${moduleName}`;
|
|
159
|
-
const moduleRef = `./${tempFileName}`;
|
|
169
|
+
const moduleRef = `./${tempFileName}.ts`;
|
|
160
170
|
lines.push(`export { ${fns.sort().join(", ")} } from '${moduleRef}';`);
|
|
161
171
|
const compiled = compiledFiles[filePath];
|
|
162
172
|
if (compiled) {
|
|
163
173
|
const helperImport = `import { __esc, __esc_attr, __ssr_spread, __ssr_style_object } from '@vertz/ui-server';
|
|
174
|
+
` + `import type { SSRAotContext } from '@vertz/ui-server';
|
|
164
175
|
`;
|
|
165
|
-
|
|
176
|
+
const extracted = extractSsrFunctions(compiled.code, fns);
|
|
177
|
+
files[`${tempFileName}.ts`] = helperImport + extracted;
|
|
166
178
|
}
|
|
167
179
|
fileIndex++;
|
|
168
180
|
}
|
|
@@ -172,6 +184,129 @@ function generateAotBarrel(compiledFiles, routeMap) {
|
|
|
172
184
|
files
|
|
173
185
|
};
|
|
174
186
|
}
|
|
187
|
+
function extractSsrFunctions(code, fnNames) {
|
|
188
|
+
const extracted = [];
|
|
189
|
+
for (const fnName of fnNames) {
|
|
190
|
+
const marker = `export function ${fnName}(`;
|
|
191
|
+
const startIdx = code.indexOf(marker);
|
|
192
|
+
if (startIdx === -1)
|
|
193
|
+
continue;
|
|
194
|
+
const bodyStart = code.indexOf("{", startIdx + marker.length);
|
|
195
|
+
if (bodyStart === -1)
|
|
196
|
+
continue;
|
|
197
|
+
let depth = 1;
|
|
198
|
+
let i = bodyStart + 1;
|
|
199
|
+
while (i < code.length && depth > 0) {
|
|
200
|
+
if (code[i] === "{")
|
|
201
|
+
depth++;
|
|
202
|
+
else if (code[i] === "}")
|
|
203
|
+
depth--;
|
|
204
|
+
i++;
|
|
205
|
+
}
|
|
206
|
+
extracted.push(code.slice(startIdx, i));
|
|
207
|
+
}
|
|
208
|
+
return extracted.join(`
|
|
209
|
+
`);
|
|
210
|
+
}
|
|
211
|
+
function findAppComponent(components) {
|
|
212
|
+
for (const [name, comp] of Object.entries(components)) {
|
|
213
|
+
if (comp.tier === "runtime-fallback")
|
|
214
|
+
continue;
|
|
215
|
+
if (comp.holes.includes("RouterView")) {
|
|
216
|
+
return {
|
|
217
|
+
renderFn: `__ssr_${name}`,
|
|
218
|
+
holes: comp.holes,
|
|
219
|
+
queryKeys: comp.queryKeys
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
function attachPerRouteCss(compiledFiles, routeMap, appEntry) {
|
|
226
|
+
const classToRule = new Map;
|
|
227
|
+
for (const file of Object.values(compiledFiles)) {
|
|
228
|
+
if (!file.css)
|
|
229
|
+
continue;
|
|
230
|
+
for (const rule of file.css) {
|
|
231
|
+
const match = /\.(_[0-9a-f]{8})/.exec(rule);
|
|
232
|
+
if (match)
|
|
233
|
+
classToRule.set(match[1], rule);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (classToRule.size === 0)
|
|
237
|
+
return;
|
|
238
|
+
const componentCode = new Map;
|
|
239
|
+
const componentHoles = new Map;
|
|
240
|
+
for (const file of Object.values(compiledFiles)) {
|
|
241
|
+
for (const comp of file.components) {
|
|
242
|
+
const fnName = `__ssr_${comp.name}`;
|
|
243
|
+
const code = extractSsrFunctions(file.code, [fnName]);
|
|
244
|
+
if (code)
|
|
245
|
+
componentCode.set(comp.name, code);
|
|
246
|
+
if (comp.holes.length > 0)
|
|
247
|
+
componentHoles.set(comp.name, comp.holes);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const classNamePattern = /_([\da-f]{8})/g;
|
|
251
|
+
function findUsedCss(code, seenClasses) {
|
|
252
|
+
const rules = [];
|
|
253
|
+
let m;
|
|
254
|
+
while ((m = classNamePattern.exec(code)) !== null) {
|
|
255
|
+
const cls = `_${m[1]}`;
|
|
256
|
+
if (seenClasses.has(cls))
|
|
257
|
+
continue;
|
|
258
|
+
seenClasses.add(cls);
|
|
259
|
+
const rule = classToRule.get(cls);
|
|
260
|
+
if (rule)
|
|
261
|
+
rules.push(rule);
|
|
262
|
+
}
|
|
263
|
+
classNamePattern.lastIndex = 0;
|
|
264
|
+
return rules;
|
|
265
|
+
}
|
|
266
|
+
function collectTreeCss(rootName) {
|
|
267
|
+
const allRules = [];
|
|
268
|
+
const seenClasses = new Set;
|
|
269
|
+
const visited = new Set;
|
|
270
|
+
const queue = [rootName];
|
|
271
|
+
while (queue.length > 0) {
|
|
272
|
+
const name = queue.pop();
|
|
273
|
+
if (visited.has(name))
|
|
274
|
+
continue;
|
|
275
|
+
visited.add(name);
|
|
276
|
+
const code = componentCode.get(name);
|
|
277
|
+
if (code) {
|
|
278
|
+
allRules.push(...findUsedCss(code, seenClasses));
|
|
279
|
+
const localCallPattern = /__ssr_(\w+)\(/g;
|
|
280
|
+
let lm;
|
|
281
|
+
while ((lm = localCallPattern.exec(code)) !== null) {
|
|
282
|
+
const childName = lm[1];
|
|
283
|
+
if (!visited.has(childName))
|
|
284
|
+
queue.push(childName);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const holes = componentHoles.get(name);
|
|
288
|
+
if (holes) {
|
|
289
|
+
for (const hole of holes) {
|
|
290
|
+
if (!visited.has(hole))
|
|
291
|
+
queue.push(hole);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return allRules;
|
|
296
|
+
}
|
|
297
|
+
if (appEntry) {
|
|
298
|
+
const appName = appEntry.renderFn.replace(/^__ssr_/, "");
|
|
299
|
+
const appCss = collectTreeCss(appName);
|
|
300
|
+
if (appCss.length > 0)
|
|
301
|
+
appEntry.css = appCss;
|
|
302
|
+
}
|
|
303
|
+
for (const entry of Object.values(routeMap)) {
|
|
304
|
+
const compName = entry.renderFn.replace(/^__ssr_/, "");
|
|
305
|
+
const routeCss = collectTreeCss(compName);
|
|
306
|
+
if (routeCss.length > 0)
|
|
307
|
+
entry.css = routeCss;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
175
310
|
function collectTsxFiles(dir) {
|
|
176
311
|
const files = [];
|
|
177
312
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -212,7 +347,7 @@ function inlineCriticalCss(css) {
|
|
|
212
347
|
// src/font-metrics.ts
|
|
213
348
|
import { access as fsAccess } from "node:fs/promises";
|
|
214
349
|
import { readFile } from "node:fs/promises";
|
|
215
|
-
import { join as join2 } from "node:path";
|
|
350
|
+
import { isAbsolute, join as join2 } from "node:path";
|
|
216
351
|
import { fromBuffer } from "@capsizecss/unpack";
|
|
217
352
|
var SYSTEM_FONT_METRICS = {
|
|
218
353
|
Arial: {
|
|
@@ -280,6 +415,12 @@ function getPrimarySrcPath(descriptor) {
|
|
|
280
415
|
return null;
|
|
281
416
|
}
|
|
282
417
|
async function resolveFilePath(urlPath, rootDir) {
|
|
418
|
+
if (isAbsolute(urlPath)) {
|
|
419
|
+
try {
|
|
420
|
+
await fsAccess(urlPath);
|
|
421
|
+
return urlPath;
|
|
422
|
+
} catch {}
|
|
423
|
+
}
|
|
283
424
|
const cleaned = urlPath.startsWith("/") ? urlPath.slice(1) : urlPath;
|
|
284
425
|
const direct = join2(rootDir, cleaned);
|
|
285
426
|
try {
|
|
@@ -1048,6 +1189,7 @@ export {
|
|
|
1048
1189
|
generateSSRHtml,
|
|
1049
1190
|
generateAotBuildManifest,
|
|
1050
1191
|
generateAotBarrel,
|
|
1192
|
+
findAppComponent,
|
|
1051
1193
|
extractRoutes,
|
|
1052
1194
|
extractFontMetrics,
|
|
1053
1195
|
evaluateAccessRule,
|
|
@@ -1065,8 +1207,10 @@ export {
|
|
|
1065
1207
|
createAotManifestManager,
|
|
1066
1208
|
createAccessSetScript,
|
|
1067
1209
|
collectStreamChunks,
|
|
1210
|
+
clearRouteCssCache,
|
|
1068
1211
|
clearGlobalSSRTimeout,
|
|
1069
1212
|
buildAotRouteMap,
|
|
1213
|
+
attachPerRouteCss,
|
|
1070
1214
|
__ssr_style_object,
|
|
1071
1215
|
__ssr_spread,
|
|
1072
1216
|
__esc_attr,
|
package/dist/node-handler.d.ts
CHANGED
|
@@ -94,6 +94,8 @@ interface SSRAotContext {
|
|
|
94
94
|
session: PrefetchSession | undefined;
|
|
95
95
|
/** Route params for the current request. */
|
|
96
96
|
params: Record<string, string>;
|
|
97
|
+
/** URL search params for the current request (used by AOT functions with ${sp:name} keys). */
|
|
98
|
+
searchParams: URLSearchParams | undefined;
|
|
97
99
|
}
|
|
98
100
|
/** An AOT render function: takes props/data and context, returns HTML string. */
|
|
99
101
|
type AotRenderFn = (data: Record<string, unknown>, ctx: SSRAotContext) => string;
|
|
@@ -105,6 +107,8 @@ interface AotRouteEntry {
|
|
|
105
107
|
holes: string[];
|
|
106
108
|
/** Query cache keys this route reads via ctx.getData(). */
|
|
107
109
|
queryKeys?: string[];
|
|
110
|
+
/** Pre-filtered CSS rules for this route, determined at build time (#1988). */
|
|
111
|
+
css?: string[];
|
|
108
112
|
}
|
|
109
113
|
/**
|
|
110
114
|
* AOT manifest — maps route patterns to pre-compiled render functions.
|
|
@@ -114,6 +118,8 @@ interface AotRouteEntry {
|
|
|
114
118
|
interface AotManifest {
|
|
115
119
|
/** Route pattern → AOT entry. */
|
|
116
120
|
routes: Record<string, AotRouteEntry>;
|
|
121
|
+
/** Root layout (App) entry — wraps page content via its RouterView hole. */
|
|
122
|
+
app?: AotRouteEntry;
|
|
117
123
|
}
|
|
118
124
|
/**
|
|
119
125
|
* Resolves custom data for AOT-rendered routes.
|
|
@@ -126,7 +132,7 @@ interface AotManifest {
|
|
|
126
132
|
* @param unresolvedKeys - Query keys not yet populated by entity prefetch
|
|
127
133
|
* @returns Map of cache key → data, or empty Map to skip
|
|
128
134
|
*/
|
|
129
|
-
type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[]) => Promise<Map<string, unknown>> | Map<string, unknown>;
|
|
135
|
+
type AotDataResolver = (pattern: string, params: Record<string, string>, unresolvedKeys: string[], searchParams?: URLSearchParams) => Promise<Map<string, unknown>> | Map<string, unknown>;
|
|
130
136
|
import { AccessSet } from "@vertz/ui/auth";
|
|
131
137
|
interface SessionData {
|
|
132
138
|
user: {
|
package/dist/node-handler.js
CHANGED