@chidchanun/bcp 0.1.7 → 0.1.9

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.
@@ -20,6 +20,10 @@ import type {
20
20
  ProductionRouteAsset,
21
21
  } from "../../bundler/src/production.js";
22
22
 
23
+ import {
24
+ BcpLoaderDataProvider,
25
+ } from "../../client/src/loader-data.js";
26
+
23
27
  import {
24
28
  createMetadataHeadEntries,
25
29
  type ResolvedMetadata,
@@ -49,6 +53,13 @@ import {
49
53
  type MetadataSource,
50
54
  } from "./metadata.js";
51
55
 
56
+ import {
57
+ attachLoaderDataToParams,
58
+ executePageLoaderFunction,
59
+ type PageLoader,
60
+ type PageLoaderExecution,
61
+ } from "./page-loader.js";
62
+
52
63
  import {
53
64
  applyResponseCookies,
54
65
  runWithRequestContext,
@@ -69,6 +80,7 @@ export interface StandalonePageRoute {
69
80
  error: ComponentType<any> | null;
70
81
  notFound: ComponentType<any> | null;
71
82
  metadataSources: MetadataSource[];
83
+ loader: PageLoader | null;
72
84
  client: ProductionRouteAsset;
73
85
  }
74
86
 
@@ -345,6 +357,7 @@ export function createStandaloneProductionServer(
345
357
  await sendPage(
346
358
  req,
347
359
  res,
360
+ requestUrl,
348
361
  definition,
349
362
  match.params,
350
363
  options
@@ -453,29 +466,99 @@ export function createStandaloneProductionServer(
453
466
  async function sendPage(
454
467
  req: http.IncomingMessage,
455
468
  res: http.ServerResponse,
469
+ requestUrl: URL,
456
470
  definition: StandalonePageRoute,
457
471
  params: Record<string, string>,
458
472
  options: StandaloneProductionServerOptions
459
473
  ): Promise<void> {
460
474
  try {
461
- const metadata =
462
- await resolveRouteMetadata(
463
- definition.metadataSources,
464
- params
475
+ const request =
476
+ await createWebRequest(
477
+ req,
478
+ requestUrl
465
479
  );
466
480
 
467
- const html =
468
- renderPageDocument(
469
- definition,
470
- params,
471
- metadata
481
+ const response =
482
+ await runWithRequestContext(
483
+ request,
484
+ async () => {
485
+ const loaderExecution:
486
+ PageLoaderExecution =
487
+ definition.loader
488
+ ? await executePageLoaderFunction(
489
+ definition.loader,
490
+ params,
491
+ requestUrl,
492
+ definition.pathname
493
+ )
494
+ : {
495
+ hasLoader:
496
+ false,
497
+ data:
498
+ undefined,
499
+ response:
500
+ null,
501
+ };
502
+
503
+ if (
504
+ loaderExecution.response
505
+ ) {
506
+ return applyResponseCookies(
507
+ loaderExecution.response
508
+ );
509
+ }
510
+
511
+ const metadata =
512
+ await resolveRouteMetadata(
513
+ definition.metadataSources,
514
+ params
515
+ );
516
+
517
+ const frameworkParams =
518
+ attachLoaderDataToParams(
519
+ params,
520
+ loaderExecution
521
+ );
522
+
523
+ const html =
524
+ renderPageDocument(
525
+ definition,
526
+ frameworkParams,
527
+ metadata,
528
+ loaderExecution
529
+ );
530
+
531
+ return applyResponseCookies(
532
+ new Response(
533
+ html,
534
+ {
535
+ status:
536
+ 200,
537
+ headers: {
538
+ "Content-Type":
539
+ "text/html; charset=utf-8",
540
+ "Cache-Control":
541
+ "no-store",
542
+ },
543
+ }
544
+ )
545
+ );
546
+ },
547
+ {
548
+ remoteAddress:
549
+ req.socket
550
+ .remoteAddress ??
551
+ null,
552
+ }
472
553
  );
473
554
 
474
- sendHtml(
555
+ await sendWebResponse(
475
556
  req,
476
557
  res,
477
- 200,
478
- html
558
+ response,
559
+ normalizeHttpMethod(
560
+ req.method
561
+ ) === "HEAD"
479
562
  );
480
563
  } catch (error) {
481
564
  if (isNotFoundError(error)) {
@@ -561,10 +644,11 @@ function sendGlobalNotFound(
561
644
 
562
645
  function renderPageDocument(
563
646
  definition: StandalonePageRoute,
564
- params: Record<string, string>,
565
- metadata: ResolvedMetadata
647
+ params: Record<string, any>,
648
+ metadata: ResolvedMetadata,
649
+ loaderExecution: PageLoaderExecution
566
650
  ): string {
567
- const element =
651
+ let element =
568
652
  wrapWithLayouts(
569
653
  createElement(
570
654
  definition.page,
@@ -576,6 +660,20 @@ function renderPageDocument(
576
660
  params
577
661
  );
578
662
 
663
+ if (
664
+ loaderExecution.hasLoader
665
+ ) {
666
+ element =
667
+ createElement(
668
+ BcpLoaderDataProvider,
669
+ {
670
+ data:
671
+ loaderExecution.data,
672
+ },
673
+ element
674
+ );
675
+ }
676
+
579
677
  const content =
580
678
  renderToString(
581
679
  element
@@ -595,7 +693,7 @@ function renderPageDocument(
595
693
  function renderFallbackDocument(
596
694
  Component: ComponentType<any> | null,
597
695
  layouts: ComponentType<any>[],
598
- params: Record<string, string>,
696
+ params: Record<string, any>,
599
697
  fallback:
600
698
  | {
601
699
  kind: "not-found";
@@ -700,7 +798,7 @@ function renderFallbackDocument(
700
798
  function wrapWithLayouts(
701
799
  child: ReactElement,
702
800
  layouts: ComponentType<any>[],
703
- params: Record<string, string>
801
+ params: Record<string, any>
704
802
  ): ReactElement {
705
803
  let element =
706
804
  child;
@@ -728,7 +826,7 @@ function renderDocument(
728
826
  input: {
729
827
  content: string;
730
828
  route: string | null;
731
- params: Record<string, string> | null;
829
+ params: Record<string, any> | null;
732
830
  client: ProductionRouteAsset | null;
733
831
  metadata: ResolvedMetadata;
734
832
  }
@@ -1029,6 +1127,19 @@ async function handleNavigation(
1029
1127
  return;
1030
1128
  }
1031
1129
 
1130
+ if (definition.loader) {
1131
+ sendJson(
1132
+ req,
1133
+ res,
1134
+ 409,
1135
+ {
1136
+ error:
1137
+ "Loader routes require document navigation.",
1138
+ }
1139
+ );
1140
+ return;
1141
+ }
1142
+
1032
1143
  let metadata:
1033
1144
  ResolvedMetadata;
1034
1145
 
@@ -1699,7 +1810,8 @@ async function sendWebResponse(
1699
1810
 
1700
1811
  if (
1701
1812
  cookies &&
1702
- cookies.length > 0
1813
+ cookies.length >
1814
+ 0
1703
1815
  ) {
1704
1816
  res.setHeader(
1705
1817
  "Set-Cookie",
@@ -18,7 +18,7 @@ import {
18
18
  type StandaloneApiRoute,
19
19
  type StandalonePageRoute,
20
20
  type StandaloneProductionServerOptions as BaseStandaloneProductionServerOptions,
21
- } from "./standalone-production-runtime-v2.js";
21
+ } from "./standalone-production-runtime-v2-navigation.js";
22
22
 
23
23
  import type {
24
24
  MiddlewareModule,
@@ -46,8 +46,11 @@ export function createStandaloneProductionServer(
46
46
  }
47
47
 
48
48
  const manifest =
49
- readCacheManifest(
50
- options.buildDirectory
49
+ excludeLoaderPagesFromCache(
50
+ readCacheManifest(
51
+ options.buildDirectory
52
+ ),
53
+ options.routes
51
54
  );
52
55
 
53
56
  const responseCacheEnabled =
@@ -156,6 +159,43 @@ export function createStandaloneProductionServer(
156
159
  };
157
160
  }
158
161
 
162
+ function excludeLoaderPagesFromCache(
163
+ manifest: ResponseCacheManifest,
164
+ routes: StandalonePageRoute[]
165
+ ): ResponseCacheManifest {
166
+ const loaderRoutes =
167
+ new Set(
168
+ routes
169
+ .filter(
170
+ (route) =>
171
+ route.loader !==
172
+ null
173
+ )
174
+ .map(
175
+ (route) =>
176
+ route.pathname
177
+ )
178
+ );
179
+
180
+ if (
181
+ loaderRoutes.size ===
182
+ 0
183
+ ) {
184
+ return manifest;
185
+ }
186
+
187
+ return {
188
+ ...manifest,
189
+ pages:
190
+ manifest.pages.filter(
191
+ (route) =>
192
+ !loaderRoutes.has(
193
+ route.pathname
194
+ )
195
+ ),
196
+ };
197
+ }
198
+
159
199
  function readCacheManifest(
160
200
  buildDirectory: string
161
201
  ): ResponseCacheManifest {
@@ -11,12 +11,19 @@ import {
11
11
  applyDevDocumentMetadata,
12
12
  } from "./dev-document-metadata.js";
13
13
 
14
+ import {
15
+ createDevNavigationTargetResponse,
16
+ } from "./dev-navigation-target.js";
17
+
14
18
  import {
15
19
  resolveNavigationPayload,
16
20
  sendNavigationError,
17
- sendNavigationPayload,
18
21
  } from "./navigation-payload.js";
19
22
 
23
+ import {
24
+ sendNavigationWebResponse,
25
+ } from "./navigation-response.js";
26
+
20
27
  import {
21
28
  readPublicAsset,
22
29
  type StaticAsset,
@@ -405,7 +412,11 @@ async function sendHtmlWithMetadata(
405
412
  const payload =
406
413
  await resolveNavigationPayload(
407
414
  rootDirectory,
408
- pathname
415
+ pathname,
416
+ {
417
+ allowLoaderRoute:
418
+ true,
419
+ }
409
420
  );
410
421
 
411
422
  const html =
@@ -595,34 +606,27 @@ async function handleNavigationRequest(
595
606
  return;
596
607
  }
597
608
 
598
- const payload =
599
- await resolveNavigationPayload(
609
+ const response =
610
+ await createDevNavigationTargetResponse(
611
+ req,
600
612
  rootDirectory,
601
- target.pathname
613
+ target
602
614
  );
603
615
 
604
- if (!payload) {
616
+ if (!response) {
605
617
  sendNavigationError(
606
618
  res,
607
619
  404,
608
620
  "Route not found."
609
621
  );
610
-
611
- logRequest(
622
+ } else {
623
+ await sendNavigationWebResponse(
612
624
  req,
613
- requestUrl.pathname,
614
625
  res,
615
- startedAt
626
+ response
616
627
  );
617
-
618
- return;
619
628
  }
620
629
 
621
- sendNavigationPayload(
622
- res,
623
- payload
624
- );
625
-
626
630
  logRequest(
627
631
  req,
628
632
  requestUrl.pathname,