@lolyjs/core 0.2.0-alpha.14 → 0.2.0-alpha.15
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 +99 -12
- package/dist/cli.cjs +192 -44
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +192 -44
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +192 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +192 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -168,6 +168,10 @@ interface LoaderResult {
|
|
|
168
168
|
className?: string;
|
|
169
169
|
theme?: string;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Server loader function type (getServerSideProps).
|
|
173
|
+
* This function is exported from server.hook.ts files.
|
|
174
|
+
*/
|
|
171
175
|
type ServerLoader = (ctx: ServerContext) => Promise<LoaderResult>;
|
|
172
176
|
interface PageMetadata {
|
|
173
177
|
title?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -168,6 +168,10 @@ interface LoaderResult {
|
|
|
168
168
|
className?: string;
|
|
169
169
|
theme?: string;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Server loader function type (getServerSideProps).
|
|
173
|
+
* This function is exported from server.hook.ts files.
|
|
174
|
+
*/
|
|
171
175
|
type ServerLoader = (ctx: ServerContext) => Promise<LoaderResult>;
|
|
172
176
|
interface PageMetadata {
|
|
173
177
|
title?: string;
|
package/dist/index.js
CHANGED
|
@@ -204,7 +204,7 @@ function loadLayoutsForDir(pageDir, appDir) {
|
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
// modules/router/
|
|
207
|
+
// modules/router/server-hook.ts
|
|
208
208
|
import fs3 from "fs";
|
|
209
209
|
import path3 from "path";
|
|
210
210
|
var NAMING = {
|
|
@@ -216,14 +216,16 @@ var NAMING = {
|
|
|
216
216
|
// Files
|
|
217
217
|
SERVER_HOOK: "server.hook"
|
|
218
218
|
};
|
|
219
|
-
function
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
219
|
+
function loadServerHookForDir(currentDir) {
|
|
220
|
+
const pageServerHookTs = path3.join(currentDir, `page.server.hook.ts`);
|
|
221
|
+
const pageServerHookJs = path3.join(currentDir, `page.server.hook.js`);
|
|
222
|
+
const serverHookTs = path3.join(currentDir, `${NAMING.SERVER_HOOK}.ts`);
|
|
223
|
+
const serverHookJs = path3.join(currentDir, `${NAMING.SERVER_HOOK}.js`);
|
|
224
|
+
const file = fs3.existsSync(pageServerHookTs) ? pageServerHookTs : fs3.existsSync(pageServerHookJs) ? pageServerHookJs : fs3.existsSync(serverHookTs) ? serverHookTs : fs3.existsSync(serverHookJs) ? serverHookJs : null;
|
|
223
225
|
if (!file) {
|
|
224
226
|
return {
|
|
225
227
|
middlewares: [],
|
|
226
|
-
|
|
228
|
+
serverHook: null,
|
|
227
229
|
dynamic: "auto",
|
|
228
230
|
generateStaticParams: null
|
|
229
231
|
};
|
|
@@ -239,12 +241,12 @@ function loadLoaderForDir(currentDir) {
|
|
|
239
241
|
mod = __require(file);
|
|
240
242
|
} catch (error) {
|
|
241
243
|
console.error(
|
|
242
|
-
`[framework][
|
|
244
|
+
`[framework][server-hook] Error loading server hook from ${file}:`,
|
|
243
245
|
error
|
|
244
246
|
);
|
|
245
247
|
return {
|
|
246
248
|
middlewares: [],
|
|
247
|
-
|
|
249
|
+
serverHook: null,
|
|
248
250
|
dynamic: "auto",
|
|
249
251
|
generateStaticParams: null
|
|
250
252
|
};
|
|
@@ -252,16 +254,43 @@ function loadLoaderForDir(currentDir) {
|
|
|
252
254
|
const middlewares = Array.isArray(
|
|
253
255
|
mod?.[NAMING.BEFORE_MIDDLEWARES]
|
|
254
256
|
) ? mod[NAMING.BEFORE_MIDDLEWARES] : [];
|
|
255
|
-
const
|
|
257
|
+
const serverHook = typeof mod?.[NAMING.GET_SERVER_DATA_FN] === "function" ? mod[NAMING.GET_SERVER_DATA_FN] : null;
|
|
256
258
|
const dynamic = mod?.[NAMING.RENDER_TYPE_CONST] === "force-static" || mod?.[NAMING.RENDER_TYPE_CONST] === "force-dynamic" ? mod.dynamic : "auto";
|
|
257
259
|
const generateStaticParams = typeof mod?.[NAMING.GENERATE_SSG_PARAMS] === "function" ? mod[NAMING.GENERATE_SSG_PARAMS] : null;
|
|
258
260
|
return {
|
|
259
261
|
middlewares,
|
|
260
|
-
|
|
262
|
+
serverHook,
|
|
261
263
|
dynamic,
|
|
262
264
|
generateStaticParams
|
|
263
265
|
};
|
|
264
266
|
}
|
|
267
|
+
function loadLayoutServerHook(layoutFile) {
|
|
268
|
+
const layoutDir = path3.dirname(layoutFile);
|
|
269
|
+
const layoutBasename = path3.basename(layoutFile, path3.extname(layoutFile));
|
|
270
|
+
const serverHookTs = path3.join(layoutDir, `${layoutBasename}.server.hook.ts`);
|
|
271
|
+
const serverHookJs = path3.join(layoutDir, `${layoutBasename}.server.hook.js`);
|
|
272
|
+
const file = fs3.existsSync(serverHookTs) ? serverHookTs : fs3.existsSync(serverHookJs) ? serverHookJs : null;
|
|
273
|
+
if (!file) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
277
|
+
try {
|
|
278
|
+
__require("tsx/cjs");
|
|
279
|
+
} catch (e) {
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
const mod = __require(file);
|
|
284
|
+
const serverHook = typeof mod?.getServerSideProps === "function" ? mod.getServerSideProps : null;
|
|
285
|
+
return serverHook;
|
|
286
|
+
} catch (error) {
|
|
287
|
+
console.error(
|
|
288
|
+
`[framework][server-hook] Error loading layout server hook from ${file}:`,
|
|
289
|
+
error
|
|
290
|
+
);
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
265
294
|
|
|
266
295
|
// modules/router/loader-pages.ts
|
|
267
296
|
function loadRoutes(appDir) {
|
|
@@ -293,7 +322,12 @@ function loadRoutes(appDir) {
|
|
|
293
322
|
currentDir,
|
|
294
323
|
appDir
|
|
295
324
|
);
|
|
296
|
-
const
|
|
325
|
+
const layoutServerHooks = [];
|
|
326
|
+
for (const layoutFile of layoutFiles) {
|
|
327
|
+
const layoutServerHook = loadLayoutServerHook(layoutFile);
|
|
328
|
+
layoutServerHooks.push(layoutServerHook);
|
|
329
|
+
}
|
|
330
|
+
const { middlewares, serverHook, dynamic, generateStaticParams } = loadServerHookForDir(currentDir);
|
|
297
331
|
routes.push({
|
|
298
332
|
pattern: routePath,
|
|
299
333
|
regex,
|
|
@@ -303,7 +337,10 @@ function loadRoutes(appDir) {
|
|
|
303
337
|
pageFile: fullPath,
|
|
304
338
|
layoutFiles,
|
|
305
339
|
middlewares,
|
|
306
|
-
loader,
|
|
340
|
+
loader: serverHook,
|
|
341
|
+
// Keep 'loader' field name for backward compatibility
|
|
342
|
+
layoutServerHooks,
|
|
343
|
+
// Server hooks for each layout (same order as layouts)
|
|
307
344
|
dynamic,
|
|
308
345
|
generateStaticParams
|
|
309
346
|
});
|
|
@@ -822,7 +859,12 @@ function loadRoutesFromManifest(projectRoot) {
|
|
|
822
859
|
(f) => path8.join(projectRoot, f)
|
|
823
860
|
);
|
|
824
861
|
const pageDir = path8.dirname(pageFile);
|
|
825
|
-
const
|
|
862
|
+
const layoutServerHooks = [];
|
|
863
|
+
for (const layoutFile of layoutFiles) {
|
|
864
|
+
const layoutServerHook = loadLayoutServerHook(layoutFile);
|
|
865
|
+
layoutServerHooks.push(layoutServerHook);
|
|
866
|
+
}
|
|
867
|
+
const { middlewares, serverHook, dynamic, generateStaticParams } = loadServerHookForDir(pageDir);
|
|
826
868
|
pageRoutes.push({
|
|
827
869
|
pattern: entry.pattern,
|
|
828
870
|
regex,
|
|
@@ -832,7 +874,10 @@ function loadRoutesFromManifest(projectRoot) {
|
|
|
832
874
|
pageFile,
|
|
833
875
|
layoutFiles,
|
|
834
876
|
middlewares,
|
|
835
|
-
loader,
|
|
877
|
+
loader: serverHook,
|
|
878
|
+
// Keep 'loader' field name for backward compatibility
|
|
879
|
+
layoutServerHooks,
|
|
880
|
+
// Server hooks for each layout (same order as layouts)
|
|
836
881
|
dynamic: entry.dynamic ?? dynamic,
|
|
837
882
|
generateStaticParams
|
|
838
883
|
});
|
|
@@ -1086,7 +1131,12 @@ function loadNotFoundRouteFromFilesystem(appDir) {
|
|
|
1086
1131
|
notFoundDir,
|
|
1087
1132
|
appDir
|
|
1088
1133
|
);
|
|
1089
|
-
const
|
|
1134
|
+
const layoutServerHooks = [];
|
|
1135
|
+
for (const layoutFile of layoutFiles) {
|
|
1136
|
+
const layoutServerHook = loadLayoutServerHook(layoutFile);
|
|
1137
|
+
layoutServerHooks.push(layoutServerHook);
|
|
1138
|
+
}
|
|
1139
|
+
const { middlewares, serverHook, dynamic, generateStaticParams } = loadServerHookForDir(notFoundDir);
|
|
1090
1140
|
return {
|
|
1091
1141
|
pattern: NOT_FOUND_PATTERN,
|
|
1092
1142
|
regex: new RegExp(`^${NOT_FOUND_PATTERN}/?$`),
|
|
@@ -1096,7 +1146,10 @@ function loadNotFoundRouteFromFilesystem(appDir) {
|
|
|
1096
1146
|
pageFile: notFoundFile,
|
|
1097
1147
|
layoutFiles,
|
|
1098
1148
|
middlewares,
|
|
1099
|
-
loader,
|
|
1149
|
+
loader: serverHook,
|
|
1150
|
+
// Keep 'loader' field name for backward compatibility
|
|
1151
|
+
layoutServerHooks,
|
|
1152
|
+
// Server hooks for each layout (same order as layouts)
|
|
1100
1153
|
dynamic,
|
|
1101
1154
|
generateStaticParams
|
|
1102
1155
|
};
|
|
@@ -1127,7 +1180,12 @@ function loadErrorRouteFromFilesystem(appDir) {
|
|
|
1127
1180
|
appDir,
|
|
1128
1181
|
appDir
|
|
1129
1182
|
);
|
|
1130
|
-
const
|
|
1183
|
+
const layoutServerHooks = [];
|
|
1184
|
+
for (const layoutFile of layoutFiles) {
|
|
1185
|
+
const layoutServerHook = loadLayoutServerHook(layoutFile);
|
|
1186
|
+
layoutServerHooks.push(layoutServerHook);
|
|
1187
|
+
}
|
|
1188
|
+
const { middlewares, serverHook, dynamic, generateStaticParams } = loadServerHookForDir(appDir);
|
|
1131
1189
|
return {
|
|
1132
1190
|
pattern: ERROR_PATTERN,
|
|
1133
1191
|
regex: new RegExp(`^${ERROR_PATTERN}/?$`),
|
|
@@ -1137,7 +1195,10 @@ function loadErrorRouteFromFilesystem(appDir) {
|
|
|
1137
1195
|
pageFile: errorFile,
|
|
1138
1196
|
layoutFiles,
|
|
1139
1197
|
middlewares,
|
|
1140
|
-
loader,
|
|
1198
|
+
loader: serverHook,
|
|
1199
|
+
// Keep 'loader' field name for backward compatibility
|
|
1200
|
+
layoutServerHooks,
|
|
1201
|
+
// Server hooks for each layout (same order as layouts)
|
|
1141
1202
|
dynamic,
|
|
1142
1203
|
generateStaticParams
|
|
1143
1204
|
};
|
|
@@ -3977,8 +4038,8 @@ async function runRouteMiddlewares(route, ctx) {
|
|
|
3977
4038
|
}
|
|
3978
4039
|
}
|
|
3979
4040
|
|
|
3980
|
-
// modules/server/handlers/
|
|
3981
|
-
async function
|
|
4041
|
+
// modules/server/handlers/server-hook.ts
|
|
4042
|
+
async function runRouteServerHook(route, ctx) {
|
|
3982
4043
|
if (!route.loader) {
|
|
3983
4044
|
return { props: {} };
|
|
3984
4045
|
}
|
|
@@ -4135,11 +4196,39 @@ async function handlePageRequestInternal(options) {
|
|
|
4135
4196
|
pathname: urlPath,
|
|
4136
4197
|
locals: {}
|
|
4137
4198
|
};
|
|
4138
|
-
|
|
4199
|
+
const layoutProps2 = {};
|
|
4200
|
+
if (notFoundPage.layoutServerHooks && notFoundPage.layoutServerHooks.length > 0) {
|
|
4201
|
+
for (let i = 0; i < notFoundPage.layoutServerHooks.length; i++) {
|
|
4202
|
+
const layoutServerHook = notFoundPage.layoutServerHooks[i];
|
|
4203
|
+
if (layoutServerHook) {
|
|
4204
|
+
try {
|
|
4205
|
+
const layoutResult = await layoutServerHook(ctx2);
|
|
4206
|
+
if (layoutResult.props) {
|
|
4207
|
+
Object.assign(layoutProps2, layoutResult.props);
|
|
4208
|
+
}
|
|
4209
|
+
} catch (error) {
|
|
4210
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4211
|
+
reqLogger2.warn(`Layout server hook ${i} failed for not-found`, {
|
|
4212
|
+
error,
|
|
4213
|
+
layoutFile: notFoundPage.layoutFiles[i]
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
let loaderResult2 = await runRouteServerHook(notFoundPage, ctx2);
|
|
4139
4220
|
if (!loaderResult2.theme) {
|
|
4140
4221
|
loaderResult2.theme = theme;
|
|
4141
4222
|
}
|
|
4142
|
-
const
|
|
4223
|
+
const combinedProps2 = {
|
|
4224
|
+
...layoutProps2,
|
|
4225
|
+
...loaderResult2.props || {}
|
|
4226
|
+
};
|
|
4227
|
+
const combinedLoaderResult2 = {
|
|
4228
|
+
...loaderResult2,
|
|
4229
|
+
props: combinedProps2
|
|
4230
|
+
};
|
|
4231
|
+
const initialData2 = buildInitialData(urlPath, {}, combinedLoaderResult2);
|
|
4143
4232
|
const appTree2 = buildAppTree(notFoundPage, {}, initialData2.props);
|
|
4144
4233
|
initialData2.notFound = true;
|
|
4145
4234
|
const nonce2 = res.locals.nonce || void 0;
|
|
@@ -4147,7 +4236,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4147
4236
|
appTree: appTree2,
|
|
4148
4237
|
initialData: initialData2,
|
|
4149
4238
|
routerData,
|
|
4150
|
-
meta:
|
|
4239
|
+
meta: combinedLoaderResult2.metadata ?? null,
|
|
4151
4240
|
titleFallback: "Not found",
|
|
4152
4241
|
descriptionFallback: "Loly demo",
|
|
4153
4242
|
chunkHref: null,
|
|
@@ -4166,8 +4255,8 @@ async function handlePageRequestInternal(options) {
|
|
|
4166
4255
|
},
|
|
4167
4256
|
onShellError(err) {
|
|
4168
4257
|
didError2 = true;
|
|
4169
|
-
const
|
|
4170
|
-
|
|
4258
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4259
|
+
reqLogger2.error("SSR shell error", err, { route: "not-found" });
|
|
4171
4260
|
if (!res.headersSent && errorPage) {
|
|
4172
4261
|
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
|
|
4173
4262
|
} else if (!res.headersSent) {
|
|
@@ -4179,8 +4268,8 @@ async function handlePageRequestInternal(options) {
|
|
|
4179
4268
|
},
|
|
4180
4269
|
onError(err) {
|
|
4181
4270
|
didError2 = true;
|
|
4182
|
-
const
|
|
4183
|
-
|
|
4271
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4272
|
+
reqLogger2.error("SSR error", err, { route: "not-found" });
|
|
4184
4273
|
}
|
|
4185
4274
|
});
|
|
4186
4275
|
req.on("close", () => abort2());
|
|
@@ -4202,9 +4291,30 @@ async function handlePageRequestInternal(options) {
|
|
|
4202
4291
|
if (res.headersSent) {
|
|
4203
4292
|
return;
|
|
4204
4293
|
}
|
|
4294
|
+
const layoutProps = {};
|
|
4295
|
+
const reqLogger = getRequestLogger(req);
|
|
4296
|
+
if (route.layoutServerHooks && route.layoutServerHooks.length > 0) {
|
|
4297
|
+
for (let i = 0; i < route.layoutServerHooks.length; i++) {
|
|
4298
|
+
const layoutServerHook = route.layoutServerHooks[i];
|
|
4299
|
+
if (layoutServerHook) {
|
|
4300
|
+
try {
|
|
4301
|
+
const layoutResult = await layoutServerHook(ctx);
|
|
4302
|
+
if (layoutResult.props) {
|
|
4303
|
+
Object.assign(layoutProps, layoutResult.props);
|
|
4304
|
+
}
|
|
4305
|
+
} catch (error) {
|
|
4306
|
+
reqLogger.warn(`Layout server hook ${i} failed`, {
|
|
4307
|
+
error,
|
|
4308
|
+
layoutFile: route.layoutFiles[i],
|
|
4309
|
+
route: route.pattern
|
|
4310
|
+
});
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4205
4315
|
let loaderResult;
|
|
4206
4316
|
try {
|
|
4207
|
-
loaderResult = await
|
|
4317
|
+
loaderResult = await runRouteServerHook(route, ctx);
|
|
4208
4318
|
if (!loaderResult.theme) {
|
|
4209
4319
|
loaderResult.theme = theme;
|
|
4210
4320
|
}
|
|
@@ -4223,8 +4333,18 @@ async function handlePageRequestInternal(options) {
|
|
|
4223
4333
|
}
|
|
4224
4334
|
}
|
|
4225
4335
|
}
|
|
4336
|
+
const combinedProps = {
|
|
4337
|
+
...layoutProps,
|
|
4338
|
+
// Props from layouts (stable)
|
|
4339
|
+
...loaderResult.props || {}
|
|
4340
|
+
// Props from page (overrides layout)
|
|
4341
|
+
};
|
|
4342
|
+
const combinedLoaderResult = {
|
|
4343
|
+
...loaderResult,
|
|
4344
|
+
props: combinedProps
|
|
4345
|
+
};
|
|
4226
4346
|
if (isDataReq) {
|
|
4227
|
-
handleDataResponse(res,
|
|
4347
|
+
handleDataResponse(res, combinedLoaderResult, theme);
|
|
4228
4348
|
return;
|
|
4229
4349
|
}
|
|
4230
4350
|
if (loaderResult.redirect) {
|
|
@@ -4239,7 +4359,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4239
4359
|
}
|
|
4240
4360
|
return;
|
|
4241
4361
|
}
|
|
4242
|
-
const initialData = buildInitialData(urlPath, params,
|
|
4362
|
+
const initialData = buildInitialData(urlPath, params, combinedLoaderResult);
|
|
4243
4363
|
const appTree = buildAppTree(route, params, initialData.props);
|
|
4244
4364
|
const chunkName = routeChunks[route.pattern];
|
|
4245
4365
|
let chunkHref = null;
|
|
@@ -4255,7 +4375,7 @@ async function handlePageRequestInternal(options) {
|
|
|
4255
4375
|
appTree,
|
|
4256
4376
|
initialData,
|
|
4257
4377
|
routerData,
|
|
4258
|
-
meta:
|
|
4378
|
+
meta: combinedLoaderResult.metadata,
|
|
4259
4379
|
titleFallback: "Loly framework",
|
|
4260
4380
|
descriptionFallback: "Loly demo",
|
|
4261
4381
|
chunkHref,
|
|
@@ -4276,8 +4396,8 @@ async function handlePageRequestInternal(options) {
|
|
|
4276
4396
|
},
|
|
4277
4397
|
onShellError(err) {
|
|
4278
4398
|
didError = true;
|
|
4279
|
-
const
|
|
4280
|
-
|
|
4399
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4400
|
+
reqLogger2.error("SSR shell error", err, { route: matched?.route?.pattern || "unknown" });
|
|
4281
4401
|
if (!res.headersSent && errorPage) {
|
|
4282
4402
|
renderErrorPageWithStream(errorPage, req, res, err, routeChunks, theme, projectRoot, env);
|
|
4283
4403
|
} else if (!res.headersSent) {
|
|
@@ -4289,8 +4409,8 @@ async function handlePageRequestInternal(options) {
|
|
|
4289
4409
|
},
|
|
4290
4410
|
onError(err) {
|
|
4291
4411
|
didError = true;
|
|
4292
|
-
const
|
|
4293
|
-
|
|
4412
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4413
|
+
reqLogger2.error("SSR error", err, { route: matched?.route?.pattern || "unknown" });
|
|
4294
4414
|
}
|
|
4295
4415
|
});
|
|
4296
4416
|
req.on("close", () => {
|
|
@@ -4307,11 +4427,39 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4307
4427
|
pathname: req.path,
|
|
4308
4428
|
locals: { error }
|
|
4309
4429
|
};
|
|
4310
|
-
|
|
4430
|
+
const layoutProps = {};
|
|
4431
|
+
const reqLogger = getRequestLogger(req);
|
|
4432
|
+
if (errorPage.layoutServerHooks && errorPage.layoutServerHooks.length > 0) {
|
|
4433
|
+
for (let i = 0; i < errorPage.layoutServerHooks.length; i++) {
|
|
4434
|
+
const layoutServerHook = errorPage.layoutServerHooks[i];
|
|
4435
|
+
if (layoutServerHook) {
|
|
4436
|
+
try {
|
|
4437
|
+
const layoutResult = await layoutServerHook(ctx);
|
|
4438
|
+
if (layoutResult.props) {
|
|
4439
|
+
Object.assign(layoutProps, layoutResult.props);
|
|
4440
|
+
}
|
|
4441
|
+
} catch (err) {
|
|
4442
|
+
reqLogger.warn(`Layout server hook ${i} failed for error page`, {
|
|
4443
|
+
error: err,
|
|
4444
|
+
layoutFile: errorPage.layoutFiles[i]
|
|
4445
|
+
});
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
let loaderResult = await runRouteServerHook(errorPage, ctx);
|
|
4311
4451
|
if (!loaderResult.theme && theme) {
|
|
4312
4452
|
loaderResult.theme = theme;
|
|
4313
4453
|
}
|
|
4314
|
-
const
|
|
4454
|
+
const combinedProps = {
|
|
4455
|
+
...layoutProps,
|
|
4456
|
+
...loaderResult.props || {}
|
|
4457
|
+
};
|
|
4458
|
+
const combinedLoaderResult = {
|
|
4459
|
+
...loaderResult,
|
|
4460
|
+
props: combinedProps
|
|
4461
|
+
};
|
|
4462
|
+
const initialData = buildInitialData(req.path, { error: String(error) }, combinedLoaderResult);
|
|
4315
4463
|
const routerData = buildRouterData(req);
|
|
4316
4464
|
initialData.error = true;
|
|
4317
4465
|
if (isDataReq) {
|
|
@@ -4321,8 +4469,8 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4321
4469
|
error: true,
|
|
4322
4470
|
message: String(error),
|
|
4323
4471
|
props: initialData.props,
|
|
4324
|
-
metadata:
|
|
4325
|
-
theme:
|
|
4472
|
+
metadata: combinedLoaderResult.metadata ?? null,
|
|
4473
|
+
theme: combinedLoaderResult.theme ?? theme ?? null
|
|
4326
4474
|
}));
|
|
4327
4475
|
return;
|
|
4328
4476
|
}
|
|
@@ -4344,7 +4492,7 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4344
4492
|
appTree,
|
|
4345
4493
|
initialData,
|
|
4346
4494
|
routerData,
|
|
4347
|
-
meta:
|
|
4495
|
+
meta: combinedLoaderResult.metadata ?? null,
|
|
4348
4496
|
titleFallback: "Error",
|
|
4349
4497
|
descriptionFallback: "An error occurred",
|
|
4350
4498
|
chunkHref,
|
|
@@ -4365,8 +4513,8 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4365
4513
|
},
|
|
4366
4514
|
onShellError(err) {
|
|
4367
4515
|
didError = true;
|
|
4368
|
-
const
|
|
4369
|
-
|
|
4516
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4517
|
+
reqLogger2.error("Error rendering error page", err, { type: "shellError" });
|
|
4370
4518
|
if (!res.headersSent) {
|
|
4371
4519
|
res.statusCode = 500;
|
|
4372
4520
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
@@ -4376,8 +4524,8 @@ async function renderErrorPageWithStream(errorPage, req, res, error, routeChunks
|
|
|
4376
4524
|
},
|
|
4377
4525
|
onError(err) {
|
|
4378
4526
|
didError = true;
|
|
4379
|
-
const
|
|
4380
|
-
|
|
4527
|
+
const reqLogger2 = getRequestLogger(req);
|
|
4528
|
+
reqLogger2.error("Error in error page", err);
|
|
4381
4529
|
}
|
|
4382
4530
|
});
|
|
4383
4531
|
req.on("close", () => {
|