evolit 0.1.0-alpha.17 → 0.1.0-alpha.19
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/package.json +1 -1
- package/src/build.js +22 -4
- package/src/cli.js +16 -14
- package/src/client-assets.js +101 -27
- package/src/compiler.js +9 -9
- package/src/deployment-runtime.js +22 -4
- package/src/development-events.js +87 -0
- package/src/render.js +7 -5
- package/src/server.js +4 -51
package/package.json
CHANGED
package/src/build.js
CHANGED
|
@@ -255,17 +255,35 @@ export async function buildProject(projectRoot) {
|
|
|
255
255
|
...styleUrls.map((href) => `<link rel="stylesheet" href="${href}">`),
|
|
256
256
|
].join("\n");
|
|
257
257
|
},
|
|
258
|
-
resolveBootstrap({ result }) {
|
|
258
|
+
resolveBootstrap({ routeResult, result }) {
|
|
259
|
+
const routeClientImports = resolveRouteClientImports(
|
|
260
|
+
routeResult,
|
|
261
|
+
projectRoot,
|
|
262
|
+
clientAssets,
|
|
263
|
+
);
|
|
259
264
|
return createHydrationBootstrap({
|
|
260
|
-
hydrationData: normalizeHydrationDataForClient(
|
|
265
|
+
hydrationData: normalizeHydrationDataForClient(
|
|
266
|
+
result.hydrationData,
|
|
267
|
+
projectRoot,
|
|
268
|
+
routeClientImports,
|
|
269
|
+
),
|
|
261
270
|
assetResolver,
|
|
262
271
|
hydrationModuleUrl,
|
|
263
272
|
});
|
|
264
273
|
},
|
|
265
|
-
transformDocument({ result, document }) {
|
|
274
|
+
transformDocument({ routeResult, result, document }) {
|
|
275
|
+
const routeClientImports = resolveRouteClientImports(
|
|
276
|
+
routeResult,
|
|
277
|
+
projectRoot,
|
|
278
|
+
clientAssets,
|
|
279
|
+
);
|
|
266
280
|
return rewriteHydrationDataScript(
|
|
267
281
|
document,
|
|
268
|
-
normalizeHydrationDataForClient(
|
|
282
|
+
normalizeHydrationDataForClient(
|
|
283
|
+
result.hydrationData,
|
|
284
|
+
projectRoot,
|
|
285
|
+
routeClientImports,
|
|
286
|
+
),
|
|
269
287
|
);
|
|
270
288
|
},
|
|
271
289
|
});
|
package/src/cli.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { scaffoldSite } from "./scaffold.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createDevelopmentEventReporter } from "./development-events.js";
|
|
7
|
+
|
|
8
|
+
const reportEvent = createDevelopmentEventReporter();
|
|
7
9
|
|
|
8
10
|
function parseArguments(argv) {
|
|
9
11
|
const [command, ...rest] = argv;
|
|
@@ -25,9 +27,7 @@ function parseArguments(argv) {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
function printUsage() {
|
|
28
|
-
|
|
29
|
-
console.log(` evolit ${terminal.cyan("init")} <directory>`);
|
|
30
|
-
console.log(` evolit ${terminal.cyan("<dev|build|start>")} [--port 3000]`);
|
|
30
|
+
reportEvent({ type: "usage" });
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function createSite(projectRoot, targetDirectory) {
|
|
@@ -36,7 +36,7 @@ async function createSite(projectRoot, targetDirectory) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const createdDirectory = await scaffoldSite(path.resolve(projectRoot, targetDirectory));
|
|
39
|
-
|
|
39
|
+
reportEvent({ type: "site-created", directory: createdDirectory });
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async function run() {
|
|
@@ -56,25 +56,29 @@ async function run() {
|
|
|
56
56
|
if (command === "build") {
|
|
57
57
|
const { buildProject } = await import("./build.js");
|
|
58
58
|
const manifestPath = await buildProject(projectRoot);
|
|
59
|
-
|
|
59
|
+
reportEvent({
|
|
60
|
+
type: "build-ready",
|
|
61
|
+
manifestPath: path.relative(projectRoot, manifestPath),
|
|
62
|
+
});
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
if (command === "start") {
|
|
64
67
|
const { createStartServer } = await import("./server.js");
|
|
65
|
-
|
|
68
|
+
reportEvent({ type: "server-starting", mode: "start" });
|
|
66
69
|
const server = await createStartServer(projectRoot, options);
|
|
67
70
|
await server.listen();
|
|
68
|
-
|
|
71
|
+
reportEvent({ type: "server-ready", port: server.port });
|
|
69
72
|
return;
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
if (command === "dev") {
|
|
73
76
|
const { createDevServer } = await import("./server.js");
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
const server = await createDevServer(projectRoot, {
|
|
78
|
+
...options,
|
|
79
|
+
onDevelopmentEvent: reportEvent,
|
|
80
|
+
});
|
|
76
81
|
await server.listen();
|
|
77
|
-
console.log(`${terminal.green("✓")} Ready on ${terminal.cyan(`http://localhost:${server.port}`)}`);
|
|
78
82
|
return;
|
|
79
83
|
}
|
|
80
84
|
|
|
@@ -82,8 +86,6 @@ async function run() {
|
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
run().catch((error) => {
|
|
85
|
-
|
|
86
|
-
`${terminal.red("[evolit]")} ${terminal.red("✖")} ${error instanceof Error ? error.stack ?? error.message : String(error)}`,
|
|
87
|
-
);
|
|
89
|
+
reportEvent({ type: "fatal-error", error });
|
|
88
90
|
process.exitCode = 1;
|
|
89
91
|
});
|
package/src/client-assets.js
CHANGED
|
@@ -923,10 +923,25 @@ export function getClientOutputRoot(projectRoot, mode) {
|
|
|
923
923
|
}
|
|
924
924
|
|
|
925
925
|
export function toClientModuleRelativePath(projectRoot, sourcePath) {
|
|
926
|
-
const relativePath =
|
|
926
|
+
const relativePath = toClientSourceRelativePath(projectRoot, sourcePath);
|
|
927
927
|
return toCompiledClientModuleRelativePath(relativePath);
|
|
928
928
|
}
|
|
929
929
|
|
|
930
|
+
function toClientSourceRelativePath(projectRoot, sourcePath) {
|
|
931
|
+
const relativePath = path.relative(projectRoot, sourcePath);
|
|
932
|
+
const isOutsideProject = relativePath === ".."
|
|
933
|
+
|| relativePath.startsWith(`..${path.sep}`)
|
|
934
|
+
|| path.isAbsolute(relativePath);
|
|
935
|
+
if (!isOutsideProject) {
|
|
936
|
+
return relativePath;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return path.join(
|
|
940
|
+
"__unmanaged__",
|
|
941
|
+
...relativePath.split(path.sep).map((segment) => segment === ".." ? "__up__" : segment),
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
|
|
930
945
|
function toCompiledClientModuleRelativePath(relativePath) {
|
|
931
946
|
const extension = path.extname(relativePath);
|
|
932
947
|
return extension
|
|
@@ -934,17 +949,66 @@ function toCompiledClientModuleRelativePath(relativePath) {
|
|
|
934
949
|
: `${relativePath}.mjs`;
|
|
935
950
|
}
|
|
936
951
|
|
|
952
|
+
function toCatchAllClientModuleRelativePath(clientModule) {
|
|
953
|
+
return clientModule
|
|
954
|
+
.split(/[\\/]/)
|
|
955
|
+
.map((segment) => {
|
|
956
|
+
if (segment.startsWith("[[...") && segment.endsWith("]]")) {
|
|
957
|
+
return `**...${segment.slice(5, -2)}**`;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
if (segment.startsWith("[...") && segment.endsWith("]")) {
|
|
961
|
+
return `*...${segment.slice(4, -1)}*`;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return segment;
|
|
965
|
+
})
|
|
966
|
+
.join("/");
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function toRollupSafeClientModuleRelativePath(clientModule) {
|
|
970
|
+
return clientModule.replaceAll(/[\[\]]/g, "_");
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
function getClientModuleCandidates(clientModule) {
|
|
974
|
+
const normalizedClientModule = clientModule.split(path.sep).join("/");
|
|
975
|
+
return [...new Set([
|
|
976
|
+
normalizedClientModule,
|
|
977
|
+
toCatchAllClientModuleRelativePath(normalizedClientModule),
|
|
978
|
+
toRollupSafeClientModuleRelativePath(normalizedClientModule),
|
|
979
|
+
])];
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function getClientModulePublicUrl(assetManifest, clientModule) {
|
|
983
|
+
for (const candidate of getClientModuleCandidates(clientModule)) {
|
|
984
|
+
const publicUrl = assetManifest.byClientModule[candidate];
|
|
985
|
+
if (typeof publicUrl === "string" && publicUrl.length > 0) {
|
|
986
|
+
return publicUrl;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
const candidates = new Set(getClientModuleCandidates(clientModule));
|
|
991
|
+
const asset = assetManifest.assets.find((entry) =>
|
|
992
|
+
candidates.has(entry?.clientModule) && typeof entry?.publicUrl === "string",
|
|
993
|
+
);
|
|
994
|
+
if (asset) {
|
|
995
|
+
return asset.publicUrl;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function isVirtualClientModuleId(moduleId) {
|
|
1002
|
+
return moduleId.startsWith("/app/") || moduleId.startsWith("/__unmanaged__/");
|
|
1003
|
+
}
|
|
1004
|
+
|
|
937
1005
|
function toPublicHydrationModuleId(projectRoot, moduleId) {
|
|
938
1006
|
if (typeof moduleId !== "string" || moduleId.length === 0) {
|
|
939
1007
|
return null;
|
|
940
1008
|
}
|
|
941
1009
|
|
|
942
1010
|
if (path.isAbsolute(moduleId)) {
|
|
943
|
-
|
|
944
|
-
return null;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
const relativePath = path.relative(projectRoot, moduleId).split(path.sep).join("/");
|
|
1011
|
+
const relativePath = toClientSourceRelativePath(projectRoot, moduleId).split(path.sep).join("/");
|
|
948
1012
|
return `/${relativePath}`;
|
|
949
1013
|
}
|
|
950
1014
|
|
|
@@ -986,14 +1050,10 @@ export function createAssetResolver(projectRoot, options = {}) {
|
|
|
986
1050
|
}
|
|
987
1051
|
|
|
988
1052
|
let relativeClientModule = null;
|
|
989
|
-
if (
|
|
990
|
-
relativeClientModule = toCompiledClientModuleRelativePath(moduleId.slice(1));
|
|
991
|
-
} else if (path.isAbsolute(moduleId)) {
|
|
992
|
-
if (!moduleId.startsWith(projectRoot)) {
|
|
993
|
-
return null;
|
|
994
|
-
}
|
|
995
|
-
|
|
1053
|
+
if (path.isAbsolute(moduleId) && !isVirtualClientModuleId(moduleId)) {
|
|
996
1054
|
relativeClientModule = toClientModuleRelativePath(projectRoot, moduleId);
|
|
1055
|
+
} else if (moduleId.startsWith("/")) {
|
|
1056
|
+
relativeClientModule = toCompiledClientModuleRelativePath(moduleId.slice(1));
|
|
997
1057
|
}
|
|
998
1058
|
|
|
999
1059
|
if (!relativeClientModule) {
|
|
@@ -1001,10 +1061,7 @@ export function createAssetResolver(projectRoot, options = {}) {
|
|
|
1001
1061
|
}
|
|
1002
1062
|
|
|
1003
1063
|
if (assetManifest) {
|
|
1004
|
-
return
|
|
1005
|
-
assetManifest,
|
|
1006
|
-
relativeClientModule,
|
|
1007
|
-
)?.publicUrl ?? null;
|
|
1064
|
+
return getClientModulePublicUrl(assetManifest, relativeClientModule);
|
|
1008
1065
|
}
|
|
1009
1066
|
|
|
1010
1067
|
return null;
|
|
@@ -1029,8 +1086,8 @@ export function createHydrationBootstrap({
|
|
|
1029
1086
|
hydrationModuleUrl = "@litsx/ssr/hydration",
|
|
1030
1087
|
}) {
|
|
1031
1088
|
const normalizedHydrationData = normalizeHydrationDataForClient(hydrationData);
|
|
1032
|
-
const
|
|
1033
|
-
(normalizedHydrationData?.roots ?? [])
|
|
1089
|
+
const rootModuleUrls = [...new Set([
|
|
1090
|
+
...(normalizedHydrationData?.roots ?? [])
|
|
1034
1091
|
.map((root) => {
|
|
1035
1092
|
if (typeof root?.moduleId !== "string" || root.moduleId.length === 0) {
|
|
1036
1093
|
return null;
|
|
@@ -1039,13 +1096,18 @@ export function createHydrationBootstrap({
|
|
|
1039
1096
|
return assetResolver?.(root.moduleId) ?? null;
|
|
1040
1097
|
})
|
|
1041
1098
|
.filter((moduleUrl) => typeof moduleUrl === "string" && moduleUrl.length > 0),
|
|
1099
|
+
])];
|
|
1100
|
+
const clientImports = [...new Set(
|
|
1101
|
+
(Array.isArray(normalizedHydrationData?.clientImports)
|
|
1102
|
+
? normalizedHydrationData.clientImports
|
|
1103
|
+
: []).filter((moduleUrl) => typeof moduleUrl === "string" && moduleUrl.length > 0),
|
|
1042
1104
|
)];
|
|
1043
1105
|
|
|
1044
|
-
if (
|
|
1106
|
+
if (rootModuleUrls.length === 0 && clientImports.length === 0) {
|
|
1045
1107
|
return "";
|
|
1046
1108
|
}
|
|
1047
1109
|
|
|
1048
|
-
const moduleLoaders =
|
|
1110
|
+
const moduleLoaders = rootModuleUrls
|
|
1049
1111
|
.map((moduleUrl) => ` () => import(${JSON.stringify(moduleUrl)})`)
|
|
1050
1112
|
.join(",\n");
|
|
1051
1113
|
|
|
@@ -1053,7 +1115,7 @@ export function createHydrationBootstrap({
|
|
|
1053
1115
|
import { hydratePage, registerHydrationModules } from ${JSON.stringify(hydrationModuleUrl)};
|
|
1054
1116
|
|
|
1055
1117
|
await hydratePage({
|
|
1056
|
-
clientImports:
|
|
1118
|
+
clientImports: ${JSON.stringify(clientImports)},
|
|
1057
1119
|
register: () => registerHydrationModules([
|
|
1058
1120
|
${moduleLoaders}
|
|
1059
1121
|
])
|
|
@@ -1063,7 +1125,11 @@ ${moduleLoaders}
|
|
|
1063
1125
|
return escapeInlineScriptText(source);
|
|
1064
1126
|
}
|
|
1065
1127
|
|
|
1066
|
-
export function normalizeHydrationDataForClient(
|
|
1128
|
+
export function normalizeHydrationDataForClient(
|
|
1129
|
+
hydrationData,
|
|
1130
|
+
projectRoot = null,
|
|
1131
|
+
additionalClientImports = [],
|
|
1132
|
+
) {
|
|
1067
1133
|
if (!hydrationData || typeof hydrationData !== "object") {
|
|
1068
1134
|
return hydrationData ?? null;
|
|
1069
1135
|
}
|
|
@@ -1096,7 +1162,10 @@ export function normalizeHydrationDataForClient(hydrationData, projectRoot = nul
|
|
|
1096
1162
|
roots,
|
|
1097
1163
|
};
|
|
1098
1164
|
const payload = hydrationData.payload;
|
|
1099
|
-
const clientImports =
|
|
1165
|
+
const clientImports = [...new Set([
|
|
1166
|
+
...(Array.isArray(hydrationData.clientImports) ? hydrationData.clientImports : []),
|
|
1167
|
+
...(Array.isArray(additionalClientImports) ? additionalClientImports : []),
|
|
1168
|
+
].filter((value) => typeof value === "string" && value.length > 0))];
|
|
1100
1169
|
|
|
1101
1170
|
Object.defineProperties(normalizedHydrationData, {
|
|
1102
1171
|
payload: {
|
|
@@ -1728,9 +1797,14 @@ async function bundleClientAssets(projectRoot, options = {}) {
|
|
|
1728
1797
|
|
|
1729
1798
|
const outputPath = path.join(staticRoot, chunk.fileName);
|
|
1730
1799
|
const publicUrl = toStaticPublicUrl(chunk.fileName);
|
|
1731
|
-
const
|
|
1800
|
+
const entryClientModule = clientModuleByEntryName.get(chunk.name)
|
|
1801
|
+
?? [...clientModuleByEntryName.entries()].find(([entryName]) =>
|
|
1802
|
+
toRollupSafeClientModuleRelativePath(entryName) === chunk.name,
|
|
1803
|
+
)?.[1]
|
|
1804
|
+
?? null;
|
|
1805
|
+
const isNamedEntry = chunk.isEntry && entryClientModule != null;
|
|
1732
1806
|
const clientModule = isNamedEntry
|
|
1733
|
-
?
|
|
1807
|
+
? entryClientModule
|
|
1734
1808
|
: chunk.fileName;
|
|
1735
1809
|
const transitiveMetadata = isNamedEntry
|
|
1736
1810
|
? await collectTransitiveClientModuleMetadata(projectRoot, mode, clientModule)
|
|
@@ -1939,7 +2013,7 @@ export function resolveRouteClientImports(routeResult, projectRoot, assetManifes
|
|
|
1939
2013
|
const clientModule = extension
|
|
1940
2014
|
? `${relativePath.slice(0, -extension.length)}.mjs`
|
|
1941
2015
|
: `${relativePath}.mjs`;
|
|
1942
|
-
return normalizedManifest
|
|
2016
|
+
return getClientModulePublicUrl(normalizedManifest, clientModule);
|
|
1943
2017
|
}).filter((publicUrl) => typeof publicUrl === "string"))];
|
|
1944
2018
|
}
|
|
1945
2019
|
|
package/src/compiler.js
CHANGED
|
@@ -25,7 +25,7 @@ const developmentGraphCache = new Map();
|
|
|
25
25
|
const developmentGraphDependencies = new Map();
|
|
26
26
|
const developmentModuleNamespaceCache = new Map();
|
|
27
27
|
const developmentGraphVersions = new Map();
|
|
28
|
-
const
|
|
28
|
+
const developmentUnmanagedImportWarnings = new Set();
|
|
29
29
|
|
|
30
30
|
function isRelativeSpecifier(specifier) {
|
|
31
31
|
return specifier.startsWith("./") || specifier.startsWith("../");
|
|
@@ -70,15 +70,15 @@ function isPathOutsideProject(projectRoot, filePath) {
|
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
function
|
|
73
|
+
function reportDevelopmentUnmanagedImport(projectRoot, sourcePath, resolvedImportPath, onDevelopmentEvent) {
|
|
74
74
|
const warningKey = `${path.resolve(projectRoot)}::${sourcePath}::${resolvedImportPath}`;
|
|
75
|
-
if (
|
|
75
|
+
if (developmentUnmanagedImportWarnings.has(warningKey)) {
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
developmentUnmanagedImportWarnings.add(warningKey);
|
|
80
80
|
onDevelopmentEvent?.({
|
|
81
|
-
type: "
|
|
81
|
+
type: "unmanaged-import",
|
|
82
82
|
sourcePath,
|
|
83
83
|
resolvedImportPath,
|
|
84
84
|
});
|
|
@@ -159,7 +159,7 @@ function toOutputRelativePath(projectRoot, sourcePath) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
return path.join(
|
|
162
|
-
"
|
|
162
|
+
"__unmanaged__",
|
|
163
163
|
...relativePath.split(path.sep).map((segment) => segment === ".." ? "__up__" : segment),
|
|
164
164
|
);
|
|
165
165
|
}
|
|
@@ -211,7 +211,7 @@ async function rewriteRelativeSpecifiers({
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
if (mode === "development" && isPathOutsideProject(projectRoot, resolvedImportPath)) {
|
|
214
|
-
|
|
214
|
+
reportDevelopmentUnmanagedImport(projectRoot, sourcePath, resolvedImportPath, onDevelopmentEvent);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
const importerOutputPath = toOutputPath(projectRoot, outputRoot, sourcePath);
|
|
@@ -339,9 +339,9 @@ export function invalidateDevelopmentCompilationCache(projectRoot, changedPaths
|
|
|
339
339
|
let invalidated = false;
|
|
340
340
|
|
|
341
341
|
if (normalizedChangedPaths == null) {
|
|
342
|
-
for (const warningKey of
|
|
342
|
+
for (const warningKey of developmentUnmanagedImportWarnings) {
|
|
343
343
|
if (warningKey.startsWith(prefix)) {
|
|
344
|
-
|
|
344
|
+
developmentUnmanagedImportWarnings.delete(warningKey);
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
}
|
|
@@ -293,19 +293,37 @@ export async function createRequestRenderer({
|
|
|
293
293
|
...styleUrls.map((href) => `<link rel="stylesheet" href="${href}">`),
|
|
294
294
|
].join("\n");
|
|
295
295
|
},
|
|
296
|
-
resolveBootstrap({ result }) {
|
|
296
|
+
resolveBootstrap({ routeResult, result }) {
|
|
297
|
+
const routeClientImports = resolveRouteClientImports(
|
|
298
|
+
routeResult,
|
|
299
|
+
projectRoot,
|
|
300
|
+
currentAssetManifest,
|
|
301
|
+
);
|
|
297
302
|
return createHydrationBootstrap({
|
|
298
|
-
hydrationData: normalizeHydrationDataForClient(
|
|
303
|
+
hydrationData: normalizeHydrationDataForClient(
|
|
304
|
+
result.hydrationData,
|
|
305
|
+
projectRoot,
|
|
306
|
+
routeClientImports,
|
|
307
|
+
),
|
|
299
308
|
assetResolver(moduleId) {
|
|
300
309
|
return currentAssetResolver(moduleId);
|
|
301
310
|
},
|
|
302
311
|
hydrationModuleUrl: currentHydrationModuleUrl,
|
|
303
312
|
});
|
|
304
313
|
},
|
|
305
|
-
transformDocument({ result, document }) {
|
|
314
|
+
transformDocument({ routeResult, result, document }) {
|
|
315
|
+
const routeClientImports = resolveRouteClientImports(
|
|
316
|
+
routeResult,
|
|
317
|
+
projectRoot,
|
|
318
|
+
currentAssetManifest,
|
|
319
|
+
);
|
|
306
320
|
return rewriteHydrationDataScript(
|
|
307
321
|
document,
|
|
308
|
-
normalizeHydrationDataForClient(
|
|
322
|
+
normalizeHydrationDataForClient(
|
|
323
|
+
result.hydrationData,
|
|
324
|
+
projectRoot,
|
|
325
|
+
routeClientImports,
|
|
326
|
+
),
|
|
309
327
|
);
|
|
310
328
|
},
|
|
311
329
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { terminal } from "./terminal.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates the default development-event sink used by the CLI and dev server.
|
|
5
|
+
* Keeping presentation here lets integrations replace it with onDevelopmentEvent
|
|
6
|
+
* without losing any lifecycle, build, or request diagnostics.
|
|
7
|
+
*/
|
|
8
|
+
export function createDevelopmentEventReporter() {
|
|
9
|
+
return (event) => {
|
|
10
|
+
switch (event.type) {
|
|
11
|
+
case "server-starting":
|
|
12
|
+
console.log(`${terminal.cyan("▲")} ${terminal.bold("Evolit")} ${terminal.cyan(event.mode ?? "dev")}`);
|
|
13
|
+
break;
|
|
14
|
+
case "usage":
|
|
15
|
+
console.log(`${terminal.bold("Usage:")} evolit <directory>`);
|
|
16
|
+
console.log(` evolit ${terminal.cyan("init")} <directory>`);
|
|
17
|
+
console.log(` evolit ${terminal.cyan("<dev|build|start>")} [--port 3000]`);
|
|
18
|
+
break;
|
|
19
|
+
case "site-created":
|
|
20
|
+
console.log(`${terminal.green("✓")} Created evolit site: ${terminal.cyan(event.directory)}`);
|
|
21
|
+
break;
|
|
22
|
+
case "build-ready":
|
|
23
|
+
console.log(`${terminal.green("✓")} Built Evolit app: ${terminal.cyan(event.manifestPath)}`);
|
|
24
|
+
break;
|
|
25
|
+
case "initializing":
|
|
26
|
+
console.log(`${terminal.cyan("[evolit]")} ${terminal.yellow("○")} Preparing development runtime…`);
|
|
27
|
+
break;
|
|
28
|
+
case "vendor-runtime-ready":
|
|
29
|
+
console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Vendor runtime ready.`);
|
|
30
|
+
break;
|
|
31
|
+
case "client-assets-building":
|
|
32
|
+
console.log(`${terminal.cyan("[evolit]")} ${terminal.magenta("○")} Compiling client assets (${event.entryCount} entries)…`);
|
|
33
|
+
break;
|
|
34
|
+
case "client-assets-ready":
|
|
35
|
+
console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Client assets compiled in ${terminal.dim(`${event.durationMs}ms`)} (${event.entryCount} entries).`);
|
|
36
|
+
break;
|
|
37
|
+
case "client-assets-cache-hit":
|
|
38
|
+
console.log(`${terminal.cyan("[evolit]")} ${terminal.blue("●")} Client assets served from cache.`);
|
|
39
|
+
break;
|
|
40
|
+
case "invalidated":
|
|
41
|
+
console.log(
|
|
42
|
+
`${terminal.cyan("[evolit]")} ${terminal.yellow("△")} Source change detected${event.changedPathCount == null ? "" : ` (${event.changedPathCount} files)`}; invalidated ${event.affectedClientEntryCount} client entries.`,
|
|
43
|
+
);
|
|
44
|
+
break;
|
|
45
|
+
case "unmanaged-import":
|
|
46
|
+
console.warn(
|
|
47
|
+
`${terminal.yellow("[evolit]")} ${terminal.yellow("⚠")} Unmanaged import ${terminal.cyan(JSON.stringify(event.resolvedImportPath))} from ${terminal.cyan(JSON.stringify(event.sourcePath))} is outside the project root. Evolit does not watch it; changes may not trigger a rebuild, and it may be unavailable in another checkout or deployment. It will be emitted under ${terminal.cyan("/_evolit/static/__unmanaged__/")}.`,
|
|
48
|
+
);
|
|
49
|
+
break;
|
|
50
|
+
case "server-ready":
|
|
51
|
+
console.log(`${terminal.green("✓")} Ready on ${terminal.cyan(`http://localhost:${event.port}`)}`);
|
|
52
|
+
break;
|
|
53
|
+
case "request": {
|
|
54
|
+
const statusColor = event.status >= 500
|
|
55
|
+
? terminal.red
|
|
56
|
+
: event.status >= 400
|
|
57
|
+
? terminal.yellow
|
|
58
|
+
: event.status >= 300
|
|
59
|
+
? terminal.blue
|
|
60
|
+
: terminal.green;
|
|
61
|
+
console.log(
|
|
62
|
+
`${terminal.cyan("[evolit]")} ${terminal.dim(event.method)} ${event.pathname} ${statusColor(event.status)} in ${terminal.dim(`${event.durationMs}ms`)}${event.cacheState ? ` ${terminal.blue(`(${event.cacheState})`)}` : ""}`,
|
|
63
|
+
);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "request-error":
|
|
67
|
+
console.error(
|
|
68
|
+
`${terminal.red("[evolit]")} ${terminal.red("✖")} ${event.method} ${event.pathname} failed`,
|
|
69
|
+
event.error,
|
|
70
|
+
);
|
|
71
|
+
break;
|
|
72
|
+
case "fatal-error":
|
|
73
|
+
console.error(
|
|
74
|
+
`${terminal.red("[evolit]")} ${terminal.red("✖")} ${event.error instanceof Error ? event.error.stack ?? event.error.message : String(event.error)}`,
|
|
75
|
+
);
|
|
76
|
+
break;
|
|
77
|
+
case "route-error":
|
|
78
|
+
console.error(
|
|
79
|
+
`${terminal.red("[evolit]")} ${terminal.red("✖")} Route rendering failed ${terminal.dim(`(${event.digest})`)} at ${terminal.cyan(event.pathname)}`,
|
|
80
|
+
event.error,
|
|
81
|
+
);
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
package/src/render.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
isEvolitHttpSignal,
|
|
13
13
|
runWithRequestContext,
|
|
14
14
|
} from "./request-context.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createDevelopmentEventReporter } from "./development-events.js";
|
|
16
16
|
import {
|
|
17
17
|
LITSX_COMPONENT,
|
|
18
18
|
LITSX_SERVER_COMPONENT,
|
|
@@ -90,10 +90,12 @@ function createBoundaryError(error, { mode, route, reportRouteError }) {
|
|
|
90
90
|
if (typeof reportRouteError === "function") {
|
|
91
91
|
reportRouteError(report);
|
|
92
92
|
} else {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
createDevelopmentEventReporter()({
|
|
94
|
+
type: "route-error",
|
|
95
|
+
digest,
|
|
96
|
+
pathname: route.pathname,
|
|
97
|
+
error: originalError,
|
|
98
|
+
});
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
const boundaryError = new Error("An unexpected server error occurred.");
|
package/src/server.js
CHANGED
|
@@ -9,7 +9,7 @@ import { APP_DIRECTORY, BUILD_DIRECTORY, INTERNAL_DIRECTORY, MANIFEST_FILENAME }
|
|
|
9
9
|
import { normalizeClientAssetManifest } from "./client-assets.js";
|
|
10
10
|
import { pathExists, readJson } from "./fs-utils.js";
|
|
11
11
|
import { createDefaultRouteCacheKey, resolveResponseCacheRuntime } from "./response-cache.js";
|
|
12
|
-
import {
|
|
12
|
+
import { createDevelopmentEventReporter } from "./development-events.js";
|
|
13
13
|
|
|
14
14
|
function getPort(explicitPort) {
|
|
15
15
|
const port = explicitPort ?? process.env.PORT ?? "3000";
|
|
@@ -141,57 +141,9 @@ async function createRecursiveDirectoryWatcher(rootDirectory, onChange) {
|
|
|
141
141
|
|
|
142
142
|
async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
143
143
|
const reportDevelopmentEvent = mode === "development"
|
|
144
|
-
? options.onDevelopmentEvent ?? (
|
|
145
|
-
switch (event.type) {
|
|
146
|
-
case "initializing":
|
|
147
|
-
console.log(`${terminal.cyan("[evolit]")} ${terminal.yellow("○")} Preparing development runtime…`);
|
|
148
|
-
break;
|
|
149
|
-
case "vendor-runtime-ready":
|
|
150
|
-
console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Vendor runtime ready.`);
|
|
151
|
-
break;
|
|
152
|
-
case "client-assets-building":
|
|
153
|
-
console.log(`${terminal.cyan("[evolit]")} ${terminal.magenta("○")} Compiling client assets (${event.entryCount} entries)…`);
|
|
154
|
-
break;
|
|
155
|
-
case "client-assets-ready":
|
|
156
|
-
console.log(`${terminal.cyan("[evolit]")} ${terminal.green("✓")} Client assets compiled in ${terminal.dim(`${event.durationMs}ms`)} (${event.entryCount} entries).`);
|
|
157
|
-
break;
|
|
158
|
-
case "client-assets-cache-hit":
|
|
159
|
-
console.log(`${terminal.cyan("[evolit]")} ${terminal.blue("●")} Client assets served from cache.`);
|
|
160
|
-
break;
|
|
161
|
-
case "invalidated":
|
|
162
|
-
console.log(
|
|
163
|
-
`${terminal.cyan("[evolit]")} ${terminal.yellow("△")} Source change detected${event.changedPathCount == null ? "" : ` (${event.changedPathCount} files)`}; invalidated ${event.affectedClientEntryCount} client entries.`,
|
|
164
|
-
);
|
|
165
|
-
break;
|
|
166
|
-
case "external-import":
|
|
167
|
-
console.warn(
|
|
168
|
-
`${terminal.yellow("[evolit]")} ${terminal.yellow("⚠")} Development import ${terminal.cyan(JSON.stringify(event.resolvedImportPath))} from ${terminal.cyan(JSON.stringify(event.sourcePath))} is outside the project root. It will be emitted under ${terminal.cyan("/_evolit/static/__external__/")}.`,
|
|
169
|
-
);
|
|
170
|
-
break;
|
|
171
|
-
case "request": {
|
|
172
|
-
const statusColor = event.status >= 500
|
|
173
|
-
? terminal.red
|
|
174
|
-
: event.status >= 400
|
|
175
|
-
? terminal.yellow
|
|
176
|
-
: event.status >= 300
|
|
177
|
-
? terminal.blue
|
|
178
|
-
: terminal.green;
|
|
179
|
-
console.log(
|
|
180
|
-
`${terminal.cyan("[evolit]")} ${terminal.dim(event.method)} ${event.pathname} ${statusColor(event.status)} in ${terminal.dim(`${event.durationMs}ms`)}${event.cacheState ? ` ${terminal.blue(`(${event.cacheState})`)}` : ""}`,
|
|
181
|
-
);
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
case "request-error":
|
|
185
|
-
console.error(
|
|
186
|
-
`${terminal.red("[evolit]")} ${terminal.red("✖")} ${event.method} ${event.pathname} failed`,
|
|
187
|
-
event.error,
|
|
188
|
-
);
|
|
189
|
-
break;
|
|
190
|
-
default:
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
})
|
|
144
|
+
? options.onDevelopmentEvent ?? createDevelopmentEventReporter()
|
|
194
145
|
: null;
|
|
146
|
+
reportDevelopmentEvent?.({ type: "server-starting" });
|
|
195
147
|
const evolitConfig = options.evolitConfig ?? await loadEvolitConfig(projectRoot);
|
|
196
148
|
const responseCacheRuntime = options.responseCacheStore
|
|
197
149
|
? {
|
|
@@ -331,6 +283,7 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
331
283
|
await new Promise((resolve) => {
|
|
332
284
|
server.listen(port, resolve);
|
|
333
285
|
});
|
|
286
|
+
reportDevelopmentEvent?.({ type: "server-ready", port });
|
|
334
287
|
return server;
|
|
335
288
|
},
|
|
336
289
|
async close() {
|