@reckona/mreact-router 0.0.100 → 0.0.101
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/build.d.ts.map +1 -1
- package/dist/build.js +170 -50
- package/dist/build.js.map +1 -1
- package/package.json +11 -11
- package/src/build.ts +240 -53
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-router",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.101",
|
|
4
4
|
"description": "File-system app router, SSR, actions, and deployment adapters for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx",
|
|
@@ -105,20 +105,20 @@
|
|
|
105
105
|
},
|
|
106
106
|
"dependencies": {
|
|
107
107
|
"typescript": "^6.0.3",
|
|
108
|
-
"@reckona/mreact": "0.0.
|
|
109
|
-
"@reckona/mreact-
|
|
110
|
-
"@reckona/mreact-devtools": "0.0.
|
|
111
|
-
"@reckona/mreact-
|
|
112
|
-
"@reckona/mreact-
|
|
113
|
-
"@reckona/mreact-
|
|
114
|
-
"@reckona/mreact-reactive-dom": "0.0.
|
|
115
|
-
"@reckona/mreact-server": "0.0.
|
|
116
|
-
"@reckona/mreact-shared": "0.0.
|
|
108
|
+
"@reckona/mreact": "0.0.101",
|
|
109
|
+
"@reckona/mreact-compiler": "0.0.101",
|
|
110
|
+
"@reckona/mreact-devtools": "0.0.101",
|
|
111
|
+
"@reckona/mreact-compat": "0.0.101",
|
|
112
|
+
"@reckona/mreact-reactive-core": "0.0.101",
|
|
113
|
+
"@reckona/mreact-query": "0.0.101",
|
|
114
|
+
"@reckona/mreact-reactive-dom": "0.0.101",
|
|
115
|
+
"@reckona/mreact-server": "0.0.101",
|
|
116
|
+
"@reckona/mreact-shared": "0.0.101"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
119
|
"vite": ">=8 <9"
|
|
120
120
|
},
|
|
121
121
|
"optionalDependencies": {
|
|
122
|
-
"@reckona/mreact-router-native": "0.0.
|
|
122
|
+
"@reckona/mreact-router-native": "0.0.101"
|
|
123
123
|
}
|
|
124
124
|
}
|
package/src/build.ts
CHANGED
|
@@ -2380,6 +2380,11 @@ interface CloudflareBatchedRouteModules {
|
|
|
2380
2380
|
entries: ReadonlyMap<string, CloudflareBatchedRouteModule>;
|
|
2381
2381
|
}
|
|
2382
2382
|
|
|
2383
|
+
interface CloudflareBatchedComponentRoute {
|
|
2384
|
+
filename: string;
|
|
2385
|
+
routeId: string;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2383
2388
|
interface RouteRequestModuleBatchEntry {
|
|
2384
2389
|
code: string;
|
|
2385
2390
|
filename: string;
|
|
@@ -2437,10 +2442,26 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2437
2442
|
root: options.projectRoot,
|
|
2438
2443
|
vitePlugins: options.vitePlugins,
|
|
2439
2444
|
});
|
|
2445
|
+
const directComponentRoutes = await collectCloudflareDirectComponentRoutes({
|
|
2446
|
+
requiredRoutes,
|
|
2447
|
+
routesDir: options.routesDir,
|
|
2448
|
+
serverModules: options.serverModules,
|
|
2449
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2450
|
+
});
|
|
2451
|
+
const directComponentRouteIds = new Set(directComponentRoutes.map((route) => route.routeId));
|
|
2452
|
+
const directComponentModules = await buildCloudflareServerComponentModuleBatch({
|
|
2453
|
+
cacheDir: options.cacheDir,
|
|
2454
|
+
projectRoot: options.projectRoot,
|
|
2455
|
+
routes: directComponentRoutes,
|
|
2456
|
+
serverModules: options.serverModules,
|
|
2457
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2458
|
+
vitePlugins: options.vitePlugins,
|
|
2459
|
+
});
|
|
2440
2460
|
|
|
2441
2461
|
await Promise.all([
|
|
2442
2462
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, serverRouteModules),
|
|
2443
2463
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, loaderRouteModules),
|
|
2464
|
+
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, directComponentModules),
|
|
2444
2465
|
]);
|
|
2445
2466
|
|
|
2446
2467
|
const registryEntries = await mapWithBuildConcurrency(requiredRoutes, async ({ route, routeFile, routeId }) => {
|
|
@@ -2480,29 +2501,39 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2480
2501
|
: "string";
|
|
2481
2502
|
|
|
2482
2503
|
try {
|
|
2483
|
-
const
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
+
const batchedComponent =
|
|
2505
|
+
directComponentRouteIds.has(routeId) ? directComponentModules.entries.get(routeId) : undefined;
|
|
2506
|
+
let componentFile = batchedComponent?.fileName;
|
|
2507
|
+
|
|
2508
|
+
if (batchedComponent === undefined) {
|
|
2509
|
+
const componentOutput =
|
|
2510
|
+
serverOutput === "stream"
|
|
2511
|
+
? await buildCloudflareStreamRouteComponentModule({
|
|
2512
|
+
cacheDir: options.cacheDir,
|
|
2513
|
+
filename: route.file,
|
|
2514
|
+
projectRoot: options.projectRoot,
|
|
2515
|
+
routesDir: options.routesDir,
|
|
2516
|
+
serverModules: options.serverModules,
|
|
2517
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2518
|
+
vitePlugins: options.vitePlugins,
|
|
2519
|
+
})
|
|
2520
|
+
: await buildCloudflareStringRouteComponentModule({
|
|
2521
|
+
cacheDir: options.cacheDir,
|
|
2522
|
+
filename: route.file,
|
|
2523
|
+
projectRoot: options.projectRoot,
|
|
2524
|
+
routesDir: options.routesDir,
|
|
2525
|
+
serverModules: options.serverModules,
|
|
2526
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2527
|
+
vitePlugins: options.vitePlugins,
|
|
2528
|
+
});
|
|
2504
2529
|
|
|
2505
|
-
|
|
2530
|
+
componentFile = `routes/${routeId}.${hashText(componentOutput).slice(0, 8)}.component.mjs`;
|
|
2531
|
+
await writeFile(join(options.cloudflareDir, componentFile), componentOutput);
|
|
2532
|
+
}
|
|
2533
|
+
|
|
2534
|
+
if (componentFile === undefined) {
|
|
2535
|
+
throw new Error("Missing bundled Cloudflare component module.");
|
|
2536
|
+
}
|
|
2506
2537
|
|
|
2507
2538
|
const componentImport = `./${componentFile.split("/").pop() ?? componentFile}`;
|
|
2508
2539
|
routeModuleExports = [
|
|
@@ -2549,12 +2580,140 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2549
2580
|
return { registryFile: "route-modules.mjs" };
|
|
2550
2581
|
}
|
|
2551
2582
|
|
|
2583
|
+
async function collectCloudflareDirectComponentRoutes(options: {
|
|
2584
|
+
requiredRoutes: readonly CloudflareRequiredRoute[];
|
|
2585
|
+
routesDir: string;
|
|
2586
|
+
serverModules: Record<string, BuiltServerModuleArtifact>;
|
|
2587
|
+
sourceAnalysis: BuildSourceAnalysisScope;
|
|
2588
|
+
}): Promise<CloudflareBatchedComponentRoute[]> {
|
|
2589
|
+
const routes = await Promise.all(
|
|
2590
|
+
options.requiredRoutes.map(async ({ route, routeFile, routeId }) => {
|
|
2591
|
+
if (route.kind !== "page") {
|
|
2592
|
+
return undefined;
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
const serverOutput =
|
|
2596
|
+
options.serverModules[routeFile]?.analysis?.streamRoute === true ||
|
|
2597
|
+
options.sourceAnalysis.byRouteFile.get(routeFile)?.streamRoute === true
|
|
2598
|
+
? "stream"
|
|
2599
|
+
: "string";
|
|
2600
|
+
|
|
2601
|
+
if (serverOutput !== "string") {
|
|
2602
|
+
return undefined;
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
const shellFiles = await cloudflareShellFilesForPage(options.routesDir, route.file);
|
|
2606
|
+
|
|
2607
|
+
if (shellFiles.length > 0) {
|
|
2608
|
+
return undefined;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
return {
|
|
2612
|
+
filename: route.file,
|
|
2613
|
+
routeId,
|
|
2614
|
+
};
|
|
2615
|
+
}),
|
|
2616
|
+
);
|
|
2617
|
+
|
|
2618
|
+
return routes.filter((route): route is CloudflareBatchedComponentRoute => route !== undefined);
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2552
2621
|
interface CloudflareShellFile {
|
|
2553
2622
|
file: string;
|
|
2554
2623
|
id: string;
|
|
2555
2624
|
kind: "layout" | "template";
|
|
2556
2625
|
}
|
|
2557
2626
|
|
|
2627
|
+
async function buildCloudflareServerComponentModuleBatch(options: {
|
|
2628
|
+
cacheDir?: string | undefined;
|
|
2629
|
+
projectRoot: string;
|
|
2630
|
+
routes: readonly CloudflareBatchedComponentRoute[];
|
|
2631
|
+
serverModules: Record<string, BuiltServerModuleArtifact>;
|
|
2632
|
+
sourceAnalysis: BuildSourceAnalysisScope;
|
|
2633
|
+
vitePlugins?: readonly PluginOption[] | undefined;
|
|
2634
|
+
}): Promise<CloudflareBatchedRouteModules> {
|
|
2635
|
+
if (options.routes.length === 0) {
|
|
2636
|
+
return { chunks: [], entries: new Map() };
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
const virtualModules = new Map<string, CloudflareVirtualModule>();
|
|
2640
|
+
const bundleEntries = await Promise.all(
|
|
2641
|
+
options.routes.map(async (route) => {
|
|
2642
|
+
const metadataModule = await buildCloudflareRouteMetadataExportModule({
|
|
2643
|
+
cacheDir: options.cacheDir,
|
|
2644
|
+
filename: route.filename,
|
|
2645
|
+
hasMetadata: buildSourceAnalysisForFile(
|
|
2646
|
+
options.sourceAnalysis,
|
|
2647
|
+
options.projectRoot,
|
|
2648
|
+
route.filename,
|
|
2649
|
+
)?.hasMetadata,
|
|
2650
|
+
root: options.projectRoot,
|
|
2651
|
+
vitePlugins: options.vitePlugins,
|
|
2652
|
+
});
|
|
2653
|
+
const metadataId = `mreact:metadata:${route.routeId}`;
|
|
2654
|
+
|
|
2655
|
+
if (metadataModule !== undefined) {
|
|
2656
|
+
virtualModules.set(metadataId, {
|
|
2657
|
+
contents: metadataModule,
|
|
2658
|
+
resolveDir: dirname(route.filename),
|
|
2659
|
+
});
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
return {
|
|
2663
|
+
code: cloudflareServerComponentModuleEntry(
|
|
2664
|
+
route.filename,
|
|
2665
|
+
metadataModule === undefined ? undefined : metadataId,
|
|
2666
|
+
),
|
|
2667
|
+
filename: `${route.filename}.mreact-cloudflare-component.js`,
|
|
2668
|
+
name: `${route.routeId}.component`,
|
|
2669
|
+
routeId: route.routeId,
|
|
2670
|
+
};
|
|
2671
|
+
}),
|
|
2672
|
+
);
|
|
2673
|
+
const output = await bundleRouterModules({
|
|
2674
|
+
cacheDir: options.cacheDir,
|
|
2675
|
+
chunkFileNames: "routes/chunks/[name].[hash].mjs",
|
|
2676
|
+
entries: bundleEntries,
|
|
2677
|
+
entryFileNames: "routes/[name].[hash].mjs",
|
|
2678
|
+
minify: true,
|
|
2679
|
+
platform: "node",
|
|
2680
|
+
plugins: [
|
|
2681
|
+
cloudflareVirtualModulesPlugin(virtualModules),
|
|
2682
|
+
cloudflareServerSourceTransformPlugin({
|
|
2683
|
+
projectRoot: options.projectRoot,
|
|
2684
|
+
serverOutput: "string",
|
|
2685
|
+
serverModules: options.serverModules,
|
|
2686
|
+
vitePlugins: options.vitePlugins,
|
|
2687
|
+
}),
|
|
2688
|
+
cloudflareWorkspaceRuntimePlugin(),
|
|
2689
|
+
],
|
|
2690
|
+
root: options.projectRoot,
|
|
2691
|
+
target: "es2022",
|
|
2692
|
+
vitePlugins: options.vitePlugins,
|
|
2693
|
+
});
|
|
2694
|
+
const entriesByName = new Map(bundleEntries.map((entry) => [entry.name, entry]));
|
|
2695
|
+
const entries = new Map<string, CloudflareBatchedRouteModule>();
|
|
2696
|
+
|
|
2697
|
+
for (const chunk of output.chunks) {
|
|
2698
|
+
if (!chunk.isEntry) {
|
|
2699
|
+
continue;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
const entry = entriesByName.get(chunk.name);
|
|
2703
|
+
|
|
2704
|
+
if (entry === undefined) {
|
|
2705
|
+
continue;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
entries.set(entry.routeId, {
|
|
2709
|
+
code: chunk.code,
|
|
2710
|
+
fileName: chunk.fileName,
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
return { chunks: output.chunks, entries };
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2558
2717
|
async function buildCloudflareServerComponentModule(options: {
|
|
2559
2718
|
cacheDir?: string | undefined;
|
|
2560
2719
|
filename: string;
|
|
@@ -2571,15 +2730,10 @@ async function buildCloudflareServerComponentModule(options: {
|
|
|
2571
2730
|
root: options.projectRoot,
|
|
2572
2731
|
vitePlugins: options.vitePlugins,
|
|
2573
2732
|
});
|
|
2574
|
-
const entry =
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
export const App = component;
|
|
2579
|
-
export default component;
|
|
2580
|
-
export const generateMetadata = metadataModule.generateMetadata;
|
|
2581
|
-
export const metadata = metadataModule.metadata;
|
|
2582
|
-
export const slots = routeModule.slots;`;
|
|
2733
|
+
const entry = cloudflareServerComponentModuleEntry(
|
|
2734
|
+
options.filename,
|
|
2735
|
+
metadataModule === undefined ? undefined : "mreact:metadata",
|
|
2736
|
+
);
|
|
2583
2737
|
|
|
2584
2738
|
return bundleCloudflareVirtualModule({
|
|
2585
2739
|
entry,
|
|
@@ -2603,6 +2757,21 @@ export const slots = routeModule.slots;`;
|
|
|
2603
2757
|
});
|
|
2604
2758
|
}
|
|
2605
2759
|
|
|
2760
|
+
function cloudflareServerComponentModuleEntry(
|
|
2761
|
+
filename: string,
|
|
2762
|
+
metadataModuleId: string | undefined,
|
|
2763
|
+
): string {
|
|
2764
|
+
return `import * as routeModule from ${JSON.stringify(filename)};
|
|
2765
|
+
${metadataModuleId === undefined ? "const metadataModule = {};" : `import * as metadataModule from ${JSON.stringify(metadataModuleId)};`}
|
|
2766
|
+
|
|
2767
|
+
const component = routeModule.default ?? routeModule.App ?? Object.values(routeModule).find((value) => typeof value === "function");
|
|
2768
|
+
export const App = component;
|
|
2769
|
+
export default component;
|
|
2770
|
+
export const generateMetadata = metadataModule.generateMetadata;
|
|
2771
|
+
export const metadata = metadataModule.metadata;
|
|
2772
|
+
export const slots = routeModule.slots;`;
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2606
2775
|
async function buildCloudflareStringRouteComponentModule(options: {
|
|
2607
2776
|
cacheDir?: string | undefined;
|
|
2608
2777
|
filename: string;
|
|
@@ -3341,28 +3510,14 @@ async function bundleCloudflareVirtualModule(options: {
|
|
|
3341
3510
|
entry: options.entry,
|
|
3342
3511
|
filename: options.filename,
|
|
3343
3512
|
plugins: [
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
const contents = options.modules.get(args.path);
|
|
3353
|
-
|
|
3354
|
-
if (contents === undefined) {
|
|
3355
|
-
throw new Error(`Missing virtual Cloudflare module ${args.path}.`);
|
|
3356
|
-
}
|
|
3357
|
-
|
|
3358
|
-
return {
|
|
3359
|
-
contents,
|
|
3360
|
-
loader: "js",
|
|
3361
|
-
resolveDir: options.resolveDir,
|
|
3362
|
-
};
|
|
3363
|
-
});
|
|
3364
|
-
},
|
|
3365
|
-
},
|
|
3513
|
+
cloudflareVirtualModulesPlugin(
|
|
3514
|
+
new Map(
|
|
3515
|
+
Array.from(options.modules, ([id, contents]) => [
|
|
3516
|
+
id,
|
|
3517
|
+
{ contents, resolveDir: options.resolveDir },
|
|
3518
|
+
]),
|
|
3519
|
+
),
|
|
3520
|
+
),
|
|
3366
3521
|
...options.plugins,
|
|
3367
3522
|
],
|
|
3368
3523
|
resolveDir: options.resolveDir,
|
|
@@ -3371,6 +3526,38 @@ async function bundleCloudflareVirtualModule(options: {
|
|
|
3371
3526
|
});
|
|
3372
3527
|
}
|
|
3373
3528
|
|
|
3529
|
+
interface CloudflareVirtualModule {
|
|
3530
|
+
contents: string;
|
|
3531
|
+
resolveDir: string;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
function cloudflareVirtualModulesPlugin(
|
|
3535
|
+
modules: ReadonlyMap<string, CloudflareVirtualModule>,
|
|
3536
|
+
): RouterCompatPlugin {
|
|
3537
|
+
return {
|
|
3538
|
+
name: "mreact-cloudflare-virtual-modules",
|
|
3539
|
+
setup(buildApi) {
|
|
3540
|
+
buildApi.onResolve({ filter: /^mreact:/ }, (args) => ({
|
|
3541
|
+
namespace: "mreact-cloudflare-virtual",
|
|
3542
|
+
path: args.path,
|
|
3543
|
+
}));
|
|
3544
|
+
buildApi.onLoad({ filter: /.*/, namespace: "mreact-cloudflare-virtual" }, (args) => {
|
|
3545
|
+
const module = modules.get(args.path);
|
|
3546
|
+
|
|
3547
|
+
if (module === undefined) {
|
|
3548
|
+
throw new Error(`Missing virtual Cloudflare module ${args.path}.`);
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3551
|
+
return {
|
|
3552
|
+
contents: module.contents,
|
|
3553
|
+
loader: "js",
|
|
3554
|
+
resolveDir: module.resolveDir,
|
|
3555
|
+
};
|
|
3556
|
+
});
|
|
3557
|
+
},
|
|
3558
|
+
};
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3374
3561
|
async function cloudflareShellFilesForPage(
|
|
3375
3562
|
routesDir: string,
|
|
3376
3563
|
pageFile: string,
|