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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { extractCandidates } from "../../html/styles-builder/tailwind-compiler.js";
|
|
2
|
+
import { getRouteModulePaths } from "../../modules/manifest/route-module-manifest.js";
|
|
3
|
+
import { rendererLogger } from "../../utils/index.js";
|
|
4
|
+
const logger = rendererLogger.component("css-candidate-manifest");
|
|
5
|
+
const SOURCE_EXTENSIONS = [".tsx", ".jsx", ".mdx", ".ts", ".js"];
|
|
6
|
+
const DEV_MANIFEST_TTL_MS = 2000;
|
|
7
|
+
const manifestCache = new Map();
|
|
8
|
+
const routeCandidateCache = new Map();
|
|
9
|
+
function normalizePath(path) {
|
|
10
|
+
return path.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
11
|
+
}
|
|
12
|
+
function toRelativeProjectPath(path, projectDir) {
|
|
13
|
+
const normalized = normalizePath(path);
|
|
14
|
+
const normalizedProjectDir = normalizePath(projectDir).replace(/\/+$/, "");
|
|
15
|
+
if (normalized.startsWith(normalizedProjectDir)) {
|
|
16
|
+
return normalized.slice(normalizedProjectDir.length).replace(/^\/+/, "");
|
|
17
|
+
}
|
|
18
|
+
return normalized.replace(/^\/+/, "");
|
|
19
|
+
}
|
|
20
|
+
function buildManifestCacheKey(projectScope, projectVersion) {
|
|
21
|
+
return `${projectScope}:${projectVersion}`;
|
|
22
|
+
}
|
|
23
|
+
function shouldRebuildManifest(existing, developmentMode) {
|
|
24
|
+
if (!existing)
|
|
25
|
+
return true;
|
|
26
|
+
if (!developmentMode)
|
|
27
|
+
return false;
|
|
28
|
+
return (Date.now() - existing.builtAt) > DEV_MANIFEST_TTL_MS;
|
|
29
|
+
}
|
|
30
|
+
function buildSourceCandidatePaths(modulePath) {
|
|
31
|
+
const normalized = normalizePath(modulePath).replace(/^\/+/, "").replace(/^_vf_modules\//, "");
|
|
32
|
+
if (!normalized.endsWith(".js"))
|
|
33
|
+
return [normalized];
|
|
34
|
+
const withoutJs = normalized.slice(0, -3);
|
|
35
|
+
return [
|
|
36
|
+
`${withoutJs}.tsx`,
|
|
37
|
+
`${withoutJs}.ts`,
|
|
38
|
+
`${withoutJs}.jsx`,
|
|
39
|
+
`${withoutJs}.mdx`,
|
|
40
|
+
`${withoutJs}.js`,
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function buildCandidateManifest(files, projectDir) {
|
|
44
|
+
const fileCandidates = new Map();
|
|
45
|
+
const allCandidates = new Set();
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
if (!file.content)
|
|
48
|
+
continue;
|
|
49
|
+
if (!SOURCE_EXTENSIONS.some((ext) => file.path.endsWith(ext)))
|
|
50
|
+
continue;
|
|
51
|
+
const candidates = new Set(extractCandidates(file.content));
|
|
52
|
+
const relativePath = toRelativeProjectPath(file.path, projectDir);
|
|
53
|
+
const absolutePath = normalizePath(file.path);
|
|
54
|
+
fileCandidates.set(relativePath, candidates);
|
|
55
|
+
fileCandidates.set(absolutePath, candidates);
|
|
56
|
+
for (const cls of candidates)
|
|
57
|
+
allCandidates.add(cls);
|
|
58
|
+
}
|
|
59
|
+
return { fileCandidates, allCandidates, builtAt: Date.now() };
|
|
60
|
+
}
|
|
61
|
+
function addCandidatesForPath(target, manifest, path, projectDir) {
|
|
62
|
+
const absolutePath = normalizePath(path);
|
|
63
|
+
const relativePath = toRelativeProjectPath(path, projectDir);
|
|
64
|
+
const candidates = manifest.fileCandidates.get(absolutePath) ??
|
|
65
|
+
manifest.fileCandidates.get(relativePath);
|
|
66
|
+
if (!candidates)
|
|
67
|
+
return;
|
|
68
|
+
for (const cls of candidates)
|
|
69
|
+
target.add(cls);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve route-scoped Tailwind candidates from a precomputed per-project manifest.
|
|
73
|
+
*/
|
|
74
|
+
export function getRouteCandidates(options) {
|
|
75
|
+
const manifestKey = buildManifestCacheKey(options.projectScope, options.projectVersion);
|
|
76
|
+
const existingManifest = manifestCache.get(manifestKey);
|
|
77
|
+
const manifest = shouldRebuildManifest(existingManifest, options.developmentMode)
|
|
78
|
+
? buildCandidateManifest(options.files, options.projectDir)
|
|
79
|
+
: existingManifest;
|
|
80
|
+
if (manifest !== existingManifest) {
|
|
81
|
+
manifestCache.set(manifestKey, manifest);
|
|
82
|
+
// Clear route subsets when project-level file manifest is rebuilt.
|
|
83
|
+
for (const key of routeCandidateCache.keys()) {
|
|
84
|
+
if (key.startsWith(`${manifestKey}:`))
|
|
85
|
+
routeCandidateCache.delete(key);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const routeCacheKey = `${manifestKey}:${options.routeKey}`;
|
|
89
|
+
const cachedRoute = routeCandidateCache.get(routeCacheKey);
|
|
90
|
+
if (cachedRoute)
|
|
91
|
+
return new Set(cachedRoute);
|
|
92
|
+
const routeCandidates = new Set();
|
|
93
|
+
for (const path of options.routeFilePaths) {
|
|
94
|
+
addCandidatesForPath(routeCandidates, manifest, path, options.projectDir);
|
|
95
|
+
}
|
|
96
|
+
for (const modulePath of getRouteModulePaths(options.projectScope, options.routeKey)) {
|
|
97
|
+
for (const sourcePath of buildSourceCandidatePaths(modulePath)) {
|
|
98
|
+
addCandidatesForPath(routeCandidates, manifest, sourcePath, options.projectDir);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Fallback to full-project candidates for correctness if route manifest is incomplete.
|
|
102
|
+
if (routeCandidates.size === 0) {
|
|
103
|
+
for (const cls of manifest.allCandidates)
|
|
104
|
+
routeCandidates.add(cls);
|
|
105
|
+
}
|
|
106
|
+
routeCandidateCache.set(routeCacheKey, routeCandidates);
|
|
107
|
+
logger.debug("Resolved route candidates", {
|
|
108
|
+
projectScope: options.projectScope,
|
|
109
|
+
projectVersion: options.projectVersion,
|
|
110
|
+
route: options.routeKey,
|
|
111
|
+
count: routeCandidates.size,
|
|
112
|
+
});
|
|
113
|
+
return new Set(routeCandidates);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Invalidate cached candidate manifests for one project scope (or all scopes).
|
|
117
|
+
*/
|
|
118
|
+
export function invalidateProjectCandidateManifests(projectScope) {
|
|
119
|
+
if (!projectScope) {
|
|
120
|
+
manifestCache.clear();
|
|
121
|
+
routeCandidateCache.clear();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
for (const key of manifestCache.keys()) {
|
|
125
|
+
if (key.startsWith(`${projectScope}:`))
|
|
126
|
+
manifestCache.delete(key);
|
|
127
|
+
}
|
|
128
|
+
for (const key of routeCandidateCache.keys()) {
|
|
129
|
+
if (key.startsWith(`${projectScope}:`))
|
|
130
|
+
routeCandidateCache.delete(key);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -20,6 +20,8 @@ export interface HTMLGenerationContext {
|
|
|
20
20
|
ssrHash: string;
|
|
21
21
|
options?: RenderOptions;
|
|
22
22
|
collectedHead?: CollectedHead;
|
|
23
|
+
/** Absolute paths to CSS files imported by components (collected during module loading) */
|
|
24
|
+
cssImports?: string[];
|
|
23
25
|
}
|
|
24
26
|
export declare class HTMLGenerator {
|
|
25
27
|
private config;
|
|
@@ -35,6 +37,14 @@ export declare class HTMLGenerator {
|
|
|
35
37
|
private resolveAppPath;
|
|
36
38
|
private loadProjectFile;
|
|
37
39
|
private buildHTMLOptions;
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Load CSS files imported by components and merge with the global stylesheet.
|
|
42
|
+
* Deduplicates against the configured Tailwind stylesheet path to avoid
|
|
43
|
+
* double-loading globals.css when it's both auto-discovered and explicitly imported.
|
|
44
|
+
*/
|
|
45
|
+
private mergeImportedCSS;
|
|
46
|
+
private getProjectContentVersion;
|
|
47
|
+
private buildRouteManifestKey;
|
|
48
|
+
private extractProjectClassesForRoute;
|
|
39
49
|
}
|
|
40
50
|
//# sourceMappingURL=html.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQ7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAchD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAWjE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAmCZ,sBAAsB;YAsBtB,wBAAwB;YAkBxB,gBAAgB;YAehB,kBAAkB;IAsDhC,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAYf,gBAAgB;IAuE9B;;;;OAIG;YACW,gBAAgB;IA0D9B,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAwD5C"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { join } from "../../platform/compat/path/index.js";
|
|
2
2
|
import { getExtensionName } from "../../utils/path-utils.js";
|
|
3
3
|
import { extractHTMLMetadata, generateHTMLShellParts, injectHTMLContent, isFullHTMLDocument, } from "../../html/index.js";
|
|
4
|
-
import { extractCandidates } from "../../html/styles-builder/tailwind-compiler.js";
|
|
5
4
|
import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
|
|
6
5
|
import { injectElementSelectors } from "../../studio/element-selector-injector.js";
|
|
7
6
|
import { computeSourceHash } from "../../studio/hash-utils.js";
|
|
8
7
|
import { extractRelativePath } from "../../utils/route-path-utils.js";
|
|
9
8
|
import { resolveAppComponentPath } from "../layouts/utils/app-resolver.js";
|
|
10
9
|
import { StreamTimeoutError, streamToString } from "../utils/stream-utils.js";
|
|
10
|
+
import { normalizeCssModuleKey, rewriteCssModuleContent, } from "../../transforms/css-modules/naming.js";
|
|
11
|
+
import { getRouteCandidates } from "./css-candidate-manifest.js";
|
|
11
12
|
const logger = rendererLogger.component("html-generator");
|
|
12
13
|
export class HTMLGenerator {
|
|
13
14
|
config;
|
|
@@ -204,11 +205,14 @@ export class HTMLGenerator {
|
|
|
204
205
|
}
|
|
205
206
|
async buildHTMLOptions(context, mergedFrontmatter) {
|
|
206
207
|
const stylesheetPath = this.config.config?.tailwind?.stylesheet || "globals.css";
|
|
207
|
-
const [appComponentPath, globalCSS
|
|
208
|
+
const [appComponentPath, globalCSS] = await Promise.all([
|
|
208
209
|
this.resolveAppPath().then((p) => p ?? undefined),
|
|
209
210
|
this.loadProjectFile(stylesheetPath),
|
|
210
|
-
this.extractProjectClasses(),
|
|
211
211
|
]);
|
|
212
|
+
const projectClasses = await this.extractProjectClassesForRoute(context, appComponentPath);
|
|
213
|
+
// Load CSS imported by components and merge with globalCSS.
|
|
214
|
+
// Deduplicate against the configured stylesheet to avoid double-loading.
|
|
215
|
+
const combinedCSS = await this.mergeImportedCSS(globalCSS, context.cssImports, stylesheetPath);
|
|
212
216
|
logger.debug("App component resolution", {
|
|
213
217
|
appComponentPath,
|
|
214
218
|
projectDir: this.config.projectDir,
|
|
@@ -234,7 +238,7 @@ export class HTMLGenerator {
|
|
|
234
238
|
pagePath,
|
|
235
239
|
pageType,
|
|
236
240
|
nonce: context.options?.nonce,
|
|
237
|
-
globalCSS,
|
|
241
|
+
globalCSS: combinedCSS,
|
|
238
242
|
frontmatter: mergedFrontmatter,
|
|
239
243
|
studioEmbed: context.options?.studioEmbed,
|
|
240
244
|
projectId: context.options?.projectId,
|
|
@@ -250,8 +254,74 @@ export class HTMLGenerator {
|
|
|
250
254
|
noHmr: context.options?.noHmr,
|
|
251
255
|
};
|
|
252
256
|
}
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Load CSS files imported by components and merge with the global stylesheet.
|
|
259
|
+
* Deduplicates against the configured Tailwind stylesheet path to avoid
|
|
260
|
+
* double-loading globals.css when it's both auto-discovered and explicitly imported.
|
|
261
|
+
*/
|
|
262
|
+
async mergeImportedCSS(globalCSS, cssImports, stylesheetPath) {
|
|
263
|
+
if (!cssImports || cssImports.length === 0)
|
|
264
|
+
return globalCSS;
|
|
265
|
+
const normalizedStylesheetPath = stylesheetPath.replace(/^\/+/, "");
|
|
266
|
+
const configuredStylesheetAbsolute = normalizeCssModuleKey(join(this.config.projectDir, normalizedStylesheetPath));
|
|
267
|
+
const uniqueImports = new Map();
|
|
268
|
+
for (const cssPath of cssImports) {
|
|
269
|
+
const normalized = normalizeCssModuleKey(cssPath);
|
|
270
|
+
if (!uniqueImports.has(normalized)) {
|
|
271
|
+
uniqueImports.set(normalized, cssPath);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const sortedImports = [...uniqueImports.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
275
|
+
const regularCssSegments = [];
|
|
276
|
+
const moduleCssSegments = [];
|
|
277
|
+
for (const [normalizedCssPath, cssPath] of sortedImports) {
|
|
278
|
+
// Deduplicate only exact path matches to avoid skipping unrelated files
|
|
279
|
+
// like /styles/globals.css when the configured stylesheet is /globals.css.
|
|
280
|
+
if (normalizedCssPath === configuredStylesheetAbsolute) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const content = await this.config.adapter.fs.readFile(cssPath);
|
|
285
|
+
if (!content)
|
|
286
|
+
continue;
|
|
287
|
+
if (normalizedCssPath.endsWith(".module.css")) {
|
|
288
|
+
moduleCssSegments.push(rewriteCssModuleContent(content, normalizedCssPath));
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
regularCssSegments.push(content);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
logger.debug("Could not load imported CSS file", { cssPath });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (regularCssSegments.length === 0 && moduleCssSegments.length === 0)
|
|
299
|
+
return globalCSS;
|
|
300
|
+
const combined = [globalCSS, ...regularCssSegments, ...moduleCssSegments]
|
|
301
|
+
.filter(Boolean)
|
|
302
|
+
.join("\n");
|
|
303
|
+
logger.debug("Merged imported CSS with global stylesheet", {
|
|
304
|
+
importedCount: regularCssSegments.length + moduleCssSegments.length,
|
|
305
|
+
regularCount: regularCssSegments.length,
|
|
306
|
+
moduleCount: moduleCssSegments.length,
|
|
307
|
+
totalLength: combined.length,
|
|
308
|
+
});
|
|
309
|
+
return combined;
|
|
310
|
+
}
|
|
311
|
+
getProjectContentVersion() {
|
|
312
|
+
const wrappedFs = this.config.adapter.fs;
|
|
313
|
+
if (typeof wrappedFs.getUnderlyingAdapter !== "function")
|
|
314
|
+
return undefined;
|
|
315
|
+
const fsAdapter = wrappedFs.getUnderlyingAdapter();
|
|
316
|
+
return fsAdapter.getProjectData?.()?.updated_at;
|
|
317
|
+
}
|
|
318
|
+
buildRouteManifestKey(pagePath) {
|
|
319
|
+
const relativePagePath = extractRelativePath(pagePath, this.config.projectDir);
|
|
320
|
+
return relativePagePath
|
|
321
|
+
.replace(/\.(tsx|ts|jsx|mdx|md|js)$/, "")
|
|
322
|
+
.replace(/^pages\//, "");
|
|
323
|
+
}
|
|
324
|
+
async extractProjectClassesForRoute(context, appComponentPath) {
|
|
255
325
|
const classes = new Set();
|
|
256
326
|
const wrappedFs = this.config.adapter.fs;
|
|
257
327
|
if (typeof wrappedFs.getUnderlyingAdapter !== "function")
|
|
@@ -260,19 +330,34 @@ export class HTMLGenerator {
|
|
|
260
330
|
if (typeof fsAdapter.getAllSourceFiles !== "function")
|
|
261
331
|
return classes;
|
|
262
332
|
const files = await fsAdapter.getAllSourceFiles();
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
333
|
+
const projectScope = context.options?.projectSlug || context.options?.projectId ||
|
|
334
|
+
this.config.projectDir;
|
|
335
|
+
const projectVersion = this.getProjectContentVersion() ??
|
|
336
|
+
(this.config.mode === "development" ? "dev" : "unknown");
|
|
337
|
+
const routeKey = this.buildRouteManifestKey(context.pageInfo.entity.path);
|
|
338
|
+
const routeLayoutPaths = context.nestedLayouts
|
|
339
|
+
.map((layout) => layout.componentPath || layout.path)
|
|
340
|
+
.filter((path) => Boolean(path));
|
|
341
|
+
const routeFilePaths = [
|
|
342
|
+
context.pageInfo.entity.path,
|
|
343
|
+
...routeLayoutPaths,
|
|
344
|
+
...(appComponentPath ? [appComponentPath] : []),
|
|
345
|
+
];
|
|
346
|
+
const routeCandidates = getRouteCandidates({
|
|
347
|
+
projectScope,
|
|
348
|
+
projectVersion,
|
|
349
|
+
projectDir: this.config.projectDir,
|
|
350
|
+
routeKey,
|
|
351
|
+
routeFilePaths,
|
|
352
|
+
files,
|
|
353
|
+
developmentMode: this.config.mode === "development",
|
|
354
|
+
});
|
|
355
|
+
for (const cls of routeCandidates)
|
|
356
|
+
classes.add(cls);
|
|
274
357
|
logger.debug("extractProjectClasses", {
|
|
275
|
-
filesProcessed,
|
|
358
|
+
filesProcessed: files.length,
|
|
359
|
+
routeKey,
|
|
360
|
+
routeFileCount: routeFilePaths.length,
|
|
276
361
|
totalClasses: classes.size,
|
|
277
362
|
});
|
|
278
363
|
return classes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAwChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,eAAe,EAAE,eAAe,CAAC;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,OAAO,qBAAqB,EAAE,sBAAsB,CAAC;CAC1E;AAQD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,kBAAkB,CAAqB;gBAEnC,MAAM,EAAE,oBAAoB;IAaxC;;;OAGG;IACH,gBAAgB,IAAI,IAAI;IAKxB,OAAO,CAAC,UAAU;IAIlB;;;;;;;;;OASG;YACW,qBAAqB;IAsDnC;;;OAGG;YACW,mBAAmB;IAkH3B,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA4O9E,+EAA+E;IACzE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4KvF;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAetB"}
|
|
@@ -31,6 +31,7 @@ import { LAYOUT_EXTENSIONS } from "../layouts/types.js";
|
|
|
31
31
|
import { withTimeout, withTimeoutThrow } from "../utils/stream-utils.js";
|
|
32
32
|
import { generateTailwind4CSS } from "../../html/styles-builder/index.js";
|
|
33
33
|
import { createEsmCache, createModuleCache, loadModule } from "./module-loader/index.js";
|
|
34
|
+
import { getCSSImports, runWithCSSCollector, } from "../../modules/react-loader/css-import-collector.js";
|
|
34
35
|
// Extracted modules
|
|
35
36
|
import { EMPTY_LAYOUT_RESULT, isDotPath } from "./path-helpers.js";
|
|
36
37
|
import { cachePageCss, CSS_SSR_TIMEOUT_MS, getCachedPageCss, getPageCssCacheKey, } from "./css-cache.js";
|
|
@@ -215,7 +216,7 @@ export class RenderPipeline {
|
|
|
215
216
|
if (this.config.mode === "development") {
|
|
216
217
|
clearSSRModuleCacheForProject(projectId);
|
|
217
218
|
}
|
|
218
|
-
return withSpan("render.page", async () => {
|
|
219
|
+
return withSpan("render.page", () => runWithCSSCollector(async () => {
|
|
219
220
|
const pageResolveStart = performance.now();
|
|
220
221
|
const pageInfo = await withSpan("render.resolve_page", () => this.config.pageResolver.resolvePage(slug), { "render.slug": slug });
|
|
221
222
|
timing.pageResolve = Math.round(performance.now() - pageResolveStart);
|
|
@@ -283,6 +284,9 @@ export class RenderPipeline {
|
|
|
283
284
|
const layoutApplyStart = performance.now();
|
|
284
285
|
const wrappedElement = await withSpan("render.apply_layouts", () => this.config.layoutOrchestrator.applyLayoutsAndWrappers(pageElement, pageInfo, layoutResult.layoutBundle, layoutResult.nestedLayouts, layoutDataMap, options?.url, mergedFrontmatter, headings, options?.projectSlug), { "render.slug": slug, "render.layout_count": layoutResult.nestedLayouts.length });
|
|
285
286
|
timing.layoutApply = Math.round(performance.now() - layoutApplyStart);
|
|
287
|
+
// Snapshot CSS imports collected during module loading (before SSR rendering).
|
|
288
|
+
// These are passed to the HTML generator to be included in the output.
|
|
289
|
+
const collectedCSSImports = getCSSImports();
|
|
286
290
|
const ssrStart = performance.now();
|
|
287
291
|
const ssrResult = await withSpan("render.ssr", () => withTimeoutThrow(this.config.ssrOrchestrator.performSSRRendering(wrappedElement, {
|
|
288
292
|
pageInfo,
|
|
@@ -291,8 +295,16 @@ export class RenderPipeline {
|
|
|
291
295
|
nestedLayouts: layoutResult.nestedLayouts,
|
|
292
296
|
collectedMetadata: pageBundleResult.collectedMetadata,
|
|
293
297
|
slug,
|
|
298
|
+
cssImports: collectedCSSImports,
|
|
294
299
|
}, mergedOptions), SSR_RENDER_TIMEOUT_MS, `SSR rendering for ${slug}`), { "render.slug": slug, "render.delivery": mergedOptions?.delivery || "full" });
|
|
295
300
|
timing.ssr = Math.round(performance.now() - ssrStart);
|
|
301
|
+
if (collectedCSSImports.length > 0) {
|
|
302
|
+
renderPipelineLog.debug("CSS imports collected for HTML generation", {
|
|
303
|
+
slug,
|
|
304
|
+
count: collectedCSSImports.length,
|
|
305
|
+
paths: collectedCSSImports.map((p) => p.split("/").pop()),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
296
308
|
const pageModule = pageBundleResult.clientModuleCode && pageBundleResult.pageModuleType
|
|
297
309
|
? {
|
|
298
310
|
slug,
|
|
@@ -321,7 +333,7 @@ export class RenderPipeline {
|
|
|
321
333
|
timing.total = Math.round(performance.now() - pipelineStartTime);
|
|
322
334
|
renderPipelineLog.debug("Complete", { slug, timing });
|
|
323
335
|
return result;
|
|
324
|
-
}, {
|
|
336
|
+
}).then(({ result }) => result), {
|
|
325
337
|
"render.slug": slug,
|
|
326
338
|
"render.project_id": options?.projectId || this.config.projectDir,
|
|
327
339
|
"render.mode": this.config.mode,
|
|
@@ -9,6 +9,8 @@ export interface BootstrapResult {
|
|
|
9
9
|
usingFSAdapter: boolean;
|
|
10
10
|
/** FSAdapter type (if used) */
|
|
11
11
|
fsAdapterType?: string;
|
|
12
|
+
/** Dispose FSAdapter resources (WebSocket connections, caches) */
|
|
13
|
+
dispose?: () => void;
|
|
12
14
|
}
|
|
13
15
|
export declare function bootstrap(projectDir: string, adapter: RuntimeAdapter): Promise<BootstrapResult>;
|
|
14
16
|
export declare function bootstrapDev(projectDir: string, adapter: RuntimeAdapter): Promise<BootstrapResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/src/server/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/src/server/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA4B1D,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,EAAE,cAAc,CAAC;IAExB,2BAA2B;IAC3B,MAAM,EAAE,eAAe,CAAC;IAExB,wCAAwC;IACxC,cAAc,EAAE,OAAO,CAAC;IAExB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAkDD,wBAAsB,SAAS,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAqG1B;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAa1B;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
|
|
@@ -2,6 +2,7 @@ import { clearConfigCache, getConfig } from "../config/index.js";
|
|
|
2
2
|
import { getEnvironmentConfig, refreshEnvironmentConfig, } from "../config/environment-config.js";
|
|
3
3
|
import { getErrorMessage } from "../errors/veryfront-error.js";
|
|
4
4
|
import { enhanceAdapterWithFS } from "../platform/adapters/fs/integration.js";
|
|
5
|
+
import { isExtendedFSAdapter } from "../platform/adapters/fs/wrapper.js";
|
|
5
6
|
import { getEnv } from "../platform/compat/process.js";
|
|
6
7
|
import { initializeEsbuild } from "../platform/compat/esbuild.js";
|
|
7
8
|
import { logger } from "../utils/index.js";
|
|
@@ -120,11 +121,20 @@ export async function bootstrap(projectDir, adapter) {
|
|
|
120
121
|
runtime: adapter.id,
|
|
121
122
|
fsAdapter: fsType,
|
|
122
123
|
});
|
|
124
|
+
let dispose;
|
|
125
|
+
if (isExtendedFSAdapter(enhancedAdapter.fs)) {
|
|
126
|
+
const underlying = enhancedAdapter.fs.getUnderlyingAdapter();
|
|
127
|
+
if ("dispose" in underlying &&
|
|
128
|
+
typeof underlying.dispose === "function") {
|
|
129
|
+
dispose = () => underlying.dispose();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
123
132
|
return {
|
|
124
133
|
adapter: enhancedAdapter,
|
|
125
134
|
config,
|
|
126
135
|
usingFSAdapter: true,
|
|
127
136
|
fsAdapterType: fsType,
|
|
137
|
+
dispose,
|
|
128
138
|
};
|
|
129
139
|
}
|
|
130
140
|
export async function bootstrapDev(projectDir, adapter) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-html-generator.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-html-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAMrD,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,gDAAgD;IAChD,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"markdown-html-generator.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-html-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAMrD,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,gDAAgD;IAChD,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgDD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CA0FzE"}
|
|
@@ -21,16 +21,22 @@ function detectTheme(req, url) {
|
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Generate the studio bridge `<script>` tag
|
|
25
|
-
*
|
|
24
|
+
* Generate the studio bridge `<script>` tag.
|
|
25
|
+
* Injected when embedded in Studio (`studio_embed=true`) or for standalone
|
|
26
|
+
* markdown/MDX pages so the edit button and editor features are available.
|
|
26
27
|
*/
|
|
27
28
|
function buildStudioScript(url, projectId, filePath) {
|
|
28
29
|
const studioEmbed = url.searchParams.get("studio_embed") === "true";
|
|
29
|
-
|
|
30
|
+
const isMarkdown = /\.mdx?$/i.test(filePath);
|
|
31
|
+
if (!studioEmbed && !isMarkdown)
|
|
30
32
|
return "";
|
|
33
|
+
const queryProjectId = url.searchParams.get("vf_project_id")?.trim() || "";
|
|
34
|
+
const queryFileId = url.searchParams.get("vf_file_id")?.trim() || "";
|
|
35
|
+
const canonicalProjectId = queryProjectId || projectId;
|
|
36
|
+
const canonicalPageId = queryFileId || filePath;
|
|
31
37
|
return `<script>${generateStudioBridgeScript({
|
|
32
|
-
projectId,
|
|
33
|
-
pageId:
|
|
38
|
+
projectId: canonicalProjectId,
|
|
39
|
+
pageId: canonicalPageId,
|
|
34
40
|
pagePath: filePath,
|
|
35
41
|
})}</script>`;
|
|
36
42
|
}
|
|
@@ -170,12 +170,14 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
170
170
|
// BIND_ADDRESS: 0.0.0.0 = all interfaces, 127.0.0.1 = localhost only
|
|
171
171
|
// Note: Don't use HOSTNAME - K8s sets it to pod name which resolves to pod IP
|
|
172
172
|
const bindAddress = adapter.env.get("BIND_ADDRESS") ?? "0.0.0.0";
|
|
173
|
+
const bootstrap = await bootstrapProd(projectDir, adapter);
|
|
173
174
|
const server = await startProductionServer({
|
|
174
175
|
projectDir,
|
|
175
176
|
port,
|
|
176
177
|
bindAddress,
|
|
177
178
|
debug: isDebugEnabled(adapter.env),
|
|
178
179
|
adapter, // Pass adapter to avoid re-detection
|
|
180
|
+
bootstrapResult: bootstrap,
|
|
179
181
|
signal: shutdownController.signal,
|
|
180
182
|
});
|
|
181
183
|
// Wait for server to be fully ready before accepting traffic
|
|
@@ -209,6 +211,7 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
209
211
|
// Phase 3: Stop accepting new connections and clean up
|
|
210
212
|
stopMemoryMonitoring();
|
|
211
213
|
requestTracker.shutdown();
|
|
214
|
+
bootstrap.dispose?.();
|
|
212
215
|
shutdownController.abort();
|
|
213
216
|
await server.stop();
|
|
214
217
|
await shutdownOTLP();
|
|
@@ -218,8 +221,13 @@ if (globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).main) {
|
|
|
218
221
|
logger.warn("Error while shutting down production server:", error);
|
|
219
222
|
}
|
|
220
223
|
};
|
|
221
|
-
|
|
222
|
-
|
|
224
|
+
const handleSignal = (signal) => {
|
|
225
|
+
void shutdown(signal).catch((error) => {
|
|
226
|
+
logger.warn("Unhandled error while shutting down production server", { signal, error });
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
onSignal("SIGINT", () => handleSignal("SIGINT"));
|
|
230
|
+
onSignal("SIGTERM", () => handleSignal("SIGTERM"));
|
|
223
231
|
}
|
|
224
232
|
catch (e) {
|
|
225
233
|
logger.error("Failed to start production server:", e);
|
|
@@ -2,6 +2,8 @@ export interface StudioBridgeOptions {
|
|
|
2
2
|
projectId: string;
|
|
3
3
|
pageId: string;
|
|
4
4
|
pagePath?: string;
|
|
5
|
+
debugSkipInit?: boolean;
|
|
6
|
+
debugExposeInternals?: boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare function generateStudioBridgeScript(options: StudioBridgeOptions): string;
|
|
7
9
|
//# sourceMappingURL=bridge-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-template.d.ts","sourceRoot":"","sources":["../../../src/src/studio/bridge-template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge-template.d.ts","sourceRoot":"","sources":["../../../src/src/studio/bridge-template.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAy/H/E"}
|