@qwik.dev/router 2.0.0-beta.3 → 2.0.0-beta.5

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.
@@ -229,8 +229,11 @@ var RewriteMessage = class extends AbortMessage {
229
229
  // packages/qwik-router/src/runtime/src/constants.ts
230
230
  var MODULE_CACHE = /* @__PURE__ */ new WeakMap();
231
231
  var QACTION_KEY = "qaction";
232
+ var QLOADER_KEY = "qloaders";
232
233
  var QFN_KEY = "qfunc";
233
234
  var QDATA_KEY = "qdata";
235
+ var Q_ROUTE = "q:route";
236
+ var DEFAULT_LOADERS_SERIALIZATION_STRATEGY = globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__ || "never";
234
237
 
235
238
  // packages/qwik-router/src/runtime/src/route-matcher.ts
236
239
  function matchRoute(route, path) {
@@ -352,6 +355,19 @@ function lastIndexOf(text, start, match, searchIdx, notFoundIdx) {
352
355
  return idx > start ? idx : notFoundIdx;
353
356
  }
354
357
 
358
+ // packages/qwik-router/src/runtime/src/utils.ts
359
+ import { createAsyncComputed$, isBrowser as isBrowser2 } from "@qwik.dev/core";
360
+ import {
361
+ _UNINITIALIZED
362
+ } from "@qwik.dev/core/internal";
363
+
364
+ // packages/qwik-router/src/runtime/src/use-endpoint.ts
365
+ import { _deserialize } from "@qwik.dev/core/internal";
366
+
367
+ // packages/qwik-router/src/runtime/src/client-navigate.ts
368
+ import { isBrowser } from "@qwik.dev/core";
369
+ import { p as preload } from "@qwik.dev/core/preloader";
370
+
355
371
  // packages/qwik-router/src/runtime/src/utils.ts
356
372
  var isPromise = (value) => {
357
373
  return value && typeof value.then === "function";
@@ -375,13 +391,13 @@ var loadRoute = async (routes, menus, cacheModules, pathname) => {
375
391
  return null;
376
392
  }
377
393
  for (const routeData of routes) {
378
- const routeName = routeData[0];
394
+ const routeName = routeData[0 /* RouteName */];
379
395
  const params = matchRoute(routeName, pathname);
380
396
  if (!params) {
381
397
  continue;
382
398
  }
383
- const loaders = routeData[1];
384
- const routeBundleNames = routeData[3];
399
+ const loaders = routeData[1 /* Loaders */];
400
+ const routeBundleNames = routeData[3 /* RouteBundleNames */];
385
401
  const modules = new Array(loaders.length);
386
402
  const pendingLoads = [];
387
403
  loaders.forEach((moduleLoader, i) => {
@@ -433,14 +449,20 @@ var getMenuLoader = (menus, pathname) => {
433
449
  if (menus) {
434
450
  pathname = pathname.endsWith("/") ? pathname : pathname + "/";
435
451
  const menu = menus.find(
436
- (m) => m[0] === pathname || pathname.startsWith(m[0] + (pathname.endsWith("/") ? "" : "/"))
452
+ (m) => m[0 /* Pathname */] === pathname || pathname.startsWith(m[0 /* Pathname */] + (pathname.endsWith("/") ? "" : "/"))
437
453
  );
438
454
  if (menu) {
439
- return menu[1];
455
+ return menu[1 /* MenuLoader */];
440
456
  }
441
457
  }
442
458
  };
443
459
 
460
+ // packages/qwik-router/src/middleware/request-handler/resolve-request-handlers.ts
461
+ import { _UNINITIALIZED as _UNINITIALIZED3 } from "@qwik.dev/core/internal";
462
+
463
+ // packages/qwik-router/src/middleware/request-handler/request-event.ts
464
+ import { _UNINITIALIZED as _UNINITIALIZED2 } from "@qwik.dev/core/internal";
465
+
444
466
  // packages/qwik-router/src/middleware/request-handler/cache-control.ts
445
467
  function createCacheControl(cacheControl) {
446
468
  const controls = [];
@@ -616,12 +638,17 @@ var RequestEvLoaders = Symbol("RequestEvLoaders");
616
638
  var RequestEvMode = Symbol("RequestEvMode");
617
639
  var RequestEvRoute = Symbol("RequestEvRoute");
618
640
  var RequestEvQwikSerializer = Symbol("RequestEvQwikSerializer");
641
+ var RequestEvLoaderSerializationStrategyMap = Symbol(
642
+ "RequestEvLoaderSerializationStrategyMap"
643
+ );
619
644
  var RequestEvTrailingSlash = Symbol("RequestEvTrailingSlash");
620
645
  var RequestRouteName = "@routeName";
621
646
  var RequestEvSharedActionId = "@actionId";
622
647
  var RequestEvSharedActionFormData = "@actionFormData";
623
648
  var RequestEvSharedNonce = "@nonce";
624
649
  var RequestEvIsRewrite = "@rewrite";
650
+ var RequestEvShareServerTiming = "@serverTiming";
651
+ var RequestEvShareQData = "qData";
625
652
  function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trailingSlash, basePathname, qwikSerializer, resolved) {
626
653
  const { request, platform, env } = serverRequestEv;
627
654
  const sharedMap = /* @__PURE__ */ new Map();
@@ -705,6 +732,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
705
732
  const loaders = {};
706
733
  const requestEv = {
707
734
  [RequestEvLoaders]: loaders,
735
+ [RequestEvLoaderSerializationStrategyMap]: /* @__PURE__ */ new Map(),
708
736
  [RequestEvMode]: serverRequestEv.mode,
709
737
  [RequestEvTrailingSlash]: trailingSlash,
710
738
  get [RequestEvRoute]() {
@@ -718,7 +746,7 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
718
746
  signal: request.signal,
719
747
  originalUrl: new URL(url),
720
748
  get params() {
721
- return (loadedRoute == null ? void 0 : loadedRoute[1]) ?? {};
749
+ return (loadedRoute == null ? void 0 : loadedRoute[1 /* Params */]) ?? {};
722
750
  },
723
751
  get pathname() {
724
752
  return url.pathname;
@@ -755,6 +783,10 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
755
783
  "You can not get the returned data of a loader that has not been executed for this request."
756
784
  );
757
785
  }
786
+ if (loaders[id] === _UNINITIALIZED2) {
787
+ const isDev = getRequestMode(requestEv) === "dev";
788
+ await getRouteLoaderPromise(loaderOrAction, loaders, requestEv, isDev, qwikSerializer);
789
+ }
758
790
  }
759
791
  return loaders[id];
760
792
  },
@@ -836,9 +868,12 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
836
868
  getWritableStream: () => {
837
869
  if (writableStream === null) {
838
870
  if (serverRequestEv.mode === "dev") {
839
- const serverTiming = sharedMap.get("@serverTiming");
871
+ const serverTiming = sharedMap.get(RequestEvShareServerTiming);
840
872
  if (serverTiming) {
841
- headers.set("Server-Timing", serverTiming.map((a) => `${a[0]};dur=${a[1]}`).join(","));
873
+ headers.set(
874
+ "Server-Timing",
875
+ serverTiming.map(([name, duration]) => `${name};dur=${duration}`).join(",")
876
+ );
842
877
  }
843
878
  }
844
879
  writableStream = serverRequestEv.getWritableStream(
@@ -857,6 +892,9 @@ function createRequestEvent(serverRequestEv, loadedRoute, requestHandlers, trail
857
892
  function getRequestLoaders(requestEv) {
858
893
  return requestEv[RequestEvLoaders];
859
894
  }
895
+ function getRequestLoaderSerializationStrategyMap(requestEv) {
896
+ return requestEv[RequestEvLoaderSerializationStrategyMap];
897
+ }
860
898
  function getRequestTrailingSlash(requestEv) {
861
899
  return requestEv[RequestEvTrailingSlash];
862
900
  }
@@ -929,13 +967,15 @@ function getQwikRouterServerData(requestEv) {
929
967
  if (protocol) {
930
968
  reconstructedUrl.protocol = protocol;
931
969
  }
970
+ const loaders = getRequestLoaders(requestEv);
971
+ const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
932
972
  return {
933
973
  url: reconstructedUrl.href,
934
974
  requestHeaders,
935
975
  locale: locale(),
936
976
  nonce,
937
977
  containerAttributes: {
938
- "q:route": routeName
978
+ [Q_ROUTE]: routeName
939
979
  },
940
980
  qwikrouter: {
941
981
  routeName,
@@ -944,7 +984,8 @@ function getQwikRouterServerData(requestEv) {
944
984
  loadedRoute: getRequestRoute(requestEv),
945
985
  response: {
946
986
  status: status(),
947
- loaders: getRequestLoaders(requestEv),
987
+ loaders,
988
+ loadersSerializationStrategy,
948
989
  action,
949
990
  formData
950
991
  }
@@ -957,7 +998,7 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
957
998
  const routeLoaders = [];
958
999
  const routeActions = [];
959
1000
  const requestHandlers = [];
960
- const isPageRoute = !!(route && isLastModulePageRoute(route[2]));
1001
+ const isPageRoute = !!(route && isLastModulePageRoute(route[2 /* Mods */]));
961
1002
  if (serverPlugins) {
962
1003
  _resolveRequestHandlers(
963
1004
  routeLoaders,
@@ -969,7 +1010,7 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
969
1010
  );
970
1011
  }
971
1012
  if (route) {
972
- const routeName = route[0];
1013
+ const routeName = route[0 /* RouteName */];
973
1014
  if (checkOrigin && (method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE")) {
974
1015
  requestHandlers.unshift(csrfCheckMiddleware);
975
1016
  }
@@ -980,7 +1021,7 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
980
1021
  requestHandlers.push(fixTrailingSlash);
981
1022
  requestHandlers.push(renderQData);
982
1023
  }
983
- const routeModules = route[2];
1024
+ const routeModules = route[2 /* Mods */];
984
1025
  requestHandlers.push(handleRedirect);
985
1026
  _resolveRequestHandlers(
986
1027
  routeLoaders,
@@ -994,7 +1035,8 @@ var resolveRequestHandlers = (serverPlugins, route, method, checkOrigin, renderH
994
1035
  requestHandlers.push((ev) => {
995
1036
  ev.sharedMap.set(RequestRouteName, routeName);
996
1037
  });
997
- requestHandlers.push(actionsMiddleware(routeActions, routeLoaders));
1038
+ requestHandlers.push(actionsMiddleware(routeActions));
1039
+ requestHandlers.push(loadersMiddleware(routeLoaders));
998
1040
  requestHandlers.push(renderHandler);
999
1041
  }
1000
1042
  }
@@ -1056,8 +1098,9 @@ var _resolveRequestHandlers = (routeLoaders, routeActions, requestHandlers, rout
1056
1098
  }
1057
1099
  }
1058
1100
  };
1059
- function actionsMiddleware(routeActions, routeLoaders) {
1060
- return async (requestEv) => {
1101
+ function actionsMiddleware(routeActions) {
1102
+ return async (requestEvent) => {
1103
+ const requestEv = requestEvent;
1061
1104
  if (requestEv.headersSent) {
1062
1105
  requestEv.exit();
1063
1106
  return;
@@ -1092,7 +1135,7 @@ function actionsMiddleware(routeActions, routeLoaders) {
1092
1135
  } else {
1093
1136
  const actionResolved = isDev ? await measure(
1094
1137
  requestEv,
1095
- action.__qrl.getSymbol().split("_", 1)[0],
1138
+ action.__qrl.getHash(),
1096
1139
  () => action.__qrl.call(requestEv, result.data, requestEv)
1097
1140
  ) : await action.__qrl.call(requestEv, result.data, requestEv);
1098
1141
  if (isDev) {
@@ -1103,46 +1146,76 @@ function actionsMiddleware(routeActions, routeLoaders) {
1103
1146
  }
1104
1147
  }
1105
1148
  }
1149
+ };
1150
+ }
1151
+ function loadersMiddleware(routeLoaders) {
1152
+ return async (requestEvent) => {
1153
+ const requestEv = requestEvent;
1154
+ if (requestEv.headersSent) {
1155
+ requestEv.exit();
1156
+ return;
1157
+ }
1158
+ const loaders = getRequestLoaders(requestEv);
1159
+ const isDev = getRequestMode(requestEv) === "dev";
1160
+ const qwikSerializer = requestEv[RequestEvQwikSerializer];
1106
1161
  if (routeLoaders.length > 0) {
1107
- const resolvedLoadersPromises = routeLoaders.map((loader) => {
1108
- const loaderId = loader.__id;
1109
- loaders[loaderId] = runValidators(
1110
- requestEv,
1111
- loader.__validators,
1112
- void 0,
1113
- // data
1114
- isDev
1115
- ).then((res) => {
1116
- if (res.success) {
1117
- if (isDev) {
1118
- return measure(
1119
- requestEv,
1120
- loader.__qrl.getSymbol().split("_", 1)[0],
1121
- () => loader.__qrl.call(requestEv, requestEv)
1122
- );
1123
- } else {
1124
- return loader.__qrl.call(requestEv, requestEv);
1125
- }
1162
+ let currentLoaders = [];
1163
+ if (requestEv.query.has(QLOADER_KEY)) {
1164
+ const selectedLoaderIds = requestEv.query.getAll(QLOADER_KEY);
1165
+ for (const loader of routeLoaders) {
1166
+ if (selectedLoaderIds.includes(loader.__id)) {
1167
+ currentLoaders.push(loader);
1126
1168
  } else {
1127
- return requestEv.fail(res.status ?? 500, res.error);
1169
+ loaders[loader.__id] = _UNINITIALIZED3;
1128
1170
  }
1129
- }).then((resolvedLoader) => {
1130
- if (typeof resolvedLoader === "function") {
1131
- loaders[loaderId] = resolvedLoader();
1132
- } else {
1133
- if (isDev) {
1134
- verifySerializable(qwikSerializer, resolvedLoader, loader.__qrl);
1135
- }
1136
- loaders[loaderId] = resolvedLoader;
1137
- }
1138
- return resolvedLoader;
1139
- });
1140
- return loaders[loaderId];
1141
- });
1171
+ }
1172
+ } else {
1173
+ currentLoaders = routeLoaders;
1174
+ }
1175
+ const resolvedLoadersPromises = currentLoaders.map(
1176
+ (loader) => getRouteLoaderPromise(loader, loaders, requestEv, isDev, qwikSerializer)
1177
+ );
1142
1178
  await Promise.all(resolvedLoadersPromises);
1143
1179
  }
1144
1180
  };
1145
1181
  }
1182
+ async function getRouteLoaderPromise(loader, loaders, requestEv, isDev, qwikSerializer) {
1183
+ const loaderId = loader.__id;
1184
+ loaders[loaderId] = runValidators(
1185
+ requestEv,
1186
+ loader.__validators,
1187
+ void 0,
1188
+ // data
1189
+ isDev
1190
+ ).then((res) => {
1191
+ if (res.success) {
1192
+ if (isDev) {
1193
+ return measure(
1194
+ requestEv,
1195
+ loader.__qrl.getHash(),
1196
+ () => loader.__qrl.call(requestEv, requestEv)
1197
+ );
1198
+ } else {
1199
+ return loader.__qrl.call(requestEv, requestEv);
1200
+ }
1201
+ } else {
1202
+ return requestEv.fail(res.status ?? 500, res.error);
1203
+ }
1204
+ }).then((resolvedLoader) => {
1205
+ if (typeof resolvedLoader === "function") {
1206
+ loaders[loaderId] = resolvedLoader();
1207
+ } else {
1208
+ if (isDev) {
1209
+ verifySerializable(qwikSerializer, resolvedLoader, loader.__qrl);
1210
+ }
1211
+ loaders[loaderId] = resolvedLoader;
1212
+ }
1213
+ return resolvedLoader;
1214
+ });
1215
+ const loadersSerializationStrategy = getRequestLoaderSerializationStrategyMap(requestEv);
1216
+ loadersSerializationStrategy.set(loaderId, loader.__serializationStrategy);
1217
+ return loaders[loaderId];
1218
+ }
1146
1219
  async function runValidators(requestEv, validators, data, isDev) {
1147
1220
  let lastResult = {
1148
1221
  success: true,
@@ -1277,7 +1350,7 @@ function getPathname(url, trailingSlash) {
1277
1350
  url.pathname = url.pathname.slice(0, -1);
1278
1351
  }
1279
1352
  }
1280
- const search = url.search.slice(1).replaceAll(/&?q(action|data|func)=[^&]+/g, "");
1353
+ const search = url.search.slice(1).replaceAll(/&?q(action|data|func|loaders)=[^&]+/g, "");
1281
1354
  return `${url.pathname}${search ? `?${search}` : ""}${url.hash}`;
1282
1355
  }
1283
1356
  var encoder = /* @__PURE__ */ new TextEncoder();
@@ -1343,7 +1416,7 @@ function renderQwikMiddleware(render) {
1343
1416
  if (typeof result.html === "string") {
1344
1417
  await stream.write(result.html);
1345
1418
  }
1346
- requestEv.sharedMap.set("qData", qData);
1419
+ requestEv.sharedMap.set(RequestEvShareQData, qData);
1347
1420
  } finally {
1348
1421
  await stream.ready;
1349
1422
  await stream.close();
@@ -1368,10 +1441,10 @@ async function handleRedirect(requestEv) {
1368
1441
  return;
1369
1442
  }
1370
1443
  const status = requestEv.status();
1371
- const location = requestEv.headers.get("Location");
1372
- const isRedirect = status >= 301 && status <= 308 && location;
1444
+ const location2 = requestEv.headers.get("Location");
1445
+ const isRedirect = status >= 301 && status <= 308 && location2;
1373
1446
  if (isRedirect) {
1374
- const adaptedLocation = makeQDataPath(location);
1447
+ const adaptedLocation = makeQDataPath(location2);
1375
1448
  if (adaptedLocation) {
1376
1449
  requestEv.headers.set("Location", adaptedLocation);
1377
1450
  requestEv.getWritableStream().close();
@@ -1397,8 +1470,24 @@ async function renderQData(requestEv) {
1397
1470
  const requestHeaders = {};
1398
1471
  requestEv.request.headers.forEach((value, key) => requestHeaders[key] = value);
1399
1472
  requestEv.headers.set("Content-Type", "application/json; charset=utf-8");
1400
- const qData = {
1401
- loaders: getRequestLoaders(requestEv),
1473
+ let loaders = getRequestLoaders(requestEv);
1474
+ const selectedLoaderIds = requestEv.query.getAll(QLOADER_KEY);
1475
+ const hasCustomLoaders = selectedLoaderIds.length > 0;
1476
+ if (hasCustomLoaders) {
1477
+ const selectedLoaders = {};
1478
+ for (const loaderId of selectedLoaderIds) {
1479
+ const loader = loaders[loaderId];
1480
+ selectedLoaders[loaderId] = loader;
1481
+ }
1482
+ loaders = selectedLoaders;
1483
+ }
1484
+ const qData = hasCustomLoaders ? {
1485
+ // send minimal data to the client
1486
+ loaders,
1487
+ status: status !== 200 ? status : 200,
1488
+ href: getPathname(requestEv.url, trailingSlash)
1489
+ } : {
1490
+ loaders,
1402
1491
  action: requestEv.sharedMap.get(RequestEvSharedActionId),
1403
1492
  status: status !== 200 ? status : 200,
1404
1493
  href: getPathname(requestEv.url, trailingSlash),
@@ -1409,7 +1498,7 @@ async function renderQData(requestEv) {
1409
1498
  const qwikSerializer = requestEv[RequestEvQwikSerializer];
1410
1499
  const data = await qwikSerializer._serialize([qData]);
1411
1500
  writer.write(encoder.encode(data));
1412
- requestEv.sharedMap.set("qData", qData);
1501
+ requestEv.sharedMap.set(RequestEvShareQData, qData);
1413
1502
  writer.close();
1414
1503
  }
1415
1504
  function makeQDataPath(href) {
@@ -1431,9 +1520,9 @@ async function measure(requestEv, name, fn) {
1431
1520
  return await fn();
1432
1521
  } finally {
1433
1522
  const duration = now() - start;
1434
- let measurements = requestEv.sharedMap.get("@serverTiming");
1523
+ let measurements = requestEv.sharedMap.get(RequestEvShareServerTiming);
1435
1524
  if (!measurements) {
1436
- requestEv.sharedMap.set("@serverTiming", measurements = []);
1525
+ requestEv.sharedMap.set(RequestEvShareServerTiming, measurements = []);
1437
1526
  }
1438
1527
  measurements.push([name, duration]);
1439
1528
  }
@@ -1561,6 +1650,7 @@ var _TextEncoderStream_polyfill = class {
1561
1650
  export {
1562
1651
  AbortMessage,
1563
1652
  RedirectMessage,
1653
+ RequestEvShareQData,
1564
1654
  RewriteMessage,
1565
1655
  ServerError,
1566
1656
  _TextEncoderStream_polyfill,
@@ -232,7 +232,7 @@ async function workerRender(sys, opts, staticRoute, pendingPromises, callback) {
232
232
  const writePromises = [];
233
233
  try {
234
234
  if (writeQDataEnabled) {
235
- const qData = requestEv.sharedMap.get("qData");
235
+ const qData = requestEv.sharedMap.get(import_request_handler.RequestEvShareQData);
236
236
  if (qData && !is404ErrorPage) {
237
237
  const qDataFilePath = sys.getDataFilePath(url.pathname);
238
238
  const dataWriter = sys.createWriteStream(qDataFilePath);
@@ -837,7 +837,9 @@ async function generateNotFoundPages(sys, opts, routes) {
837
837
  if (opts.emit404Pages !== false) {
838
838
  const basePathname = opts.basePathname || "/";
839
839
  const rootNotFoundPathname = basePathname + "404.html";
840
- const hasRootNotFound = routes.some((r) => r[2] === rootNotFoundPathname);
840
+ const hasRootNotFound = routes.some(
841
+ (r) => r[2 /* OriginalPathname */] === rootNotFoundPathname
842
+ );
841
843
  if (!hasRootNotFound) {
842
844
  const filePath = sys.getRouteFilePath(rootNotFoundPathname, true);
843
845
  const html = (0, import_request_handler2.getErrorHtml)(404, "Resource Not Found");
@@ -59,7 +59,7 @@ function normalizePathSlash(path) {
59
59
 
60
60
  // packages/qwik-router/src/static/worker-thread.ts
61
61
  import { _deserialize, _serialize, _verifySerializable } from "@qwik.dev/core/internal";
62
- import { requestHandler } from "../middleware/request-handler/index.mjs";
62
+ import { requestHandler, RequestEvShareQData } from "../middleware/request-handler/index.mjs";
63
63
  import { WritableStream } from "node:stream/web";
64
64
  import { pathToFileURL } from "node:url";
65
65
  async function workerThread(sys) {
@@ -196,7 +196,7 @@ async function workerRender(sys, opts, staticRoute, pendingPromises, callback) {
196
196
  const writePromises = [];
197
197
  try {
198
198
  if (writeQDataEnabled) {
199
- const qData = requestEv.sharedMap.get("qData");
199
+ const qData = requestEv.sharedMap.get(RequestEvShareQData);
200
200
  if (qData && !is404ErrorPage) {
201
201
  const qDataFilePath = sys.getDataFilePath(url.pathname);
202
202
  const dataWriter = sys.createWriteStream(qDataFilePath);
@@ -800,7 +800,9 @@ async function generateNotFoundPages(sys, opts, routes) {
800
800
  if (opts.emit404Pages !== false) {
801
801
  const basePathname = opts.basePathname || "/";
802
802
  const rootNotFoundPathname = basePathname + "404.html";
803
- const hasRootNotFound = routes.some((r) => r[2] === rootNotFoundPathname);
803
+ const hasRootNotFound = routes.some(
804
+ (r) => r[2 /* OriginalPathname */] === rootNotFoundPathname
805
+ );
804
806
  if (!hasRootNotFound) {
805
807
  const filePath = sys.getRouteFilePath(rootNotFoundPathname, true);
806
808
  const html = getErrorHtml(404, "Resource Not Found");