@ecopages/core 0.2.0-alpha.26 → 0.2.0-alpha.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/CHANGELOG.md +25 -0
- package/README.md +63 -7
- package/package.json +8 -94
- package/src/adapters/bun/create-app.d.ts +1 -0
- package/src/adapters/bun/create-app.js +39 -2
- package/src/adapters/bun/hmr-manager.d.ts +1 -13
- package/src/adapters/bun/hmr-manager.js +1 -22
- package/src/adapters/bun/server-adapter.js +23 -4
- package/src/adapters/node/node-hmr-manager.d.ts +2 -14
- package/src/adapters/node/node-hmr-manager.js +2 -23
- package/src/adapters/shared/explicit-static-render-preparation.d.ts +25 -0
- package/src/adapters/shared/explicit-static-render-preparation.js +26 -0
- package/src/adapters/shared/explicit-static-route-matcher.d.ts +5 -2
- package/src/adapters/shared/explicit-static-route-matcher.js +14 -16
- package/src/adapters/shared/file-route-middleware-pipeline.d.ts +7 -10
- package/src/adapters/shared/file-route-middleware-pipeline.js +2 -11
- package/src/adapters/shared/fs-server-response-factory.d.ts +13 -9
- package/src/adapters/shared/fs-server-response-factory.js +10 -26
- package/src/adapters/shared/fs-server-response-matcher.d.ts +14 -6
- package/src/adapters/shared/fs-server-response-matcher.js +67 -28
- package/src/adapters/shared/render-context.d.ts +2 -2
- package/src/adapters/shared/server-adapter.d.ts +21 -10
- package/src/adapters/shared/server-adapter.js +171 -132
- package/src/adapters/shared/server-route-handler.d.ts +2 -2
- package/src/adapters/shared/server-route-handler.js +1 -1
- package/src/adapters/shared/server-static-builder.d.ts +4 -4
- package/src/config/README.md +1 -1
- package/src/config/config-builder.d.ts +2 -2
- package/src/config/config-builder.js +0 -5
- package/src/dev/host-runtime.d.ts +10 -0
- package/src/dev/host-runtime.js +24 -0
- package/src/eco/eco.js +7 -7
- package/src/eco/eco.types.d.ts +3 -3
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +3 -1
- package/src/hmr/strategies/js-hmr-strategy.d.ts +0 -5
- package/src/integrations/ghtml/ghtml-renderer.d.ts +0 -4
- package/src/integrations/ghtml/ghtml-renderer.js +1 -7
- package/src/plugins/eco-component-meta-plugin.js +0 -1
- package/src/plugins/integration-plugin.d.ts +14 -18
- package/src/plugins/integration-plugin.js +14 -21
- package/src/plugins/processor.d.ts +2 -0
- package/src/plugins/processor.js +6 -1
- package/src/route-renderer/GRAPH.md +81 -289
- package/src/route-renderer/README.md +67 -105
- package/src/route-renderer/orchestration/component-render-context.d.ts +24 -18
- package/src/route-renderer/orchestration/component-render-context.js +14 -14
- package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +18 -0
- package/src/route-renderer/orchestration/declared-ownership-graph.js +34 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +108 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +206 -0
- package/src/route-renderer/orchestration/integration-renderer.d.ts +96 -136
- package/src/route-renderer/orchestration/integration-renderer.js +280 -303
- package/src/route-renderer/orchestration/ownership-planning.service.d.ts +24 -0
- package/src/route-renderer/orchestration/ownership-planning.service.js +63 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +29 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +53 -0
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +90 -0
- package/src/route-renderer/orchestration/{queued-boundary-runtime.service.js → queued-foreign-subtree-resolution.service.js} +28 -25
- package/src/route-renderer/orchestration/render-output.utils.d.ts +3 -3
- package/src/route-renderer/orchestration/render-output.utils.js +6 -6
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +120 -0
- package/src/route-renderer/orchestration/{render-preparation.service.js → route-render-orchestrator.js} +132 -108
- package/src/route-renderer/page-loading/component-dependency-collection.js +8 -1
- package/src/route-renderer/page-loading/dependency-resolver.js +5 -7
- package/src/route-renderer/page-loading/page-dependency-bundling.d.ts +1 -1
- package/src/route-renderer/page-loading/page-dependency-bundling.js +41 -19
- package/src/route-renderer/route-renderer.d.ts +28 -26
- package/src/route-renderer/route-renderer.js +4 -27
- package/src/router/README.md +16 -19
- package/src/router/server/route-registry.d.ts +78 -0
- package/src/router/server/route-registry.js +262 -0
- package/src/services/README.md +1 -2
- package/src/services/assets/asset-processing-service/assets.types.d.ts +3 -0
- package/src/services/assets/asset-processing-service/index.d.ts +1 -0
- package/src/services/assets/asset-processing-service/index.js +1 -0
- package/src/services/assets/asset-processing-service/page-package.d.ts +3 -0
- package/src/services/assets/asset-processing-service/page-package.js +74 -0
- package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +4 -4
- package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +6 -3
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +9 -3
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +4 -2
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -1
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +3 -1
- package/src/services/module-loading/node-bootstrap-plugin.js +15 -3
- package/src/static-site-generator/static-site-generator.d.ts +20 -21
- package/src/static-site-generator/static-site-generator.js +107 -140
- package/src/types/internal-types.d.ts +13 -12
- package/src/types/public-types.d.ts +46 -36
- package/src/watchers/project-watcher.test-helpers.js +5 -5
- package/src/route-renderer/orchestration/boundary-planning.service.d.ts +0 -25
- package/src/route-renderer/orchestration/boundary-planning.service.js +0 -97
- package/src/route-renderer/orchestration/page-packaging.service.d.ts +0 -16
- package/src/route-renderer/orchestration/page-packaging.service.js +0 -66
- package/src/route-renderer/orchestration/queued-boundary-runtime.service.d.ts +0 -89
- package/src/route-renderer/orchestration/render-execution.service.d.ts +0 -43
- package/src/route-renderer/orchestration/render-execution.service.js +0 -106
- package/src/route-renderer/orchestration/render-preparation.service.d.ts +0 -120
- package/src/route-renderer/orchestration/route-shell-composer.service.d.ts +0 -50
- package/src/route-renderer/orchestration/route-shell-composer.service.js +0 -81
- package/src/router/server/fs-router-scanner.d.ts +0 -41
- package/src/router/server/fs-router-scanner.js +0 -161
- package/src/router/server/fs-router.d.ts +0 -26
- package/src/router/server/fs-router.js +0 -100
- package/src/services/runtime-state/runtime-specifier-registry.service.d.ts +0 -69
- package/src/services/runtime-state/runtime-specifier-registry.service.js +0 -37
|
@@ -48,7 +48,8 @@ class ContentStylesheetProcessor extends BaseProcessor {
|
|
|
48
48
|
position: dep.position,
|
|
49
49
|
attributes: dep.attributes,
|
|
50
50
|
inline: dep.inline,
|
|
51
|
-
packageRole: dep.packageRole
|
|
51
|
+
packageRole: dep.packageRole,
|
|
52
|
+
bundledSourceFilepaths: dep.bundledSourceFilepaths
|
|
52
53
|
};
|
|
53
54
|
});
|
|
54
55
|
}
|
|
@@ -52,12 +52,14 @@ class FileStylesheetProcessor extends BaseProcessor {
|
|
|
52
52
|
}
|
|
53
53
|
return {
|
|
54
54
|
filepath,
|
|
55
|
+
sourceFilepath: dep.filepath,
|
|
55
56
|
content: dep.inline ? processedContent : void 0,
|
|
56
57
|
kind: "stylesheet",
|
|
57
58
|
position: dep.position,
|
|
58
59
|
attributes: dep.attributes,
|
|
59
60
|
inline: dep.inline,
|
|
60
|
-
packageRole: dep.packageRole
|
|
61
|
+
packageRole: dep.packageRole,
|
|
62
|
+
bundledSourceFilepaths: dep.bundledSourceFilepaths
|
|
61
63
|
};
|
|
62
64
|
});
|
|
63
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync } from "node:fs";
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { resolveInternalExecutionDir } from "../../utils/resolve-work-dir.js";
|
|
@@ -51,7 +51,7 @@ function ensureRuntimePackageLink(nodeModulesDir, specifier, resolvedPath) {
|
|
|
51
51
|
if (linkPointsToPackage(linkPath, packageRoot)) {
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
removeRuntimePackageLink(linkPath);
|
|
55
55
|
}
|
|
56
56
|
try {
|
|
57
57
|
symlinkSync(packageRoot, linkPath, "dir");
|
|
@@ -62,10 +62,22 @@ function ensureRuntimePackageLink(nodeModulesDir, specifier, resolvedPath) {
|
|
|
62
62
|
if (linkPointsToPackage(linkPath, packageRoot)) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
removeRuntimePackageLink(linkPath);
|
|
66
66
|
symlinkSync(packageRoot, linkPath, "dir");
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
function removeRuntimePackageLink(linkPath) {
|
|
70
|
+
try {
|
|
71
|
+
const stats = lstatSync(linkPath);
|
|
72
|
+
if (stats.isSymbolicLink()) {
|
|
73
|
+
unlinkSync(linkPath);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
rmSync(linkPath, { recursive: true, force: true });
|
|
80
|
+
}
|
|
69
81
|
function getNodeUnsupportedBuiltinError(specifier, importer) {
|
|
70
82
|
return `Node bootstrap transpilation does not support Bun builtin specifier ${JSON.stringify(specifier)}${importer ? ` imported from ${importer}` : ""}.`;
|
|
71
83
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { EcoPagesAppConfig } from '../types/internal-types.js';
|
|
2
2
|
import type { StaticRoute } from '../types/public-types.js';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { PageRendererResolver, StaticGenerationRendererResolver } from '../route-renderer/route-renderer.js';
|
|
4
|
+
import type { StaticGenerationRoute } from '../router/server/route-registry.js';
|
|
5
|
+
type StaticGenerationRouteSource = {
|
|
6
|
+
listStaticGenerationRoutes(input: {
|
|
7
|
+
runtimeOrigin: string;
|
|
8
|
+
}): Promise<readonly StaticGenerationRoute[]>;
|
|
9
|
+
};
|
|
10
|
+
type StaticPageRouteRendererFactory = PageRendererResolver;
|
|
11
|
+
type StaticGenerationRendererFactory = StaticGenerationRendererResolver;
|
|
5
12
|
export declare const STATIC_SITE_GENERATOR_ERRORS: {
|
|
6
13
|
readonly ROUTE_RENDERER_FACTORY_REQUIRED: "RouteRendererFactory is required for render strategy";
|
|
7
14
|
readonly unsupportedBodyType: (bodyType: string) => string;
|
|
@@ -53,14 +60,9 @@ export declare class StaticSiteGenerator {
|
|
|
53
60
|
* Collects parent directories that must exist for the generated route set.
|
|
54
61
|
*/
|
|
55
62
|
getDirectories(routes: string[]): string[];
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* @param templatePath - The template path (e.g., "/blog/[slug]")
|
|
60
|
-
* @param actualPath - The actual path (e.g., "/blog/my-post")
|
|
61
|
-
* @returns A record of extracted parameters (e.g., { slug: "my-post" })
|
|
62
|
-
*/
|
|
63
|
-
private extractParams;
|
|
63
|
+
private writeStaticOutput;
|
|
64
|
+
private getStaticBuildStrategy;
|
|
65
|
+
private createFilesystemStaticContents;
|
|
64
66
|
/**
|
|
65
67
|
* Generates static output for all filesystem-discovered routes.
|
|
66
68
|
*
|
|
@@ -69,15 +71,15 @@ export declare class StaticSiteGenerator {
|
|
|
69
71
|
* issuing a request against the running server origin. Render-strategy routes
|
|
70
72
|
* go through the normal route renderer directly.
|
|
71
73
|
*/
|
|
72
|
-
generateStaticPages(router:
|
|
74
|
+
generateStaticPages(router: StaticGenerationRouteSource, baseUrl: string, routeRendererFactory?: StaticPageRouteRendererFactory): Promise<void>;
|
|
73
75
|
private resolveStaticFetchUrl;
|
|
74
76
|
/**
|
|
75
77
|
* Executes the full static-generation workflow for one app run.
|
|
76
78
|
*/
|
|
77
79
|
run({ router, baseUrl, routeRendererFactory, staticRoutes, }: {
|
|
78
|
-
router:
|
|
80
|
+
router: StaticGenerationRouteSource;
|
|
79
81
|
baseUrl: string;
|
|
80
|
-
routeRendererFactory?:
|
|
82
|
+
routeRendererFactory?: StaticGenerationRendererFactory;
|
|
81
83
|
staticRoutes?: StaticRoute[];
|
|
82
84
|
}): Promise<void>;
|
|
83
85
|
/**
|
|
@@ -85,14 +87,10 @@ export declare class StaticSiteGenerator {
|
|
|
85
87
|
* These routes use eco.page views via loader functions for HMR support.
|
|
86
88
|
*/
|
|
87
89
|
private generateExplicitStaticPages;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
private
|
|
92
|
-
/**
|
|
93
|
-
* Generate static pages for a dynamic route using staticPaths.
|
|
94
|
-
*/
|
|
95
|
-
private generateDynamicStaticRoute;
|
|
90
|
+
private generateExplicitStaticRoute;
|
|
91
|
+
private planExplicitStaticRoute;
|
|
92
|
+
private createExplicitStaticContents;
|
|
93
|
+
private listExplicitStaticRouteEntries;
|
|
96
94
|
/**
|
|
97
95
|
* Resolve a route path template with actual params.
|
|
98
96
|
* Supports both :param and [param] syntax.
|
|
@@ -103,3 +101,4 @@ export declare class StaticSiteGenerator {
|
|
|
103
101
|
*/
|
|
104
102
|
private getOutputPath;
|
|
105
103
|
}
|
|
104
|
+
export {};
|
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { appLogger } from "../global/app-logger.js";
|
|
3
3
|
import { fileSystem } from "@ecopages/file-system";
|
|
4
4
|
import { PathUtils } from "../utils/path-utils.module.js";
|
|
5
|
+
import { prepareExplicitStaticRender } from "../adapters/shared/explicit-static-render-preparation.js";
|
|
5
6
|
const STATIC_SITE_GENERATOR_ERRORS = {
|
|
6
7
|
ROUTE_RENDERER_FACTORY_REQUIRED: "RouteRendererFactory is required for render strategy",
|
|
7
8
|
unsupportedBodyType: (bodyType) => `Unsupported body type for static generation: ${bodyType}`,
|
|
@@ -34,7 +35,7 @@ class StaticSiteGenerator {
|
|
|
34
35
|
* static generation.
|
|
35
36
|
*/
|
|
36
37
|
async shouldSkipStaticPageFile(filePath, routeRendererFactory) {
|
|
37
|
-
const module = await routeRendererFactory.
|
|
38
|
+
const module = await routeRendererFactory.getPageRenderer(filePath).loadPageModule(filePath, {
|
|
38
39
|
cacheScope: "static-page-probe"
|
|
39
40
|
});
|
|
40
41
|
if (module.default?.cache !== "dynamic") {
|
|
@@ -93,25 +94,50 @@ class StaticSiteGenerator {
|
|
|
93
94
|
}
|
|
94
95
|
return Array.from(directories);
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
writeStaticOutput(routePath, contents, directories = []) {
|
|
98
|
+
const outputPath = this.getOutputPath(routePath, directories);
|
|
99
|
+
fileSystem.ensureDir(path.dirname(outputPath));
|
|
100
|
+
fileSystem.write(outputPath, contents);
|
|
101
|
+
return outputPath;
|
|
102
|
+
}
|
|
103
|
+
getStaticBuildStrategy(filePath) {
|
|
104
|
+
const ext = PathUtils.getEcoTemplateExtension(filePath);
|
|
105
|
+
const integration = this.appConfig.integrations.find((plugin) => plugin.extensions.includes(ext));
|
|
106
|
+
return integration?.staticBuildStep || "render";
|
|
107
|
+
}
|
|
108
|
+
async createFilesystemStaticContents(route, baseUrl, routeRendererFactory) {
|
|
109
|
+
const {
|
|
110
|
+
templateRoute: { filePath },
|
|
111
|
+
params
|
|
112
|
+
} = route;
|
|
113
|
+
if (this.getStaticBuildStrategy(filePath) === "fetch") {
|
|
114
|
+
const fetchUrl = this.resolveStaticFetchUrl(route.requestUrl, baseUrl);
|
|
115
|
+
const response = await fetch(fetchUrl);
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
appLogger.error(`Failed to fetch ${fetchUrl}. Status: ${response.status}`);
|
|
118
|
+
return null;
|
|
112
119
|
}
|
|
120
|
+
return response.text();
|
|
121
|
+
}
|
|
122
|
+
if (!routeRendererFactory) {
|
|
123
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
124
|
+
}
|
|
125
|
+
if (await this.shouldSkipStaticPageFile(filePath, routeRendererFactory)) {
|
|
126
|
+
return null;
|
|
113
127
|
}
|
|
114
|
-
|
|
128
|
+
const renderer = routeRendererFactory.getPageRenderer(filePath);
|
|
129
|
+
const result = await renderer.execute({
|
|
130
|
+
file: filePath,
|
|
131
|
+
params
|
|
132
|
+
});
|
|
133
|
+
const body = result.body;
|
|
134
|
+
if (typeof body === "string" || Buffer.isBuffer(body)) {
|
|
135
|
+
return body;
|
|
136
|
+
}
|
|
137
|
+
if (body instanceof ReadableStream) {
|
|
138
|
+
return new Response(body).text();
|
|
139
|
+
}
|
|
140
|
+
throw new Error(STATIC_SITE_GENERATOR_ERRORS.unsupportedBodyType(typeof body));
|
|
115
141
|
}
|
|
116
142
|
/**
|
|
117
143
|
* Generates static output for all filesystem-discovered routes.
|
|
@@ -122,76 +148,22 @@ class StaticSiteGenerator {
|
|
|
122
148
|
* go through the normal route renderer directly.
|
|
123
149
|
*/
|
|
124
150
|
async generateStaticPages(router, baseUrl, routeRendererFactory) {
|
|
125
|
-
const routes =
|
|
126
|
-
appLogger.debug(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
const routes = await router.listStaticGenerationRoutes({ runtimeOrigin: baseUrl });
|
|
152
|
+
appLogger.debug(
|
|
153
|
+
"Static Pages",
|
|
154
|
+
routes.map((route) => route.requestUrl)
|
|
155
|
+
);
|
|
156
|
+
const directories = this.getDirectories(routes.map((route) => route.requestUrl));
|
|
131
157
|
for (const route of routes) {
|
|
132
158
|
try {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const strategy = integration?.staticBuildStep || "render";
|
|
137
|
-
let contents;
|
|
138
|
-
if (strategy === "fetch") {
|
|
139
|
-
const fetchUrl = this.resolveStaticFetchUrl(route, baseUrl);
|
|
140
|
-
const response = await fetch(fetchUrl);
|
|
141
|
-
if (!response.ok) {
|
|
142
|
-
appLogger.error(`Failed to fetch ${fetchUrl}. Status: ${response.status}`);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
contents = await response.text();
|
|
146
|
-
} else {
|
|
147
|
-
if (!routeRendererFactory) {
|
|
148
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.ROUTE_RENDERER_FACTORY_REQUIRED);
|
|
149
|
-
}
|
|
150
|
-
if (await this.shouldSkipStaticPageFile(filePath, routeRendererFactory)) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
let pathname2 = routePathname;
|
|
154
|
-
const pathnameSegments2 = pathname2.split("/").filter(Boolean);
|
|
155
|
-
if (pathname2 === "/") {
|
|
156
|
-
pathname2 = "/index.html";
|
|
157
|
-
} else if (pathnameSegments2.join("/").includes("[")) {
|
|
158
|
-
pathname2 = `${route.replace(router.origin, "")}.html`;
|
|
159
|
-
} else if (pathnameSegments2.length >= 1 && directories.includes(`/${pathnameSegments2.join("/")}`)) {
|
|
160
|
-
pathname2 = `${pathname2.endsWith("/") ? pathname2 : `${pathname2}/`}index.html`;
|
|
161
|
-
} else {
|
|
162
|
-
pathname2 += ".html";
|
|
163
|
-
}
|
|
164
|
-
const renderer = routeRendererFactory.createRenderer(filePath);
|
|
165
|
-
const params = this.extractParams(routePathname, pathname2.replace(".html", ""));
|
|
166
|
-
const result = await renderer.createRoute({
|
|
167
|
-
file: filePath,
|
|
168
|
-
params
|
|
169
|
-
});
|
|
170
|
-
const body = result.body;
|
|
171
|
-
if (typeof body === "string" || Buffer.isBuffer(body)) {
|
|
172
|
-
contents = body;
|
|
173
|
-
} else if (body instanceof ReadableStream) {
|
|
174
|
-
contents = await new Response(body).text();
|
|
175
|
-
} else {
|
|
176
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.unsupportedBodyType(typeof body));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
let pathname = routePathname;
|
|
180
|
-
const pathnameSegments = pathname.split("/").filter(Boolean);
|
|
181
|
-
if (pathname === "/") {
|
|
182
|
-
pathname = "/index.html";
|
|
183
|
-
} else if (pathnameSegments.join("/").includes("[")) {
|
|
184
|
-
pathname = `${route.replace(router.origin, "")}.html`;
|
|
185
|
-
} else if (pathnameSegments.length >= 1 && directories.includes(`/${pathnameSegments.join("/")}`)) {
|
|
186
|
-
pathname = `${pathname.endsWith("/") ? pathname : `${pathname}/`}index.html`;
|
|
187
|
-
} else {
|
|
188
|
-
pathname += ".html";
|
|
159
|
+
const contents = await this.createFilesystemStaticContents(route, baseUrl, routeRendererFactory);
|
|
160
|
+
if (contents === null) {
|
|
161
|
+
continue;
|
|
189
162
|
}
|
|
190
|
-
|
|
191
|
-
fileSystem.write(outputPath, contents);
|
|
163
|
+
this.writeStaticOutput(route.pathname, contents, directories);
|
|
192
164
|
} catch (error) {
|
|
193
165
|
appLogger.error(
|
|
194
|
-
`Error generating static page for ${route}:`,
|
|
166
|
+
`Error generating static page for ${route.requestUrl}:`,
|
|
195
167
|
error instanceof Error ? error : String(error)
|
|
196
168
|
);
|
|
197
169
|
}
|
|
@@ -239,12 +211,7 @@ class StaticSiteGenerator {
|
|
|
239
211
|
if (this.shouldSkipStaticView(route.path, view)) {
|
|
240
212
|
continue;
|
|
241
213
|
}
|
|
242
|
-
|
|
243
|
-
if (isDynamic) {
|
|
244
|
-
await this.generateDynamicStaticRoute(route.path, view, routeRendererFactory);
|
|
245
|
-
} else {
|
|
246
|
-
await this.generateSingleStaticRoute(route.path, view, routeRendererFactory);
|
|
247
|
-
}
|
|
214
|
+
await this.generateExplicitStaticRoute(route.path, view, routeRendererFactory);
|
|
248
215
|
} catch (error) {
|
|
249
216
|
appLogger.error(
|
|
250
217
|
`Error generating explicit static page for ${route.path}:`,
|
|
@@ -253,63 +220,64 @@ class StaticSiteGenerator {
|
|
|
253
220
|
}
|
|
254
221
|
}
|
|
255
222
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
223
|
+
async generateExplicitStaticRoute(routePath, view, routeRendererFactory) {
|
|
224
|
+
const { renderer, routeEntries } = await this.planExplicitStaticRoute(routePath, view, routeRendererFactory);
|
|
225
|
+
for (const { pathname, params } of routeEntries) {
|
|
226
|
+
const contents = await this.createExplicitStaticContents(
|
|
227
|
+
routePath,
|
|
228
|
+
view,
|
|
229
|
+
params,
|
|
230
|
+
routeRendererFactory,
|
|
231
|
+
renderer
|
|
232
|
+
);
|
|
233
|
+
const outputPath = this.writeStaticOutput(pathname, contents);
|
|
234
|
+
appLogger.debug(`Generated static page: ${pathname} -> ${outputPath}`);
|
|
267
235
|
}
|
|
268
|
-
|
|
269
|
-
|
|
236
|
+
}
|
|
237
|
+
async planExplicitStaticRoute(routePath, view, routeRendererFactory) {
|
|
238
|
+
const { renderer } = await prepareExplicitStaticRender({
|
|
239
|
+
routePath,
|
|
240
|
+
view,
|
|
241
|
+
params: {},
|
|
270
242
|
appConfig: this.appConfig,
|
|
271
|
-
runtimeOrigin: this.appConfig.baseUrl
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
243
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
244
|
+
routeRendererFactory,
|
|
245
|
+
errors: STATIC_SITE_GENERATOR_ERRORS
|
|
246
|
+
});
|
|
247
|
+
return {
|
|
248
|
+
renderer,
|
|
249
|
+
routeEntries: await this.listExplicitStaticRouteEntries(routePath, view)
|
|
250
|
+
};
|
|
279
251
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
252
|
+
async createExplicitStaticContents(routePath, view, params, routeRendererFactory, renderer) {
|
|
253
|
+
const { props, view: renderableView } = await prepareExplicitStaticRender({
|
|
254
|
+
routePath,
|
|
255
|
+
view,
|
|
256
|
+
params,
|
|
257
|
+
appConfig: this.appConfig,
|
|
258
|
+
runtimeOrigin: this.appConfig.baseUrl,
|
|
259
|
+
routeRendererFactory,
|
|
260
|
+
errors: STATIC_SITE_GENERATOR_ERRORS
|
|
261
|
+
});
|
|
262
|
+
const response = await renderer.renderToResponse(renderableView, props, {});
|
|
263
|
+
return response.text();
|
|
264
|
+
}
|
|
265
|
+
async listExplicitStaticRouteEntries(routePath, view) {
|
|
266
|
+
const isDynamic = routePath.includes(":") || routePath.includes("[");
|
|
267
|
+
if (!isDynamic) {
|
|
268
|
+
return [{ pathname: routePath, params: {} }];
|
|
269
|
+
}
|
|
284
270
|
if (!view.staticPaths) {
|
|
285
271
|
throw new Error(STATIC_SITE_GENERATOR_ERRORS.dynamicRouteRequiresStaticPaths(routePath));
|
|
286
272
|
}
|
|
287
|
-
const integrationName = view.config?.__eco?.integration;
|
|
288
|
-
if (!integrationName) {
|
|
289
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.missingIntegration(routePath));
|
|
290
|
-
}
|
|
291
|
-
const renderer = routeRendererFactory.getRendererByIntegration(integrationName);
|
|
292
|
-
if (!renderer) {
|
|
293
|
-
throw new Error(STATIC_SITE_GENERATOR_ERRORS.noRendererForIntegration(integrationName));
|
|
294
|
-
}
|
|
295
273
|
const { paths } = await view.staticPaths({
|
|
296
274
|
appConfig: this.appConfig,
|
|
297
275
|
runtimeOrigin: this.appConfig.baseUrl
|
|
298
276
|
});
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
appConfig: this.appConfig,
|
|
304
|
-
runtimeOrigin: this.appConfig.baseUrl
|
|
305
|
-
})).props : {};
|
|
306
|
-
const response = await renderer.renderToResponse(view, props, {});
|
|
307
|
-
const contents = await response.text();
|
|
308
|
-
const outputPath = this.getOutputPath(resolvedPath);
|
|
309
|
-
fileSystem.ensureDir(path.dirname(outputPath));
|
|
310
|
-
fileSystem.write(outputPath, contents);
|
|
311
|
-
appLogger.debug(`Generated static page: ${resolvedPath} -> ${outputPath}`);
|
|
312
|
-
}
|
|
277
|
+
return paths.map(({ params }) => ({
|
|
278
|
+
pathname: this.resolveRoutePath(routePath, params),
|
|
279
|
+
params
|
|
280
|
+
}));
|
|
313
281
|
}
|
|
314
282
|
/**
|
|
315
283
|
* Resolve a route path template with actual params.
|
|
@@ -328,10 +296,12 @@ class StaticSiteGenerator {
|
|
|
328
296
|
/**
|
|
329
297
|
* Get the output file path for a given route.
|
|
330
298
|
*/
|
|
331
|
-
getOutputPath(routePath) {
|
|
299
|
+
getOutputPath(routePath, directories = []) {
|
|
332
300
|
let outputName;
|
|
333
301
|
if (routePath === "/") {
|
|
334
302
|
outputName = "index.html";
|
|
303
|
+
} else if (directories.includes(routePath)) {
|
|
304
|
+
outputName = `${routePath}/index.html`;
|
|
335
305
|
} else if (routePath.endsWith("/")) {
|
|
336
306
|
outputName = `${routePath}index.html`;
|
|
337
307
|
} else {
|
|
@@ -340,9 +310,6 @@ class StaticSiteGenerator {
|
|
|
340
310
|
return path.join(this.getExportDir(), outputName);
|
|
341
311
|
}
|
|
342
312
|
}
|
|
343
|
-
function templateSegmentsFromPath(path2) {
|
|
344
|
-
return path2.split("/").filter(Boolean);
|
|
345
|
-
}
|
|
346
313
|
export {
|
|
347
314
|
STATIC_SITE_GENERATOR_ERRORS,
|
|
348
315
|
StaticSiteGenerator
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { EcoBuildPlugin } from '../build/build-types.js';
|
|
2
2
|
import type { AppBuildManifest } from '../build/build-manifest.js';
|
|
3
3
|
import type { BuildAdapter, BuildExecutor, BuildOwnership } from '../build/build-adapter.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { AnyIntegrationPlugin } from '../plugins/integration-plugin.js';
|
|
5
5
|
import type { Processor } from '../plugins/processor.js';
|
|
6
6
|
import type { EcoSourceTransform } from '../plugins/source-transform.js';
|
|
7
7
|
import type { PageMetadataProps } from './public-types.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { RouteRegistry } from '../router/server/route-registry.js';
|
|
9
9
|
import type { CacheConfig } from '../services/cache/cache.types.js';
|
|
10
10
|
import type { DevGraphService } from '../services/runtime-state/dev-graph.service.js';
|
|
11
11
|
import type { AppModuleLoader } from '../services/module-loading/app-module-loader.service.js';
|
|
12
12
|
import type { SourceModuleLoader } from '../services/module-loading/module-loading-types.js';
|
|
13
13
|
import type { EntrypointDependencyGraph } from '../services/runtime-state/entrypoint-dependency-graph.service.js';
|
|
14
|
-
import type { RuntimeSpecifierRegistry } from '../services/runtime-state/runtime-specifier-registry.service.js';
|
|
15
14
|
import type { ServerInvalidationState } from '../services/runtime-state/server-invalidation-state.service.js';
|
|
16
15
|
import type { ServerModuleTranspiler } from '../services/module-loading/server-module-transpiler.service.js';
|
|
17
16
|
export interface RobotsPreference {
|
|
@@ -102,7 +101,7 @@ export type EcoPagesAppConfig = {
|
|
|
102
101
|
*/
|
|
103
102
|
defaultMetadata: PageMetadataProps;
|
|
104
103
|
/** Integrations plugins */
|
|
105
|
-
integrations:
|
|
104
|
+
integrations: AnyIntegrationPlugin[];
|
|
106
105
|
/** Integrations dependencies */
|
|
107
106
|
integrationsDependencies: IntegrationDependencyConfig[];
|
|
108
107
|
/** Derived Paths */
|
|
@@ -155,7 +154,6 @@ export type EcoPagesAppConfig = {
|
|
|
155
154
|
entrypointDependencyGraph?: EntrypointDependencyGraph;
|
|
156
155
|
hostModuleLoader?: SourceModuleLoader;
|
|
157
156
|
rendererModuleContext?: unknown;
|
|
158
|
-
runtimeSpecifierRegistry?: RuntimeSpecifierRegistry;
|
|
159
157
|
serverInvalidationState?: ServerInvalidationState;
|
|
160
158
|
serverModuleTranspiler?: ServerModuleTranspiler;
|
|
161
159
|
};
|
|
@@ -184,11 +182,14 @@ export type RouteKind = 'exact' | 'catch-all' | 'dynamic';
|
|
|
184
182
|
* Represents the result of a route match.
|
|
185
183
|
*/
|
|
186
184
|
export type MatchResult = {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
185
|
+
requestedPathname: string;
|
|
186
|
+
templateRoute: {
|
|
187
|
+
filePath: string;
|
|
188
|
+
kind: RouteKind;
|
|
189
|
+
pathname: string;
|
|
190
|
+
};
|
|
191
|
+
query: Record<string, string>;
|
|
192
|
+
params: Record<string, string | string[]>;
|
|
192
193
|
};
|
|
193
194
|
/**
|
|
194
195
|
* Represents a route in EcoPages.
|
|
@@ -214,10 +215,10 @@ export type FileSystemServerOptions = {
|
|
|
214
215
|
*/
|
|
215
216
|
export interface EcoPagesFileSystemServerAdapter<ServerInstanceOptions = unknown> {
|
|
216
217
|
startServer(serverOptions: ServerInstanceOptions): {
|
|
217
|
-
router:
|
|
218
|
+
router: RouteRegistry;
|
|
218
219
|
server: unknown;
|
|
219
220
|
} | Promise<{
|
|
220
|
-
router:
|
|
221
|
+
router: RouteRegistry;
|
|
221
222
|
server: unknown;
|
|
222
223
|
}>;
|
|
223
224
|
}
|