@chidchanun/bcp 0.1.8 → 0.1.10
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/CHANGELOG.md +82 -0
- package/README.md +218 -7
- package/docs/application-modules.md +63 -3
- package/docs/releasing.md +34 -19
- package/docs/route-guards.md +240 -0
- package/docs/server-data-loaders.md +240 -0
- package/docs/updating.md +130 -0
- package/package.json +1 -1
- package/packages/bundler/src/server-production-guards.ts +497 -0
- package/packages/bundler/src/server-production-middleware.ts +33 -8
- package/packages/bundler/src/server-production.ts +25 -0
- package/packages/cli/src/args.ts +58 -0
- package/packages/cli/src/index.ts +41 -13
- package/packages/cli/src/update.ts +860 -0
- package/packages/client/src/index.tsx +5 -0
- package/packages/client/src/loader-data.tsx +229 -0
- package/packages/client/src/router-v2.tsx +254 -29
- package/packages/server/src/dev-navigation-target.ts +188 -0
- package/packages/server/src/index.ts +209 -119
- package/packages/server/src/navigation-payload.ts +24 -1
- package/packages/server/src/navigation-response.ts +284 -0
- package/packages/server/src/page-guard.ts +529 -0
- package/packages/server/src/page-loader.ts +643 -0
- package/packages/server/src/standalone-production-runtime-v2-guard.ts +815 -0
- package/packages/server/src/standalone-production-runtime-v2-navigation.ts +785 -0
- package/packages/server/src/standalone-production-runtime-v2.ts +131 -19
- package/packages/server/src/standalone-production-runtime-v3.ts +1 -1
- package/packages/server/src/standalone-production-runtime-v4.ts +42 -2
- package/packages/server/src/static-dev-server.ts +21 -17
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
fileURLToPath,
|
|
5
|
+
} from "node:url";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
build,
|
|
9
|
+
} from "esbuild";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
createServerEnvironmentDefines,
|
|
13
|
+
} from "../../env/src/index.js";
|
|
14
|
+
|
|
15
|
+
import type {
|
|
16
|
+
Route,
|
|
17
|
+
} from "../../router/src/index.js";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
findPageGuardFiles,
|
|
21
|
+
} from "../../server/src/page-guard.js";
|
|
22
|
+
|
|
23
|
+
export async function buildProductionGuards(
|
|
24
|
+
pageRoutes: Route[],
|
|
25
|
+
rootDirectory: string,
|
|
26
|
+
serverDirectory: string
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
const outputFile =
|
|
29
|
+
path.join(
|
|
30
|
+
serverDirectory,
|
|
31
|
+
"guards.mjs"
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
fs.rmSync(
|
|
35
|
+
outputFile,
|
|
36
|
+
{
|
|
37
|
+
force: true,
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const appDirectory =
|
|
42
|
+
path.join(
|
|
43
|
+
rootDirectory,
|
|
44
|
+
"app"
|
|
45
|
+
);
|
|
46
|
+
const guardedRoutes =
|
|
47
|
+
pageRoutes
|
|
48
|
+
.map(
|
|
49
|
+
(route) => ({
|
|
50
|
+
route,
|
|
51
|
+
guardFiles:
|
|
52
|
+
findPageGuardFiles(
|
|
53
|
+
appDirectory,
|
|
54
|
+
route.filePath
|
|
55
|
+
),
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.filter(
|
|
59
|
+
(entry) =>
|
|
60
|
+
entry.guardFiles.length > 0
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
guardedRoutes.length ===
|
|
65
|
+
0
|
|
66
|
+
) {
|
|
67
|
+
console.log(
|
|
68
|
+
"[BCP Build] Guards: none"
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const entryDirectory =
|
|
74
|
+
path.join(
|
|
75
|
+
rootDirectory,
|
|
76
|
+
".bcp-framework",
|
|
77
|
+
"build",
|
|
78
|
+
".guard-entry"
|
|
79
|
+
);
|
|
80
|
+
const entryFile =
|
|
81
|
+
path.join(
|
|
82
|
+
entryDirectory,
|
|
83
|
+
"guards-entry.mjs"
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
fs.rmSync(
|
|
87
|
+
entryDirectory,
|
|
88
|
+
{
|
|
89
|
+
recursive: true,
|
|
90
|
+
force: true,
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
fs.mkdirSync(
|
|
94
|
+
entryDirectory,
|
|
95
|
+
{
|
|
96
|
+
recursive: true,
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
fs.writeFileSync(
|
|
101
|
+
entryFile,
|
|
102
|
+
createGuardEntry(
|
|
103
|
+
guardedRoutes,
|
|
104
|
+
rootDirectory,
|
|
105
|
+
entryDirectory
|
|
106
|
+
),
|
|
107
|
+
"utf8"
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const frameworkDirectory =
|
|
111
|
+
path.dirname(
|
|
112
|
+
fileURLToPath(
|
|
113
|
+
import.meta.url
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
const frameworkServerEntry =
|
|
117
|
+
path.resolve(
|
|
118
|
+
frameworkDirectory,
|
|
119
|
+
"../../client/src/server.ts"
|
|
120
|
+
);
|
|
121
|
+
const frameworkServerOnlyEntry =
|
|
122
|
+
path.resolve(
|
|
123
|
+
frameworkDirectory,
|
|
124
|
+
"../../client/src/server-only.mjs"
|
|
125
|
+
);
|
|
126
|
+
const frameworkCacheEntry =
|
|
127
|
+
path.resolve(
|
|
128
|
+
frameworkDirectory,
|
|
129
|
+
"../../cache/src/index.ts"
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await build({
|
|
134
|
+
absWorkingDir:
|
|
135
|
+
rootDirectory,
|
|
136
|
+
entryPoints: [
|
|
137
|
+
entryFile,
|
|
138
|
+
],
|
|
139
|
+
outfile:
|
|
140
|
+
outputFile,
|
|
141
|
+
bundle:
|
|
142
|
+
true,
|
|
143
|
+
platform:
|
|
144
|
+
"node",
|
|
145
|
+
format:
|
|
146
|
+
"esm",
|
|
147
|
+
target: [
|
|
148
|
+
"node24",
|
|
149
|
+
],
|
|
150
|
+
minify:
|
|
151
|
+
process.env
|
|
152
|
+
.BCP_BUILD_MINIFY !==
|
|
153
|
+
"0",
|
|
154
|
+
sourcemap:
|
|
155
|
+
process.env
|
|
156
|
+
.BCP_BUILD_SOURCE_MAPS ===
|
|
157
|
+
"1",
|
|
158
|
+
treeShaking:
|
|
159
|
+
true,
|
|
160
|
+
packages:
|
|
161
|
+
"external",
|
|
162
|
+
plugins: [
|
|
163
|
+
{
|
|
164
|
+
name:
|
|
165
|
+
"bcp-guard-runtime",
|
|
166
|
+
setup(buildApi) {
|
|
167
|
+
buildApi.onResolve(
|
|
168
|
+
{
|
|
169
|
+
filter:
|
|
170
|
+
/^bcp\/server$/,
|
|
171
|
+
},
|
|
172
|
+
() => ({
|
|
173
|
+
path:
|
|
174
|
+
frameworkServerEntry,
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
buildApi.onResolve(
|
|
178
|
+
{
|
|
179
|
+
filter:
|
|
180
|
+
/^bcp\/server-only$/,
|
|
181
|
+
},
|
|
182
|
+
() => ({
|
|
183
|
+
path:
|
|
184
|
+
frameworkServerOnlyEntry,
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
buildApi.onResolve(
|
|
188
|
+
{
|
|
189
|
+
filter:
|
|
190
|
+
/^bcp\/cache$/,
|
|
191
|
+
},
|
|
192
|
+
() => ({
|
|
193
|
+
path:
|
|
194
|
+
frameworkCacheEntry,
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
define:
|
|
201
|
+
createServerEnvironmentDefines(
|
|
202
|
+
"production"
|
|
203
|
+
),
|
|
204
|
+
legalComments:
|
|
205
|
+
"none",
|
|
206
|
+
logLevel:
|
|
207
|
+
"silent",
|
|
208
|
+
});
|
|
209
|
+
} finally {
|
|
210
|
+
fs.rmSync(
|
|
211
|
+
entryDirectory,
|
|
212
|
+
{
|
|
213
|
+
recursive: true,
|
|
214
|
+
force: true,
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log(
|
|
220
|
+
`[BCP Build] Guards: ${guardedRoutes.length} protected route(s) -> ${path.relative(rootDirectory, outputFile).replace(/\\/g, "/")}`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createGuardEntry(
|
|
225
|
+
guardedRoutes: Array<{
|
|
226
|
+
route: Route;
|
|
227
|
+
guardFiles: string[];
|
|
228
|
+
}>,
|
|
229
|
+
rootDirectory: string,
|
|
230
|
+
entryDirectory: string
|
|
231
|
+
): string {
|
|
232
|
+
const frameworkDirectory =
|
|
233
|
+
path.dirname(
|
|
234
|
+
fileURLToPath(
|
|
235
|
+
import.meta.url
|
|
236
|
+
)
|
|
237
|
+
);
|
|
238
|
+
const pageGuardRuntime =
|
|
239
|
+
path.resolve(
|
|
240
|
+
frameworkDirectory,
|
|
241
|
+
"../../server/src/page-guard.ts"
|
|
242
|
+
);
|
|
243
|
+
const requestContextRuntime =
|
|
244
|
+
path.resolve(
|
|
245
|
+
frameworkDirectory,
|
|
246
|
+
"../../server/src/request-context.ts"
|
|
247
|
+
);
|
|
248
|
+
const routerRuntime =
|
|
249
|
+
path.resolve(
|
|
250
|
+
frameworkDirectory,
|
|
251
|
+
"../../router/src/index.ts"
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const imports: string[] = [
|
|
255
|
+
`import { executePageGuardFunctions } from ${JSON.stringify(
|
|
256
|
+
toImportSpecifier(
|
|
257
|
+
entryDirectory,
|
|
258
|
+
pageGuardRuntime
|
|
259
|
+
)
|
|
260
|
+
)};`,
|
|
261
|
+
`import { applyResponseCookies, runWithRequestContext } from ${JSON.stringify(
|
|
262
|
+
toImportSpecifier(
|
|
263
|
+
entryDirectory,
|
|
264
|
+
requestContextRuntime
|
|
265
|
+
)
|
|
266
|
+
)};`,
|
|
267
|
+
`import { matchRoute } from ${JSON.stringify(
|
|
268
|
+
toImportSpecifier(
|
|
269
|
+
entryDirectory,
|
|
270
|
+
routerRuntime
|
|
271
|
+
)
|
|
272
|
+
)};`,
|
|
273
|
+
];
|
|
274
|
+
const guardNameByFile =
|
|
275
|
+
new Map<string, string>();
|
|
276
|
+
let guardIndex =
|
|
277
|
+
0;
|
|
278
|
+
|
|
279
|
+
for (const entry of guardedRoutes) {
|
|
280
|
+
for (const guardFile of entry.guardFiles) {
|
|
281
|
+
if (
|
|
282
|
+
guardNameByFile.has(
|
|
283
|
+
guardFile
|
|
284
|
+
)
|
|
285
|
+
) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const guardName =
|
|
290
|
+
`Guard${guardIndex++}`;
|
|
291
|
+
guardNameByFile.set(
|
|
292
|
+
guardFile,
|
|
293
|
+
guardName
|
|
294
|
+
);
|
|
295
|
+
imports.push(
|
|
296
|
+
`import { guard as ${guardName} } from ${JSON.stringify(
|
|
297
|
+
toImportSpecifier(
|
|
298
|
+
entryDirectory,
|
|
299
|
+
guardFile
|
|
300
|
+
)
|
|
301
|
+
)};`
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const definitions =
|
|
307
|
+
guardedRoutes.map(
|
|
308
|
+
({
|
|
309
|
+
route,
|
|
310
|
+
guardFiles,
|
|
311
|
+
}) => {
|
|
312
|
+
const guards =
|
|
313
|
+
guardFiles.map(
|
|
314
|
+
(guardFile) => {
|
|
315
|
+
const guardName =
|
|
316
|
+
guardNameByFile.get(
|
|
317
|
+
guardFile
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (!guardName) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`BCP Framework: guard import was not generated for "${guardFile}".`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const label =
|
|
327
|
+
path.relative(
|
|
328
|
+
rootDirectory,
|
|
329
|
+
guardFile
|
|
330
|
+
)
|
|
331
|
+
.replace(
|
|
332
|
+
/\\/g,
|
|
333
|
+
"/"
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
return `{
|
|
337
|
+
filePath: ${JSON.stringify(label)},
|
|
338
|
+
guard: ${guardName}
|
|
339
|
+
}`;
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
return `{
|
|
344
|
+
pathname: ${JSON.stringify(route.pathname)},
|
|
345
|
+
segments: ${JSON.stringify(route.segments)},
|
|
346
|
+
guards: [${guards.join(", ")}]
|
|
347
|
+
}`;
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
return `${imports.join("\n")}
|
|
352
|
+
|
|
353
|
+
const definitions = [
|
|
354
|
+
${definitions.join(",\n ")}
|
|
355
|
+
];
|
|
356
|
+
|
|
357
|
+
const routePatterns =
|
|
358
|
+
definitions.map(
|
|
359
|
+
(definition) => ({
|
|
360
|
+
pathname:
|
|
361
|
+
definition.pathname,
|
|
362
|
+
segments:
|
|
363
|
+
definition.segments,
|
|
364
|
+
filePath:
|
|
365
|
+
definition.pathname,
|
|
366
|
+
layouts: []
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
const definitionByPathname =
|
|
371
|
+
new Map(
|
|
372
|
+
definitions.map(
|
|
373
|
+
(definition) => [
|
|
374
|
+
definition.pathname,
|
|
375
|
+
definition
|
|
376
|
+
]
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
export const guardedPathnames =
|
|
381
|
+
definitions.map(
|
|
382
|
+
(definition) =>
|
|
383
|
+
definition.pathname
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
export async function evaluateRouteGuards(input) {
|
|
387
|
+
const target =
|
|
388
|
+
new URL(
|
|
389
|
+
input.url
|
|
390
|
+
);
|
|
391
|
+
const match =
|
|
392
|
+
matchRoute(
|
|
393
|
+
routePatterns,
|
|
394
|
+
target.pathname
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
if (!match) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const definition =
|
|
402
|
+
definitionByPathname.get(
|
|
403
|
+
match.route.pathname
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (!definition) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const request =
|
|
411
|
+
new Request(
|
|
412
|
+
target,
|
|
413
|
+
{
|
|
414
|
+
method:
|
|
415
|
+
input.method ||
|
|
416
|
+
"GET",
|
|
417
|
+
headers:
|
|
418
|
+
new Headers(
|
|
419
|
+
input.headers ||
|
|
420
|
+
[]
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
return runWithRequestContext(
|
|
426
|
+
request,
|
|
427
|
+
async () => {
|
|
428
|
+
const execution =
|
|
429
|
+
await executePageGuardFunctions(
|
|
430
|
+
definition.guards,
|
|
431
|
+
match.params,
|
|
432
|
+
target
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
if (execution.response) {
|
|
436
|
+
return {
|
|
437
|
+
kind:
|
|
438
|
+
"response",
|
|
439
|
+
response:
|
|
440
|
+
applyResponseCookies(
|
|
441
|
+
execution.response
|
|
442
|
+
)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const cookieCarrier =
|
|
447
|
+
applyResponseCookies(
|
|
448
|
+
new Response(
|
|
449
|
+
null,
|
|
450
|
+
{
|
|
451
|
+
status: 204
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
kind:
|
|
458
|
+
"allow",
|
|
459
|
+
data:
|
|
460
|
+
execution.data,
|
|
461
|
+
setCookies:
|
|
462
|
+
cookieCarrier.headers.getSetCookie()
|
|
463
|
+
};
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
remoteAddress:
|
|
467
|
+
input.remoteAddress ||
|
|
468
|
+
null
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function toImportSpecifier(
|
|
476
|
+
fromDirectory: string,
|
|
477
|
+
filePath: string
|
|
478
|
+
): string {
|
|
479
|
+
let relative =
|
|
480
|
+
path.relative(
|
|
481
|
+
fromDirectory,
|
|
482
|
+
filePath
|
|
483
|
+
)
|
|
484
|
+
.replace(
|
|
485
|
+
/\\/g,
|
|
486
|
+
"/"
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
if (
|
|
490
|
+
!relative.startsWith(".")
|
|
491
|
+
) {
|
|
492
|
+
relative =
|
|
493
|
+
`./${relative}`;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return relative;
|
|
497
|
+
}
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
findProjectMiddlewareFile,
|
|
17
17
|
} from "../../server/src/middleware-loader.js";
|
|
18
18
|
|
|
19
|
+
import {
|
|
20
|
+
routeHasPageGuard,
|
|
21
|
+
} from "../../server/src/page-guard.js";
|
|
22
|
+
|
|
19
23
|
import type {
|
|
20
24
|
ApiRoute,
|
|
21
25
|
Route,
|
|
@@ -29,6 +33,10 @@ import type {
|
|
|
29
33
|
PartialHydrationBuildManifest,
|
|
30
34
|
} from "./partial-hydration.js";
|
|
31
35
|
|
|
36
|
+
import {
|
|
37
|
+
buildProductionGuards,
|
|
38
|
+
} from "./server-production-guards.js";
|
|
39
|
+
|
|
32
40
|
import {
|
|
33
41
|
buildProductionServer as buildBaseProductionServer,
|
|
34
42
|
type ProductionServerBuildResult,
|
|
@@ -73,7 +81,8 @@ export async function buildProductionServer(
|
|
|
73
81
|
writeCacheManifest(
|
|
74
82
|
pageRoutes,
|
|
75
83
|
apiRoutes,
|
|
76
|
-
serverDirectory
|
|
84
|
+
serverDirectory,
|
|
85
|
+
rootDirectory
|
|
77
86
|
);
|
|
78
87
|
|
|
79
88
|
await buildProductionMiddleware(
|
|
@@ -81,6 +90,12 @@ export async function buildProductionServer(
|
|
|
81
90
|
serverDirectory
|
|
82
91
|
);
|
|
83
92
|
|
|
93
|
+
await buildProductionGuards(
|
|
94
|
+
pageRoutes,
|
|
95
|
+
rootDirectory,
|
|
96
|
+
serverDirectory
|
|
97
|
+
);
|
|
98
|
+
|
|
84
99
|
return {
|
|
85
100
|
...baseResult,
|
|
86
101
|
size:
|
|
@@ -174,11 +189,6 @@ async function bundleServerCacheRuntime(
|
|
|
174
189
|
serverFile
|
|
175
190
|
);
|
|
176
191
|
|
|
177
|
-
/*
|
|
178
|
-
* The base server build may have emitted an external map. The final
|
|
179
|
-
* cache-runtime rebundle uses an inline map so a stale server.mjs.map
|
|
180
|
-
* must not be shipped next to the rewritten bundle.
|
|
181
|
-
*/
|
|
182
192
|
fs.rmSync(
|
|
183
193
|
`${serverFile}.map`,
|
|
184
194
|
{
|
|
@@ -204,14 +214,29 @@ async function bundleServerCacheRuntime(
|
|
|
204
214
|
function writeCacheManifest(
|
|
205
215
|
pageRoutes: Route[],
|
|
206
216
|
apiRoutes: ApiRoute[],
|
|
207
|
-
serverDirectory: string
|
|
217
|
+
serverDirectory: string,
|
|
218
|
+
rootDirectory: string
|
|
208
219
|
): void {
|
|
220
|
+
const appDirectory =
|
|
221
|
+
path.join(
|
|
222
|
+
rootDirectory,
|
|
223
|
+
"app"
|
|
224
|
+
);
|
|
225
|
+
const cacheablePages =
|
|
226
|
+
pageRoutes.filter(
|
|
227
|
+
(route) =>
|
|
228
|
+
!routeHasPageGuard(
|
|
229
|
+
appDirectory,
|
|
230
|
+
route.filePath
|
|
231
|
+
)
|
|
232
|
+
);
|
|
233
|
+
|
|
209
234
|
const manifest:
|
|
210
235
|
CacheManifest = {
|
|
211
236
|
version: 1,
|
|
212
237
|
pages:
|
|
213
238
|
collectCacheRoutes(
|
|
214
|
-
|
|
239
|
+
cacheablePages
|
|
215
240
|
),
|
|
216
241
|
apiRoutes:
|
|
217
242
|
collectCacheRoutes(
|
|
@@ -22,6 +22,10 @@ import type {
|
|
|
22
22
|
Route,
|
|
23
23
|
} from "../../router/src/index.js";
|
|
24
24
|
|
|
25
|
+
import {
|
|
26
|
+
findPageLoaderFile,
|
|
27
|
+
} from "../../server/src/page-loader.js";
|
|
28
|
+
|
|
25
29
|
import type {
|
|
26
30
|
PartialHydrationBuildManifest,
|
|
27
31
|
} from "./partial-hydration.js";
|
|
@@ -416,6 +420,26 @@ function createServerEntry(
|
|
|
416
420
|
`const ${pageName} = ${pageModuleName}.default;`
|
|
417
421
|
);
|
|
418
422
|
|
|
423
|
+
const loaderFile =
|
|
424
|
+
findPageLoaderFile(
|
|
425
|
+
route.filePath
|
|
426
|
+
);
|
|
427
|
+
let loaderName =
|
|
428
|
+
"null";
|
|
429
|
+
|
|
430
|
+
if (loaderFile) {
|
|
431
|
+
loaderName =
|
|
432
|
+
`Loader${routeIndex}`;
|
|
433
|
+
imports.push(
|
|
434
|
+
`import { loader as ${loaderName} } from ${JSON.stringify(
|
|
435
|
+
toImportSpecifier(
|
|
436
|
+
entryDirectory,
|
|
437
|
+
loaderFile
|
|
438
|
+
)
|
|
439
|
+
)};`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
419
443
|
const layoutModules:
|
|
420
444
|
Array<{
|
|
421
445
|
name: string;
|
|
@@ -630,6 +654,7 @@ function createServerEntry(
|
|
|
630
654
|
error: ${errorName},
|
|
631
655
|
notFound: ${notFoundName},
|
|
632
656
|
metadataSources: [${metadataSources.join(", ")}],
|
|
657
|
+
loader: ${loaderName},
|
|
633
658
|
hydration: ${JSON.stringify(hydration)},
|
|
634
659
|
client: ${JSON.stringify(client)}
|
|
635
660
|
}`);
|