@blinkk/root 1.0.0-alpha.9 → 1.0.0-beta.1

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/dist/render.js CHANGED
@@ -1,10 +1,14 @@
1
1
  import {
2
- ErrorPage,
3
- HEAD_CONTEXT,
2
+ htmlMinify,
3
+ htmlPretty,
4
+ parseTagNames
5
+ } from "./chunk-GGQGZ7ZE.js";
6
+ import {
7
+ HTML_CONTEXT,
4
8
  I18N_CONTEXT,
5
- SCRIPT_CONTEXT,
9
+ REQUEST_CONTEXT,
6
10
  getTranslations
7
- } from "./chunk-ZV52A6YZ.js";
11
+ } from "./chunk-WTSNW7BB.js";
8
12
 
9
13
  // src/render/render.tsx
10
14
  import renderToString from "preact-render-to-string";
@@ -149,8 +153,9 @@ function getRoutes(config) {
149
153
  }
150
154
  );
151
155
  const trie = new RouteTrie();
152
- Object.keys(routes).forEach((filePath) => {
153
- let routePath = filePath.replace(/^\/routes/, "");
156
+ Object.keys(routes).forEach((modulePath) => {
157
+ const src = modulePath.slice(1);
158
+ let routePath = modulePath.replace(/^\/routes/, "");
154
159
  const parts = path.parse(routePath);
155
160
  if (parts.name.startsWith("_")) {
156
161
  return;
@@ -160,18 +165,23 @@ function getRoutes(config) {
160
165
  } else {
161
166
  routePath = path.join(parts.dir, parts.name);
162
167
  }
168
+ const localeRoutePath = i18nUrlFormat.replace("{locale}", "[locale]").replace("{path}", routePath.replace(/^\/*/, ""));
163
169
  trie.add(routePath, {
164
- modulePath: filePath,
165
- module: routes[filePath],
166
- locale: defaultLocale
170
+ src,
171
+ module: routes[modulePath],
172
+ locale: defaultLocale,
173
+ routePath,
174
+ localeRoutePath
167
175
  });
168
176
  locales.forEach((locale) => {
169
- const localeRoutePath = i18nUrlFormat.replace("{locale}", locale).replace("{path}", routePath.replace(/^\/*/, ""));
170
- if (localeRoutePath !== routePath) {
171
- trie.add(localeRoutePath, {
172
- modulePath: filePath,
173
- module: routes[filePath],
174
- locale
177
+ const localePath = localeRoutePath.replace("[locale]", locale);
178
+ if (localePath !== routePath) {
179
+ trie.add(localePath, {
180
+ src,
181
+ module: routes[modulePath],
182
+ locale,
183
+ routePath,
184
+ localeRoutePath
175
185
  });
176
186
  }
177
187
  });
@@ -179,17 +189,33 @@ function getRoutes(config) {
179
189
  return trie;
180
190
  }
181
191
  async function getAllPathsForRoute(urlPathFormat, route) {
182
- const urlPaths = [];
183
192
  const routeModule = route.module;
193
+ if (!routeModule.default) {
194
+ return [];
195
+ }
196
+ const urlPaths = [];
184
197
  if (routeModule.getStaticPaths) {
185
198
  const staticPaths = await routeModule.getStaticPaths();
186
- staticPaths.paths.forEach(
187
- (pathParams) => {
188
- urlPaths.push({
189
- urlPath: replaceParams(urlPathFormat, pathParams.params),
190
- params: pathParams.params || {}
191
- });
192
- }
199
+ if (staticPaths.paths) {
200
+ staticPaths.paths.forEach(
201
+ (pathParams) => {
202
+ const urlPath = replaceParams(urlPathFormat, pathParams.params || {});
203
+ if (pathContainsPlaceholders(urlPath)) {
204
+ console.warn(
205
+ `path contains placeholders: ${urlPathFormat}, double check getStaticPaths() and ensure all params are returned. more info: https://rootjs.dev/guide/routes#getStaticPaths`
206
+ );
207
+ } else {
208
+ urlPaths.push({
209
+ urlPath: replaceParams(urlPathFormat, pathParams.params),
210
+ params: pathParams.params || {}
211
+ });
212
+ }
213
+ }
214
+ );
215
+ }
216
+ } else if (pathContainsPlaceholders(urlPathFormat)) {
217
+ console.warn(
218
+ `path contains placeholders: ${urlPathFormat}, did you forget to define getStaticPaths()? more info: https://rootjs.dev/guide/routes#getStaticPaths`
193
219
  );
194
220
  } else {
195
221
  urlPaths.push({ urlPath: urlPathFormat, params: {} });
@@ -209,189 +235,363 @@ function replaceParams(urlPathFormat, params) {
209
235
  );
210
236
  return urlPath;
211
237
  }
238
+ function pathContainsPlaceholders(urlPath) {
239
+ const segments = urlPath.split("/");
240
+ return segments.some((segment) => {
241
+ return segment.startsWith("[") && segment.endsWith("]");
242
+ });
243
+ }
212
244
 
213
- // src/render/render.tsx
214
- import { elementsMap } from "virtual:root-elements";
215
-
216
- // src/core/components/dev-not-found-page.tsx
245
+ // src/core/pages/ErrorPage.tsx
217
246
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
218
247
  var STYLES = `
248
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
249
+
250
+ :root {
251
+ --font-family-text: "Inter", sans-serif;
252
+ }
253
+
219
254
  body {
220
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
255
+ font-family: var(--font-family-text);
256
+ background: #F5F5F5;
257
+ padding: 40px 16px;
258
+ }
259
+
260
+ .root {
261
+ max-width: 1200px;
262
+ margin: 0 auto;
221
263
  }
222
264
 
223
265
  h1 {
224
266
  margin-bottom: 40px;
225
267
  }
226
268
 
227
- .route-list {
228
- display: grid;
229
- grid-template-columns: auto 1fr;
230
- align-items: center;
231
- column-gap: 24px;
232
- row-gap: 8px;
233
- padding: 0 40px;
269
+ h2 {
270
+ margin-top: 30px;
271
+ }
272
+
273
+ .box {
274
+ font-size: 16px;
275
+ line-height: 1.5;
276
+ padding: 16px;
277
+ border-radius: 12px;
278
+ background: #ffffff;
234
279
  }
235
280
 
236
- .route-module {
237
- text-align: right;
281
+ pre.box {
282
+ white-space: pre-wrap;
238
283
  }
239
284
 
240
- hr {
241
- margin: 60px 0;
285
+ @media (min-width: 500px) {
286
+ body {
287
+ padding: 40px;
288
+ }
289
+
290
+ .box {
291
+ padding: 24px;
292
+ }
293
+ }
294
+
295
+ @media (min-width: 1024px) {
296
+ body {
297
+ padding: 100px;
298
+ }
242
299
  }
243
300
  `;
244
- function DevNotFoundPage(props) {
245
- const routesList = [];
246
- Object.keys(props.routes).forEach((urlPath) => {
247
- routesList.push(Object.assign({}, props.routes[urlPath], { urlPath }));
248
- });
301
+ function ErrorPage(props) {
302
+ const { code, message } = props;
303
+ const title = props.title ? `${code} | ${props.title}` : code;
249
304
  return /* @__PURE__ */ jsxs(Fragment, {
250
305
  children: [
251
306
  /* @__PURE__ */ jsx("style", {
252
307
  dangerouslySetInnerHTML: { __html: STYLES }
253
308
  }),
254
309
  /* @__PURE__ */ jsxs("div", {
310
+ className: "root",
255
311
  children: [
256
- /* @__PURE__ */ jsxs("h1", {
257
- children: [
258
- /* @__PURE__ */ jsx("strong", {
259
- children: "404:"
260
- }),
261
- " Not Found"
262
- ]
312
+ /* @__PURE__ */ jsx("h1", {
313
+ children: title
263
314
  }),
264
- routesList.length > 0 ? /* @__PURE__ */ jsxs(Fragment, {
265
- children: [
266
- /* @__PURE__ */ jsx("h2", {
267
- children: "Routes found in the project:"
268
- }),
269
- /* @__PURE__ */ jsx("div", {
270
- class: "route-list",
271
- children: routesList.map((route) => /* @__PURE__ */ jsxs(Fragment, {
272
- children: [
273
- /* @__PURE__ */ jsx("div", {
274
- class: "route-module",
275
- children: route.modulePath
276
- }),
277
- /* @__PURE__ */ jsx("a", {
278
- class: "route-url",
279
- href: route.urlPath,
280
- children: route.urlPath
281
- })
282
- ]
283
- }))
284
- })
285
- ]
286
- }) : /* @__PURE__ */ jsxs(Fragment, {
287
- children: [
288
- /* @__PURE__ */ jsx("h2", {
289
- children: "No routes found in the project"
290
- }),
291
- /* @__PURE__ */ jsxs("p", {
292
- children: [
293
- "Add your first route at ",
294
- /* @__PURE__ */ jsx("code", {
295
- children: "/routes/index.tsx"
296
- })
297
- ]
298
- })
299
- ]
315
+ message && /* @__PURE__ */ jsx("p", {
316
+ children: message
300
317
  }),
301
- /* @__PURE__ */ jsx("hr", {}),
302
- /* @__PURE__ */ jsx("p", {
303
- children: "Note: This page could use some love! If you're interested in helping to style this page, please reach out to the root.js developers!"
318
+ props.children
319
+ ]
320
+ })
321
+ ]
322
+ });
323
+ }
324
+
325
+ // src/core/pages/DevNotFoundPage.tsx
326
+ import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
327
+ function DevNotFoundPage(props) {
328
+ const req = props.req;
329
+ const routesList = [];
330
+ let urlMaxLength = 0;
331
+ Object.keys(props.sitemap).forEach((urlPath) => {
332
+ const route = props.sitemap[urlPath].route;
333
+ routesList.push(Object.assign({}, route, { urlPath }));
334
+ if (urlPath.length > urlMaxLength) {
335
+ urlMaxLength = urlPath.length;
336
+ }
337
+ });
338
+ const routesListString = routesList.map((route) => {
339
+ return `${route.urlPath.padEnd(urlMaxLength, " ")} => ${route.src}`;
340
+ }).join("\n");
341
+ return /* @__PURE__ */ jsxs2(ErrorPage, {
342
+ code: 404,
343
+ title: "Root.js",
344
+ children: [
345
+ /* @__PURE__ */ jsx2("h2", {
346
+ children: "Routes"
347
+ }),
348
+ routesList.length > 0 ? /* @__PURE__ */ jsx2("pre", {
349
+ className: "box",
350
+ children: /* @__PURE__ */ jsx2("code", {
351
+ children: routesListString
352
+ })
353
+ }) : /* @__PURE__ */ jsxs2("div", {
354
+ className: "box",
355
+ children: [
356
+ "Add your first route at ",
357
+ /* @__PURE__ */ jsx2("code", {
358
+ children: "/routes/index.tsx"
304
359
  })
305
360
  ]
361
+ }),
362
+ /* @__PURE__ */ jsx2("h2", {
363
+ children: "Debug Info"
364
+ }),
365
+ /* @__PURE__ */ jsx2("pre", {
366
+ className: "box",
367
+ children: /* @__PURE__ */ jsx2("code", {
368
+ children: `url: ${req.originalUrl}`
369
+ })
370
+ })
371
+ ]
372
+ });
373
+ }
374
+
375
+ // src/core/pages/DevErrorPage.tsx
376
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
377
+ function DevErrorPage(props) {
378
+ var _a;
379
+ const req = props.req;
380
+ const err = props.error;
381
+ const route = props.route;
382
+ const routeParams = props.routeParams;
383
+ let errMsg = String(err);
384
+ if (err && err.stack) {
385
+ errMsg = err.stack.replace(/\(.*node_modules/g, "(node_modules").replace(/at \/.*node_modules/g, "at node_modules");
386
+ if ((_a = req.rootConfig) == null ? void 0 : _a.rootDir) {
387
+ errMsg = errMsg.replaceAll(req.rootConfig.rootDir, "<root>");
388
+ }
389
+ if (process.env.HOME) {
390
+ errMsg = errMsg.replaceAll(process.env.HOME, "$HOME");
391
+ }
392
+ }
393
+ return /* @__PURE__ */ jsxs3(ErrorPage, {
394
+ code: 500,
395
+ title: "Root.js",
396
+ children: [
397
+ errMsg && /* @__PURE__ */ jsxs3(Fragment2, {
398
+ children: [
399
+ /* @__PURE__ */ jsx3("h2", {
400
+ children: "Error"
401
+ }),
402
+ /* @__PURE__ */ jsx3("pre", {
403
+ className: "box",
404
+ children: /* @__PURE__ */ jsx3("code", {
405
+ children: errMsg
406
+ })
407
+ })
408
+ ]
409
+ }),
410
+ /* @__PURE__ */ jsx3("h2", {
411
+ children: "Debug Info"
412
+ }),
413
+ /* @__PURE__ */ jsx3("pre", {
414
+ className: "box",
415
+ children: /* @__PURE__ */ jsx3("code", {
416
+ children: `url: ${req.originalUrl}
417
+ route: ${(route == null ? void 0 : route.src) || "null"}
418
+ routeParams: ${routeParams && JSON.stringify(routeParams) || "null"}`
419
+ })
306
420
  })
307
421
  ]
308
422
  });
309
423
  }
310
424
 
311
425
  // src/render/render.tsx
312
- import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
426
+ import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
313
427
  var Renderer = class {
314
- constructor(config) {
315
- this.routes = getRoutes(config);
428
+ constructor(rootConfig, options) {
429
+ this.rootConfig = rootConfig;
430
+ this.routes = getRoutes(this.rootConfig);
431
+ this.assetMap = options.assetMap;
432
+ this.elementGraph = options.elementGraph;
316
433
  }
317
- async render(url, options) {
318
- const assetMap = options.assetMap;
434
+ async handle(req, res, next) {
435
+ const url = req.path;
319
436
  const [route, routeParams] = this.routes.get(url);
320
- if (route && route.module && route.module.default) {
321
- return await this.renderRoute(route, { routeParams, assetMap });
437
+ if (!route) {
438
+ next();
439
+ return;
322
440
  }
323
- return { notFound: true };
324
- }
325
- async renderRoute(route, options) {
326
- const routeParams = options.routeParams;
327
- const assetMap = options.assetMap;
328
- const Component = route.module.default;
329
- if (!Component) {
330
- throw new Error(
331
- "unable to render route. the route should have a default export that renders a jsx component."
332
- );
441
+ const render404 = async () => {
442
+ next();
443
+ };
444
+ const render = async (props2) => {
445
+ if (!route.module.default) {
446
+ console.error(`no default component exported in route: ${route.src}`);
447
+ render404();
448
+ return;
449
+ }
450
+ const output = await this.renderComponent(route.module.default, props2, {
451
+ route,
452
+ routeParams
453
+ });
454
+ let html = output.html;
455
+ if (this.rootConfig.prettyHtml) {
456
+ html = await htmlPretty(html, this.rootConfig.prettyHtmlOptions);
457
+ } else if (this.rootConfig.minifyHtml !== false) {
458
+ html = await htmlMinify(html, this.rootConfig.minifyHtmlOptions);
459
+ }
460
+ if (req.viteServer) {
461
+ html = await req.viteServer.transformIndexHtml(req.originalUrl, html);
462
+ }
463
+ let statusCode = 200;
464
+ if (route.src === "routes/404.tsx") {
465
+ statusCode = 404;
466
+ } else if (route.src === "routes/500.tsx") {
467
+ statusCode = 500;
468
+ }
469
+ res.status(statusCode).set({ "Content-Type": "text/html" }).end(html);
470
+ };
471
+ if (route.module.handle) {
472
+ const handlerContext = {
473
+ route,
474
+ params: routeParams,
475
+ render,
476
+ render404
477
+ };
478
+ req.handlerContext = handlerContext;
479
+ return route.module.handle(req, res, next);
333
480
  }
334
481
  let props = {};
335
482
  if (route.module.getStaticProps) {
336
483
  const propsData = await route.module.getStaticProps({
484
+ rootConfig: this.rootConfig,
337
485
  params: routeParams
338
486
  });
339
487
  if (propsData.notFound) {
340
- return this.render404();
488
+ return render404();
341
489
  }
342
490
  if (propsData.props) {
343
491
  props = propsData.props;
344
492
  }
345
493
  }
494
+ await render(props);
495
+ }
496
+ async renderComponent(Component, props, options) {
497
+ const { route, routeParams } = options;
346
498
  const locale = route.locale;
347
499
  const translations = getTranslations(locale);
348
- const headComponents = [];
349
- const userScripts = [];
350
- const vdom = /* @__PURE__ */ jsx2(I18N_CONTEXT.Provider, {
351
- value: { locale, translations },
352
- children: /* @__PURE__ */ jsx2(SCRIPT_CONTEXT.Provider, {
353
- value: userScripts,
354
- children: /* @__PURE__ */ jsx2(HEAD_CONTEXT.Provider, {
355
- value: headComponents,
356
- children: /* @__PURE__ */ jsx2(Component, {
500
+ const ctx = {
501
+ route,
502
+ props,
503
+ routeParams,
504
+ locale,
505
+ translations
506
+ };
507
+ const htmlContext = {
508
+ htmlAttrs: {},
509
+ headAttrs: {},
510
+ headComponents: [],
511
+ bodyAttrs: {},
512
+ scriptDeps: []
513
+ };
514
+ const vdom = /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, {
515
+ value: ctx,
516
+ children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, {
517
+ value: { locale, translations },
518
+ children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, {
519
+ value: htmlContext,
520
+ children: /* @__PURE__ */ jsx4(Component, {
357
521
  ...props
358
522
  })
359
523
  })
360
524
  })
361
525
  });
362
- const mainHtml = renderToString(vdom, {}, { pretty: true });
363
- const pageAsset = await assetMap.get(route.modulePath);
364
- const cssDeps = await (pageAsset == null ? void 0 : pageAsset.getCssDeps());
365
- if (cssDeps) {
366
- cssDeps.forEach((cssUrl) => {
367
- headComponents.push(/* @__PURE__ */ jsx2("link", {
368
- rel: "stylesheet",
369
- href: cssUrl
370
- }));
371
- });
526
+ const mainHtml = renderToString(vdom);
527
+ const jsDeps = /* @__PURE__ */ new Set();
528
+ const cssDeps = /* @__PURE__ */ new Set();
529
+ const routeAsset = await this.assetMap.get(route.src);
530
+ if (routeAsset) {
531
+ const routeCssDeps = await routeAsset.getCssDeps();
532
+ routeCssDeps.forEach((dep) => cssDeps.add(dep));
372
533
  }
373
- const scriptDeps = await this.getScriptDeps(mainHtml, { assetMap });
374
- scriptDeps.forEach((jsUrls) => {
375
- headComponents.push(/* @__PURE__ */ jsx2("script", {
376
- type: "module",
377
- src: jsUrls
378
- }));
379
- });
534
+ await this.collectElementDeps(mainHtml, jsDeps, cssDeps);
380
535
  await Promise.all(
381
- userScripts.map(async (scriptDep) => {
382
- const scriptAsset = await assetMap.get(scriptDep.src);
536
+ htmlContext.scriptDeps.map(async (scriptDep) => {
537
+ if (!scriptDep.src) {
538
+ return;
539
+ }
540
+ const scriptAsset = await this.assetMap.get(scriptDep.src.slice(1));
383
541
  if (scriptAsset) {
384
- const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;
385
- headComponents.push(/* @__PURE__ */ jsx2("script", {
386
- type: "module",
387
- src: scriptUrl
388
- }));
542
+ jsDeps.add(scriptAsset.assetUrl);
543
+ const scriptJsDeps = await scriptAsset.getJsDeps();
544
+ scriptJsDeps.forEach((dep) => jsDeps.add(dep));
389
545
  }
390
546
  })
391
547
  );
392
- const html = await this.renderHtml({ mainHtml, locale, headComponents });
548
+ const styleTags = Array.from(cssDeps).map((cssUrl) => {
549
+ return /* @__PURE__ */ jsx4("link", {
550
+ rel: "stylesheet",
551
+ href: cssUrl
552
+ });
553
+ });
554
+ const scriptTags = Array.from(jsDeps).map((jsUrls) => {
555
+ return /* @__PURE__ */ jsx4("script", {
556
+ type: "module",
557
+ src: jsUrls
558
+ });
559
+ });
560
+ const html = await this.renderHtml(mainHtml, {
561
+ htmlAttrs: htmlContext.htmlAttrs,
562
+ headAttrs: htmlContext.headAttrs,
563
+ bodyAttrs: htmlContext.bodyAttrs,
564
+ headComponents: [
565
+ ...htmlContext.headComponents,
566
+ ...styleTags,
567
+ ...scriptTags
568
+ ]
569
+ });
393
570
  return { html };
394
571
  }
572
+ async renderRoute(route, options) {
573
+ const routeParams = options.routeParams;
574
+ const Component = route.module.default;
575
+ if (!Component) {
576
+ throw new Error(
577
+ "unable to render route. the route should have a default export that renders a jsx component."
578
+ );
579
+ }
580
+ let props = {};
581
+ if (route.module.getStaticProps) {
582
+ const propsData = await route.module.getStaticProps({
583
+ rootConfig: this.rootConfig,
584
+ params: routeParams
585
+ });
586
+ if (propsData.notFound) {
587
+ return { notFound: true };
588
+ }
589
+ if (propsData.props) {
590
+ props = propsData.props;
591
+ }
592
+ }
593
+ return this.renderComponent(Component, props, { route, routeParams });
594
+ }
395
595
  async getSitemap() {
396
596
  const sitemap = {};
397
597
  await this.routes.walk(async (urlPath, route) => {
@@ -405,86 +605,131 @@ var Renderer = class {
405
605
  });
406
606
  return sitemap;
407
607
  }
408
- async renderHtml(options) {
409
- const page = /* @__PURE__ */ jsxs2("html", {
410
- lang: options.locale,
608
+ async renderHtml(html, options) {
609
+ const htmlAttrs = (options == null ? void 0 : options.htmlAttrs) || {};
610
+ const headAttrs = (options == null ? void 0 : options.headAttrs) || {};
611
+ const bodyAttrs = (options == null ? void 0 : options.bodyAttrs) || {};
612
+ const page = /* @__PURE__ */ jsxs4("html", {
613
+ ...htmlAttrs,
411
614
  children: [
412
- /* @__PURE__ */ jsxs2("head", {
615
+ /* @__PURE__ */ jsxs4("head", {
616
+ ...headAttrs,
413
617
  children: [
414
- /* @__PURE__ */ jsx2("meta", {
618
+ /* @__PURE__ */ jsx4("meta", {
415
619
  charSet: "utf-8"
416
620
  }),
417
- options.headComponents
621
+ options == null ? void 0 : options.headComponents
418
622
  ]
419
623
  }),
420
- /* @__PURE__ */ jsx2("body", {
421
- dangerouslySetInnerHTML: { __html: options.mainHtml }
624
+ /* @__PURE__ */ jsx4("body", {
625
+ ...bodyAttrs,
626
+ dangerouslySetInnerHTML: { __html: html }
422
627
  })
423
628
  ]
424
629
  });
425
- const html = `<!doctype html>
426
- ${renderToString(
427
- page,
428
- {},
429
- { pretty: true }
430
- )}
630
+ return `<!doctype html>
631
+ ${renderToString(page)}
431
632
  `;
432
- return html;
433
633
  }
434
634
  async render404() {
435
- return {
436
- html: "<!doctype html><html><title>404 Not Found</title><h1>404 Not Found</h1>",
437
- notFound: true
438
- };
439
- }
440
- async renderError(error) {
441
- const mainHtml = renderToString(/* @__PURE__ */ jsx2(ErrorPage, {
442
- error
635
+ const [route, routeParams] = this.routes.get("/404");
636
+ if (route && route.src === "routes/404.tsx" && route.module.default) {
637
+ const Component = route.module.default;
638
+ return this.renderComponent(Component, {}, { route, routeParams });
639
+ }
640
+ const mainHtml = renderToString(/* @__PURE__ */ jsx4(ErrorPage, {
641
+ code: 404,
642
+ title: "Not Found"
443
643
  }));
444
- const html = await this.renderHtml({ mainHtml, locale: "en" });
644
+ const html = await this.renderHtml(mainHtml, {
645
+ headComponents: [/* @__PURE__ */ jsx4("title", {
646
+ children: "404"
647
+ })]
648
+ });
445
649
  return { html };
446
650
  }
447
- async renderDevNotFound() {
448
- const routes = await this.getAllRoutes();
449
- const mainHtml = renderToString(/* @__PURE__ */ jsx2(DevNotFoundPage, {
450
- routes
451
- }));
452
- const html = await this.renderHtml({
453
- mainHtml,
454
- locale: "en",
455
- headComponents: [/* @__PURE__ */ jsx2("title", {
456
- children: "404: Not Found"
651
+ async renderError(err) {
652
+ const [route, routeParams] = this.routes.get("/500");
653
+ if (route && route.src === "routes/500.tsx" && route.module.default) {
654
+ const Component = route.module.default;
655
+ return this.renderComponent(
656
+ Component,
657
+ { error: err },
658
+ { route, routeParams }
659
+ );
660
+ }
661
+ const mainHtml = renderToString(
662
+ /* @__PURE__ */ jsx4(ErrorPage, {
663
+ code: 500,
664
+ title: "Error",
665
+ message: "An unknown error occurred."
666
+ })
667
+ );
668
+ const html = await this.renderHtml(mainHtml, {
669
+ headComponents: [/* @__PURE__ */ jsx4("title", {
670
+ children: "500"
457
671
  })]
458
672
  });
459
673
  return { html };
460
674
  }
461
- async getAllRoutes() {
462
- const routes = {};
463
- await this.routes.walk((urlPath, route) => {
464
- routes[urlPath] = route;
675
+ async renderDevServer404(req) {
676
+ const sitemap = await this.getSitemap();
677
+ const mainHtml = renderToString(
678
+ /* @__PURE__ */ jsx4(DevNotFoundPage, {
679
+ req,
680
+ sitemap
681
+ })
682
+ );
683
+ const html = await this.renderHtml(mainHtml, {
684
+ headComponents: [/* @__PURE__ */ jsx4("title", {
685
+ children: "404 | Root.js"
686
+ })]
465
687
  });
466
- return routes;
688
+ return { html };
467
689
  }
468
- async getScriptDeps(html, options) {
469
- const assetMap = options.assetMap;
470
- const deps = /* @__PURE__ */ new Set();
471
- const re = /<(\w[\w-]+\w)/g;
472
- const matches = Array.from(html.matchAll(re));
690
+ async renderDevServer500(req, error) {
691
+ const [route, routeParams] = this.routes.get(req.path);
692
+ const mainHtml = renderToString(
693
+ /* @__PURE__ */ jsx4(DevErrorPage, {
694
+ req,
695
+ route,
696
+ routeParams,
697
+ error
698
+ })
699
+ );
700
+ const html = await this.renderHtml(mainHtml, {
701
+ headComponents: [/* @__PURE__ */ jsx4("title", {
702
+ children: "500 | Root.js"
703
+ })]
704
+ });
705
+ return { html };
706
+ }
707
+ async collectElementDeps(html, jsDeps, cssDeps) {
708
+ const elementsMap = this.elementGraph.sourceFiles;
709
+ const assetMap = this.assetMap;
710
+ const tagNames = /* @__PURE__ */ new Set();
711
+ for (const tagName of parseTagNames(html)) {
712
+ if (tagName && tagName in elementsMap) {
713
+ tagNames.add(tagName);
714
+ for (const depTagName of this.elementGraph.getDeps(tagName)) {
715
+ tagNames.add(depTagName);
716
+ }
717
+ }
718
+ }
473
719
  await Promise.all(
474
- matches.map(async (match) => {
475
- const tagName = match[1];
476
- if (tagName && tagName.includes("-") && tagName in elementsMap) {
477
- const modulePath = elementsMap[tagName];
478
- const asset = await assetMap.get(modulePath);
479
- if (!asset) {
480
- return;
481
- }
482
- const assetJsDeps = await asset.getJsDeps();
483
- assetJsDeps.forEach((dep) => deps.add(dep));
720
+ Array.from(tagNames).map(async (tagName) => {
721
+ const elementModule = elementsMap[tagName];
722
+ const asset = await assetMap.get(elementModule.relPath);
723
+ if (!asset) {
724
+ return;
484
725
  }
726
+ const assetJsDeps = await asset.getJsDeps();
727
+ assetJsDeps.forEach((dep) => jsDeps.add(dep));
728
+ const assetCssDeps = await asset.getCssDeps();
729
+ assetCssDeps.forEach((dep) => cssDeps.add(dep));
485
730
  })
486
731
  );
487
- return Array.from(deps);
732
+ return { jsDeps, cssDeps };
488
733
  }
489
734
  };
490
735
  export {