veryfront 0.1.26 → 0.1.28
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/README.md +3 -11
- package/esm/cli/app/shell.d.ts.map +1 -1
- package/esm/cli/app/shell.js +9 -5
- package/esm/cli/commands/demo/demo.js +1 -1
- package/esm/cli/commands/init/catalog.d.ts.map +1 -1
- package/esm/cli/commands/init/catalog.js +13 -5
- package/esm/cli/commands/init/command-help.js +4 -4
- package/esm/cli/commands/init/types.d.ts +1 -1
- package/esm/cli/commands/init/types.d.ts.map +1 -1
- package/esm/cli/commands/serve/command.d.ts.map +1 -1
- package/esm/cli/commands/serve/command.js +0 -4
- package/esm/cli/commands/start/command.d.ts.map +1 -1
- package/esm/cli/commands/start/command.js +16 -9
- package/esm/cli/help/tips.js +6 -6
- package/esm/cli/mcp/remote-file-tools.js +1 -1
- package/esm/cli/mcp/tools/catalog-tools.d.ts +3 -3
- package/esm/cli/mcp/tools/catalog-tools.d.ts.map +1 -1
- package/esm/cli/mcp/tools/catalog-tools.js +21 -13
- package/esm/cli/mcp/tools/project-tools.js +1 -1
- package/esm/cli/templates/index.js +11 -11
- package/esm/cli/templates/manifest.d.ts +22 -15
- package/esm/cli/templates/manifest.js +24 -17
- package/esm/cli/templates/types.d.ts +1 -1
- package/esm/cli/templates/types.d.ts.map +1 -1
- package/esm/cli/utils/index.d.ts.map +1 -1
- package/esm/cli/utils/index.js +13 -1
- package/esm/deno.js +1 -1
- package/esm/src/html/html-shell-generator.d.ts.map +1 -1
- package/esm/src/html/html-shell-generator.js +2 -0
- package/esm/src/html/styles-builder/project-css-cache.d.ts +8 -1
- package/esm/src/html/styles-builder/project-css-cache.d.ts.map +1 -1
- package/esm/src/html/styles-builder/project-css-cache.js +13 -2
- package/esm/src/html/styles-builder/tailwind-compiler.d.ts +2 -0
- package/esm/src/html/styles-builder/tailwind-compiler.d.ts.map +1 -1
- package/esm/src/html/styles-builder/tailwind-compiler.js +52 -19
- package/esm/src/modules/react-loader/css-import-collector.d.ts +29 -0
- package/esm/src/modules/react-loader/css-import-collector.d.ts.map +1 -0
- package/esm/src/modules/react-loader/css-import-collector.js +41 -0
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.js +6 -0
- package/esm/src/modules/react-loader/ssr-module-loader/ssr-dependency-validator.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/ssr-dependency-validator.js +5 -0
- package/esm/src/platform/adapters/fs/factory.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/factory.js +5 -1
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts +1 -0
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.d.ts.map +1 -1
- package/esm/src/platform/adapters/fs/veryfront/websocket-manager.js +19 -5
- package/esm/src/platform/compat/process.d.ts.map +1 -1
- package/esm/src/platform/compat/process.js +20 -3
- package/esm/src/proxy/main.js +31 -12
- package/esm/src/proxy/token-manager.d.ts +2 -0
- package/esm/src/proxy/token-manager.d.ts.map +1 -1
- package/esm/src/proxy/token-manager.js +47 -8
- package/esm/src/rendering/orchestrator/css-candidate-manifest.d.ts +23 -0
- package/esm/src/rendering/orchestrator/css-candidate-manifest.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/css-candidate-manifest.js +132 -0
- package/esm/src/rendering/orchestrator/html.d.ts +11 -1
- package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/html.js +103 -18
- package/esm/src/rendering/orchestrator/pipeline.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/pipeline.js +14 -2
- package/esm/src/server/bootstrap.d.ts +2 -0
- package/esm/src/server/bootstrap.d.ts.map +1 -1
- package/esm/src/server/bootstrap.js +10 -0
- package/esm/src/server/handlers/preview/markdown-html-generator.d.ts.map +1 -1
- package/esm/src/server/handlers/preview/markdown-html-generator.js +11 -5
- package/esm/src/server/production-server.js +10 -2
- package/esm/src/studio/bridge-template.d.ts +2 -0
- package/esm/src/studio/bridge-template.d.ts.map +1 -1
- package/esm/src/studio/bridge-template.js +3390 -52
- package/esm/src/transforms/css-modules/naming.d.ts +33 -0
- package/esm/src/transforms/css-modules/naming.d.ts.map +1 -0
- package/esm/src/transforms/css-modules/naming.js +128 -0
- package/esm/src/transforms/esm/import-parser.d.ts +1 -0
- package/esm/src/transforms/esm/import-parser.d.ts.map +1 -1
- package/esm/src/transforms/esm/import-parser.js +16 -5
- package/esm/src/transforms/pipeline/index.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/index.js +3 -1
- package/esm/src/transforms/pipeline/stages/index.d.ts +1 -0
- package/esm/src/transforms/pipeline/stages/index.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/index.js +1 -0
- package/esm/src/transforms/pipeline/stages/ssr-css-strip.d.ts +18 -0
- package/esm/src/transforms/pipeline/stages/ssr-css-strip.d.ts.map +1 -0
- package/esm/src/transforms/pipeline/stages/ssr-css-strip.js +168 -0
- package/package.json +1 -1
- package/src/cli/app/shell.ts +9 -5
- package/src/cli/commands/demo/demo.ts +1 -1
- package/src/cli/commands/init/catalog.ts +13 -5
- package/src/cli/commands/init/command-help.ts +4 -4
- package/src/cli/commands/init/types.ts +5 -5
- package/src/cli/commands/serve/command.ts +0 -5
- package/src/cli/commands/start/command.ts +15 -10
- package/src/cli/help/tips.ts +6 -6
- package/src/cli/mcp/remote-file-tools.ts +1 -1
- package/src/cli/mcp/tools/catalog-tools.ts +21 -13
- package/src/cli/mcp/tools/project-tools.ts +1 -1
- package/src/cli/templates/index.ts +11 -11
- package/src/cli/templates/manifest.js +24 -17
- package/src/cli/templates/types.ts +5 -5
- package/src/cli/utils/index.ts +12 -1
- package/src/deno.js +1 -1
- package/src/src/html/html-shell-generator.ts +2 -0
- package/src/src/html/styles-builder/project-css-cache.ts +24 -1
- package/src/src/html/styles-builder/tailwind-compiler.ts +67 -26
- package/src/src/modules/react-loader/css-import-collector.ts +50 -0
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +7 -0
- package/src/src/modules/react-loader/ssr-module-loader/ssr-dependency-validator.ts +6 -0
- package/src/src/platform/adapters/fs/factory.ts +5 -1
- package/src/src/platform/adapters/fs/veryfront/websocket-manager.ts +21 -5
- package/src/src/platform/compat/process.ts +28 -4
- package/src/src/proxy/main.ts +32 -12
- package/src/src/proxy/token-manager.ts +54 -8
- package/src/src/rendering/orchestrator/css-candidate-manifest.ts +176 -0
- package/src/src/rendering/orchestrator/html.ts +128 -16
- package/src/src/rendering/orchestrator/pipeline.ts +183 -165
- package/src/src/server/bootstrap.ts +16 -0
- package/src/src/server/handlers/preview/markdown-html-generator.ts +12 -5
- package/src/src/server/production-server.ts +12 -2
- package/src/src/studio/bridge-template.ts +3392 -52
- package/src/src/transforms/css-modules/naming.ts +152 -0
- package/src/src/transforms/esm/import-parser.ts +15 -5
- package/src/src/transforms/pipeline/index.ts +3 -0
- package/src/src/transforms/pipeline/stages/index.ts +1 -0
- package/src/src/transforms/pipeline/stages/ssr-css-strip.ts +201 -0
|
@@ -46,6 +46,10 @@ import { withTimeout, withTimeoutThrow } from "../utils/stream-utils.js";
|
|
|
46
46
|
import { generateTailwind4CSS } from "../../html/styles-builder/index.js";
|
|
47
47
|
import { createEsmCache, createModuleCache, loadModule } from "./module-loader/index.js";
|
|
48
48
|
import type { ModuleLoaderConfig } from "./module-loader/index.js";
|
|
49
|
+
import {
|
|
50
|
+
getCSSImports,
|
|
51
|
+
runWithCSSCollector,
|
|
52
|
+
} from "../../modules/react-loader/css-import-collector.js";
|
|
49
53
|
|
|
50
54
|
// Extracted modules
|
|
51
55
|
import { EMPTY_LAYOUT_RESULT, isDotPath } from "./path-helpers.js";
|
|
@@ -339,186 +343,200 @@ export class RenderPipeline {
|
|
|
339
343
|
|
|
340
344
|
return withSpan(
|
|
341
345
|
"render.page",
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
346
|
+
() =>
|
|
347
|
+
runWithCSSCollector(async () => {
|
|
348
|
+
const pageResolveStart = performance.now();
|
|
349
|
+
const pageInfo = await withSpan(
|
|
350
|
+
"render.resolve_page",
|
|
351
|
+
() => this.config.pageResolver.resolvePage(slug),
|
|
352
|
+
{ "render.slug": slug },
|
|
353
|
+
);
|
|
354
|
+
timing.pageResolve = Math.round(performance.now() - pageResolveStart);
|
|
350
355
|
|
|
351
|
-
|
|
356
|
+
const skipLayouts = isDotPath(slug, pageInfo.entity.path);
|
|
352
357
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
{ "render.slug": slug },
|
|
358
|
-
);
|
|
359
|
-
timing.layoutCollect = Math.round(performance.now() - layoutCollectStart);
|
|
360
|
-
|
|
361
|
-
const layoutPreloadPromise = !skipLayouts && layoutResult.nestedLayouts.length > 0
|
|
362
|
-
? this.config.layoutOrchestrator.preloadLayoutModules(layoutResult.nestedLayouts)
|
|
363
|
-
: Promise.resolve();
|
|
364
|
-
|
|
365
|
-
let dataFetchingProps: Record<string, unknown> | undefined;
|
|
366
|
-
let resolvedParams: Record<string, string | string[]> = options?.params
|
|
367
|
-
? { ...options.params }
|
|
368
|
-
: {};
|
|
369
|
-
let layoutDataMap = new Map<string, Record<string, unknown>>();
|
|
370
|
-
|
|
371
|
-
const dataFetchStart = performance.now();
|
|
372
|
-
if (options?.request && options?.url) {
|
|
373
|
-
await withSpan(
|
|
374
|
-
"render.data_fetching",
|
|
375
|
-
async () => {
|
|
376
|
-
try {
|
|
377
|
-
const dataResolution = await this.resolveDataFetching(
|
|
378
|
-
slug,
|
|
379
|
-
pageInfo.entity.path,
|
|
380
|
-
layoutResult.nestedLayouts,
|
|
381
|
-
options,
|
|
382
|
-
);
|
|
383
|
-
resolvedParams = dataResolution.params;
|
|
384
|
-
dataFetchingProps = Object.keys(dataResolution.pageProps).length > 0
|
|
385
|
-
? dataResolution.pageProps
|
|
386
|
-
: undefined;
|
|
387
|
-
layoutDataMap = dataResolution.layoutProps;
|
|
388
|
-
} catch (error) {
|
|
389
|
-
if (error instanceof VeryfrontError) throw error;
|
|
390
|
-
|
|
391
|
-
renderPageLog.error("Data fetching error", {
|
|
392
|
-
slug,
|
|
393
|
-
error: error instanceof Error ? error.message : String(error),
|
|
394
|
-
});
|
|
395
|
-
throw error;
|
|
396
|
-
}
|
|
397
|
-
},
|
|
358
|
+
const layoutCollectStart = performance.now();
|
|
359
|
+
const layoutResult = skipLayouts ? EMPTY_LAYOUT_RESULT : await withSpan(
|
|
360
|
+
"render.collect_layouts",
|
|
361
|
+
() => this.config.layoutOrchestrator.collectLayouts(pageInfo),
|
|
398
362
|
{ "render.slug": slug },
|
|
399
363
|
);
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
364
|
+
timing.layoutCollect = Math.round(performance.now() - layoutCollectStart);
|
|
365
|
+
|
|
366
|
+
const layoutPreloadPromise = !skipLayouts && layoutResult.nestedLayouts.length > 0
|
|
367
|
+
? this.config.layoutOrchestrator.preloadLayoutModules(layoutResult.nestedLayouts)
|
|
368
|
+
: Promise.resolve();
|
|
369
|
+
|
|
370
|
+
let dataFetchingProps: Record<string, unknown> | undefined;
|
|
371
|
+
let resolvedParams: Record<string, string | string[]> = options?.params
|
|
372
|
+
? { ...options.params }
|
|
373
|
+
: {};
|
|
374
|
+
let layoutDataMap = new Map<string, Record<string, unknown>>();
|
|
375
|
+
|
|
376
|
+
const dataFetchStart = performance.now();
|
|
377
|
+
if (options?.request && options?.url) {
|
|
378
|
+
await withSpan(
|
|
379
|
+
"render.data_fetching",
|
|
380
|
+
async () => {
|
|
381
|
+
try {
|
|
382
|
+
const dataResolution = await this.resolveDataFetching(
|
|
383
|
+
slug,
|
|
384
|
+
pageInfo.entity.path,
|
|
385
|
+
layoutResult.nestedLayouts,
|
|
386
|
+
options,
|
|
387
|
+
);
|
|
388
|
+
resolvedParams = dataResolution.params;
|
|
389
|
+
dataFetchingProps = Object.keys(dataResolution.pageProps).length > 0
|
|
390
|
+
? dataResolution.pageProps
|
|
391
|
+
: undefined;
|
|
392
|
+
layoutDataMap = dataResolution.layoutProps;
|
|
393
|
+
} catch (error) {
|
|
394
|
+
if (error instanceof VeryfrontError) throw error;
|
|
395
|
+
|
|
396
|
+
renderPageLog.error("Data fetching error", {
|
|
397
|
+
slug,
|
|
398
|
+
error: error instanceof Error ? error.message : String(error),
|
|
399
|
+
});
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
{ "render.slug": slug },
|
|
404
|
+
);
|
|
409
405
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
406
|
+
timing.dataFetch = Math.round(performance.now() - dataFetchStart);
|
|
407
|
+
|
|
408
|
+
const hasResolvedParams = Object.keys(resolvedParams).length > 0;
|
|
409
|
+
const mergedOptions = (dataFetchingProps || hasResolvedParams)
|
|
410
|
+
? {
|
|
411
|
+
...options,
|
|
412
|
+
...(hasResolvedParams ? { params: resolvedParams } : {}),
|
|
413
|
+
...(dataFetchingProps ? { props: { ...options?.props, ...dataFetchingProps } } : {}),
|
|
414
|
+
}
|
|
415
|
+
: options;
|
|
416
|
+
|
|
417
|
+
const bundlePrepStart = performance.now();
|
|
418
|
+
const pageBundleResult = await withSpan(
|
|
419
|
+
"render.prepare_bundles",
|
|
420
|
+
() =>
|
|
421
|
+
this.config.pageRenderer.preparePageBundles(
|
|
422
|
+
pageInfo,
|
|
423
|
+
slug,
|
|
424
|
+
cacheResult?.cachedModule,
|
|
425
|
+
mergedOptions,
|
|
426
|
+
),
|
|
427
|
+
{ "render.slug": slug },
|
|
428
|
+
);
|
|
429
|
+
timing.bundlePrep = Math.round(performance.now() - bundlePrepStart);
|
|
425
430
|
|
|
426
|
-
|
|
431
|
+
if (pageBundleResult.scriptResult) return pageBundleResult.scriptResult;
|
|
427
432
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
433
|
+
if (!pageBundleResult.pageElement || !pageBundleResult.pageBundle) {
|
|
434
|
+
throw RENDER_ERROR.create({
|
|
435
|
+
detail: "Failed to prepare page bundle",
|
|
436
|
+
context: { slug },
|
|
437
|
+
});
|
|
438
|
+
}
|
|
434
439
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
),
|
|
461
|
-
{ "render.slug": slug, "render.layout_count": layoutResult.nestedLayouts.length },
|
|
462
|
-
);
|
|
463
|
-
timing.layoutApply = Math.round(performance.now() - layoutApplyStart);
|
|
464
|
-
|
|
465
|
-
const ssrStart = performance.now();
|
|
466
|
-
const ssrResult = await withSpan(
|
|
467
|
-
"render.ssr",
|
|
468
|
-
() =>
|
|
469
|
-
withTimeoutThrow(
|
|
470
|
-
this.config.ssrOrchestrator.performSSRRendering(
|
|
471
|
-
wrappedElement,
|
|
472
|
-
{
|
|
473
|
-
pageInfo,
|
|
474
|
-
pageBundle,
|
|
475
|
-
layoutBundle: layoutResult.layoutBundle,
|
|
476
|
-
nestedLayouts: layoutResult.nestedLayouts,
|
|
477
|
-
collectedMetadata: pageBundleResult.collectedMetadata,
|
|
478
|
-
slug,
|
|
479
|
-
},
|
|
480
|
-
mergedOptions,
|
|
440
|
+
const { pageElement, pageBundle } = pageBundleResult;
|
|
441
|
+
|
|
442
|
+
const mergedFrontmatter = {
|
|
443
|
+
...pageInfo.entity.frontmatter,
|
|
444
|
+
...(pageBundle as MdxBundle).frontmatter,
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const headings = (pageBundle as PageBundle).headings || [];
|
|
448
|
+
|
|
449
|
+
await layoutPreloadPromise;
|
|
450
|
+
|
|
451
|
+
const layoutApplyStart = performance.now();
|
|
452
|
+
const wrappedElement = await withSpan(
|
|
453
|
+
"render.apply_layouts",
|
|
454
|
+
() =>
|
|
455
|
+
this.config.layoutOrchestrator.applyLayoutsAndWrappers(
|
|
456
|
+
pageElement,
|
|
457
|
+
pageInfo,
|
|
458
|
+
layoutResult.layoutBundle,
|
|
459
|
+
layoutResult.nestedLayouts,
|
|
460
|
+
layoutDataMap,
|
|
461
|
+
options?.url,
|
|
462
|
+
mergedFrontmatter,
|
|
463
|
+
headings,
|
|
464
|
+
options?.projectSlug,
|
|
481
465
|
),
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
466
|
+
{ "render.slug": slug, "render.layout_count": layoutResult.nestedLayouts.length },
|
|
467
|
+
);
|
|
468
|
+
timing.layoutApply = Math.round(performance.now() - layoutApplyStart);
|
|
469
|
+
|
|
470
|
+
// Snapshot CSS imports collected during module loading (before SSR rendering).
|
|
471
|
+
// These are passed to the HTML generator to be included in the output.
|
|
472
|
+
const collectedCSSImports = getCSSImports();
|
|
473
|
+
|
|
474
|
+
const ssrStart = performance.now();
|
|
475
|
+
const ssrResult = await withSpan(
|
|
476
|
+
"render.ssr",
|
|
477
|
+
() =>
|
|
478
|
+
withTimeoutThrow(
|
|
479
|
+
this.config.ssrOrchestrator.performSSRRendering(
|
|
480
|
+
wrappedElement,
|
|
481
|
+
{
|
|
482
|
+
pageInfo,
|
|
483
|
+
pageBundle,
|
|
484
|
+
layoutBundle: layoutResult.layoutBundle,
|
|
485
|
+
nestedLayouts: layoutResult.nestedLayouts,
|
|
486
|
+
collectedMetadata: pageBundleResult.collectedMetadata,
|
|
487
|
+
slug,
|
|
488
|
+
cssImports: collectedCSSImports,
|
|
489
|
+
},
|
|
490
|
+
mergedOptions,
|
|
491
|
+
),
|
|
492
|
+
SSR_RENDER_TIMEOUT_MS,
|
|
493
|
+
`SSR rendering for ${slug}`,
|
|
494
|
+
),
|
|
495
|
+
{ "render.slug": slug, "render.delivery": mergedOptions?.delivery || "full" },
|
|
496
|
+
);
|
|
497
|
+
timing.ssr = Math.round(performance.now() - ssrStart);
|
|
488
498
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
499
|
+
if (collectedCSSImports.length > 0) {
|
|
500
|
+
renderPipelineLog.debug("CSS imports collected for HTML generation", {
|
|
501
|
+
slug,
|
|
502
|
+
count: collectedCSSImports.length,
|
|
503
|
+
paths: collectedCSSImports.map((p) => p.split("/").pop()),
|
|
504
|
+
});
|
|
494
505
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
html: ssrResult.fullHtml,
|
|
499
|
-
frontmatter: (pageBundleResult.pageBundle as MdxBundle).frontmatter || {},
|
|
500
|
-
headings: pageBundleResult.pageBundle.headings || [],
|
|
501
|
-
nodeMap: pageBundleResult.pageBundle.nodeMap,
|
|
502
|
-
stream: ssrResult.finalStream,
|
|
503
|
-
ssrHash: ssrResult.ssrHash,
|
|
504
|
-
...(pageModule ? { pageModule } : {}),
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
if (shouldCache && !options?.skipCachePersist) {
|
|
508
|
-
this.config.cacheCoordinator.persistResult(result, slug, cacheKey).catch((error) => {
|
|
509
|
-
renderPipelineLog.error("Cache persist failed", {
|
|
506
|
+
|
|
507
|
+
const pageModule = pageBundleResult.clientModuleCode && pageBundleResult.pageModuleType
|
|
508
|
+
? {
|
|
510
509
|
slug,
|
|
511
|
-
|
|
512
|
-
|
|
510
|
+
code: pageBundleResult.clientModuleCode,
|
|
511
|
+
type: pageBundleResult.pageModuleType,
|
|
512
|
+
}
|
|
513
|
+
: undefined;
|
|
514
|
+
|
|
515
|
+
const result: RenderResult = {
|
|
516
|
+
html: ssrResult.fullHtml,
|
|
517
|
+
frontmatter: (pageBundleResult.pageBundle as MdxBundle).frontmatter || {},
|
|
518
|
+
headings: pageBundleResult.pageBundle.headings || [],
|
|
519
|
+
nodeMap: pageBundleResult.pageBundle.nodeMap,
|
|
520
|
+
stream: ssrResult.finalStream,
|
|
521
|
+
ssrHash: ssrResult.ssrHash,
|
|
522
|
+
...(pageModule ? { pageModule } : {}),
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
if (shouldCache && !options?.skipCachePersist) {
|
|
526
|
+
this.config.cacheCoordinator.persistResult(result, slug, cacheKey).catch((error) => {
|
|
527
|
+
renderPipelineLog.error("Cache persist failed", {
|
|
528
|
+
slug,
|
|
529
|
+
error: error instanceof Error ? error.message : String(error),
|
|
530
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
531
|
+
});
|
|
513
532
|
});
|
|
514
|
-
}
|
|
515
|
-
}
|
|
533
|
+
}
|
|
516
534
|
|
|
517
|
-
|
|
518
|
-
|
|
535
|
+
timing.total = Math.round(performance.now() - pipelineStartTime);
|
|
536
|
+
renderPipelineLog.debug("Complete", { slug, timing });
|
|
519
537
|
|
|
520
|
-
|
|
521
|
-
|
|
538
|
+
return result;
|
|
539
|
+
}).then(({ result }) => result),
|
|
522
540
|
{
|
|
523
541
|
"render.slug": slug,
|
|
524
542
|
"render.project_id": options?.projectId || this.config.projectDir,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "../config/environment-config.js";
|
|
9
9
|
import { getErrorMessage } from "../errors/veryfront-error.js";
|
|
10
10
|
import { enhanceAdapterWithFS } from "../platform/adapters/fs/integration.js";
|
|
11
|
+
import { isExtendedFSAdapter } from "../platform/adapters/fs/wrapper.js";
|
|
11
12
|
import { getEnv } from "../platform/compat/process.js";
|
|
12
13
|
import { initializeEsbuild } from "../platform/compat/esbuild.js";
|
|
13
14
|
import { logger } from "../utils/index.js";
|
|
@@ -38,6 +39,9 @@ export interface BootstrapResult {
|
|
|
38
39
|
|
|
39
40
|
/** FSAdapter type (if used) */
|
|
40
41
|
fsAdapterType?: string;
|
|
42
|
+
|
|
43
|
+
/** Dispose FSAdapter resources (WebSocket connections, caches) */
|
|
44
|
+
dispose?: () => void;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
let envLogged = false;
|
|
@@ -174,11 +178,23 @@ export async function bootstrap(
|
|
|
174
178
|
fsAdapter: fsType,
|
|
175
179
|
});
|
|
176
180
|
|
|
181
|
+
let dispose: (() => void) | undefined;
|
|
182
|
+
if (isExtendedFSAdapter(enhancedAdapter.fs)) {
|
|
183
|
+
const underlying = enhancedAdapter.fs.getUnderlyingAdapter();
|
|
184
|
+
if (
|
|
185
|
+
"dispose" in underlying &&
|
|
186
|
+
typeof (underlying as { dispose?: () => void }).dispose === "function"
|
|
187
|
+
) {
|
|
188
|
+
dispose = () => (underlying as { dispose: () => void }).dispose();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
177
192
|
return {
|
|
178
193
|
adapter: enhancedAdapter,
|
|
179
194
|
config,
|
|
180
195
|
usingFSAdapter: true,
|
|
181
196
|
fsAdapterType: fsType,
|
|
197
|
+
dispose,
|
|
182
198
|
};
|
|
183
199
|
}
|
|
184
200
|
|
|
@@ -54,17 +54,24 @@ function detectTheme(req: dntShim.Request, url: URL): "light" | "dark" | null {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Generate the studio bridge `<script>` tag
|
|
58
|
-
*
|
|
57
|
+
* Generate the studio bridge `<script>` tag.
|
|
58
|
+
* Injected when embedded in Studio (`studio_embed=true`) or for standalone
|
|
59
|
+
* markdown/MDX pages so the edit button and editor features are available.
|
|
59
60
|
*/
|
|
60
61
|
function buildStudioScript(url: URL, projectId: string, filePath: string): string {
|
|
61
62
|
const studioEmbed = url.searchParams.get("studio_embed") === "true";
|
|
62
|
-
|
|
63
|
+
const isMarkdown = /\.mdx?$/i.test(filePath);
|
|
64
|
+
if (!studioEmbed && !isMarkdown) return "";
|
|
65
|
+
|
|
66
|
+
const queryProjectId = url.searchParams.get("vf_project_id")?.trim() || "";
|
|
67
|
+
const queryFileId = url.searchParams.get("vf_file_id")?.trim() || "";
|
|
68
|
+
const canonicalProjectId = queryProjectId || projectId;
|
|
69
|
+
const canonicalPageId = queryFileId || filePath;
|
|
63
70
|
|
|
64
71
|
return `<script>${
|
|
65
72
|
generateStudioBridgeScript({
|
|
66
|
-
projectId,
|
|
67
|
-
pageId:
|
|
73
|
+
projectId: canonicalProjectId,
|
|
74
|
+
pageId: canonicalPageId,
|
|
68
75
|
pagePath: filePath,
|
|
69
76
|
})
|
|
70
77
|
}</script>`;
|
|
@@ -293,12 +293,15 @@ if (import.meta.main) {
|
|
|
293
293
|
// Note: Don't use HOSTNAME - K8s sets it to pod name which resolves to pod IP
|
|
294
294
|
const bindAddress = adapter.env.get("BIND_ADDRESS") ?? "0.0.0.0";
|
|
295
295
|
|
|
296
|
+
const bootstrap = await bootstrapProd(projectDir, adapter);
|
|
297
|
+
|
|
296
298
|
const server = await startProductionServer({
|
|
297
299
|
projectDir,
|
|
298
300
|
port,
|
|
299
301
|
bindAddress,
|
|
300
302
|
debug: isDebugEnabled(adapter.env),
|
|
301
303
|
adapter, // Pass adapter to avoid re-detection
|
|
304
|
+
bootstrapResult: bootstrap,
|
|
302
305
|
signal: shutdownController.signal,
|
|
303
306
|
});
|
|
304
307
|
|
|
@@ -338,6 +341,7 @@ if (import.meta.main) {
|
|
|
338
341
|
// Phase 3: Stop accepting new connections and clean up
|
|
339
342
|
stopMemoryMonitoring();
|
|
340
343
|
requestTracker.shutdown();
|
|
344
|
+
bootstrap.dispose?.();
|
|
341
345
|
shutdownController.abort();
|
|
342
346
|
await server.stop();
|
|
343
347
|
await shutdownOTLP();
|
|
@@ -348,8 +352,14 @@ if (import.meta.main) {
|
|
|
348
352
|
}
|
|
349
353
|
};
|
|
350
354
|
|
|
351
|
-
|
|
352
|
-
|
|
355
|
+
const handleSignal = (signal: "SIGINT" | "SIGTERM"): void => {
|
|
356
|
+
void shutdown(signal).catch((error) => {
|
|
357
|
+
logger.warn("Unhandled error while shutting down production server", { signal, error });
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
onSignal("SIGINT", () => handleSignal("SIGINT"));
|
|
362
|
+
onSignal("SIGTERM", () => handleSignal("SIGTERM"));
|
|
353
363
|
} catch (e) {
|
|
354
364
|
logger.error("Failed to start production server:", e);
|
|
355
365
|
}
|