@react-router/dev 0.0.0-experimental-df0f1dfda → 0.0.0-experimental-fde52e515
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 +20 -0
- package/bin.js +2 -2
- package/dist/cli/index.js +302 -141
- package/dist/config.js +1 -1
- package/dist/routes.js +1 -1
- package/dist/vite/cloudflare.js +1 -1
- package/dist/vite.js +459 -218
- package/package.json +6 -6
package/dist/vite.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @react-router/dev v0.0.0-experimental-
|
|
2
|
+
* @react-router/dev v0.0.0-experimental-fde52e515
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -52,8 +52,10 @@ var fse = __toESM(require("fs-extra"));
|
|
|
52
52
|
var babel = __toESM(require("@babel/core"));
|
|
53
53
|
var import_react_router2 = require("react-router");
|
|
54
54
|
var import_es_module_lexer = require("es-module-lexer");
|
|
55
|
+
var import_pick3 = __toESM(require("lodash/pick"));
|
|
55
56
|
var import_jsesc = __toESM(require("jsesc"));
|
|
56
57
|
var import_picocolors3 = __toESM(require("picocolors"));
|
|
58
|
+
var import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
57
59
|
|
|
58
60
|
// typegen/index.ts
|
|
59
61
|
var import_node_fs2 = __toESM(require("fs"));
|
|
@@ -270,6 +272,13 @@ var detectPackageManager = () => {
|
|
|
270
272
|
|
|
271
273
|
// config/config.ts
|
|
272
274
|
var excludedConfigPresetKeys = ["presets"];
|
|
275
|
+
var branchRouteProperties = [
|
|
276
|
+
"id",
|
|
277
|
+
"path",
|
|
278
|
+
"file",
|
|
279
|
+
"index"
|
|
280
|
+
];
|
|
281
|
+
var configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
|
|
273
282
|
var mergeReactRouterConfig = (...configs) => {
|
|
274
283
|
let reducer = (configA, configB) => {
|
|
275
284
|
let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
|
|
@@ -1797,6 +1806,8 @@ var plugin = {
|
|
|
1797
1806
|
return function Wrapped() {
|
|
1798
1807
|
const props = {
|
|
1799
1808
|
params: useParams(),
|
|
1809
|
+
loaderData: useLoaderData(),
|
|
1810
|
+
actionData: useActionData(),
|
|
1800
1811
|
};
|
|
1801
1812
|
return h(HydrateFallback, props);
|
|
1802
1813
|
};
|
|
@@ -2062,16 +2073,24 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
|
|
|
2062
2073
|
);
|
|
2063
2074
|
return getExportNames(code);
|
|
2064
2075
|
};
|
|
2065
|
-
var
|
|
2066
|
-
|
|
2076
|
+
var resolveEnvironmentBuildContext = ({
|
|
2077
|
+
viteCommand,
|
|
2078
|
+
viteUserConfig
|
|
2079
|
+
}) => {
|
|
2080
|
+
if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
|
|
2067
2081
|
return null;
|
|
2068
2082
|
}
|
|
2069
|
-
|
|
2083
|
+
let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
|
|
2084
|
+
let resolvedBuildContext = {
|
|
2085
|
+
name: buildContext.name,
|
|
2086
|
+
options: buildContext.resolveOptions({ viteCommand, viteUserConfig })
|
|
2087
|
+
};
|
|
2088
|
+
return resolvedBuildContext;
|
|
2070
2089
|
};
|
|
2071
|
-
var getServerBuildDirectory = (ctx) => path6.join(
|
|
2090
|
+
var getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path6.join(
|
|
2072
2091
|
ctx.reactRouterConfig.buildDirectory,
|
|
2073
2092
|
"server",
|
|
2074
|
-
...
|
|
2093
|
+
...serverBundleId ? [serverBundleId] : []
|
|
2075
2094
|
);
|
|
2076
2095
|
var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
|
|
2077
2096
|
var defaultEntriesDir = path6.resolve(
|
|
@@ -2123,36 +2142,36 @@ var reactRouterVitePlugin = () => {
|
|
|
2123
2142
|
process.exit(1);
|
|
2124
2143
|
}
|
|
2125
2144
|
let viteManifestEnabled = viteUserConfig.build?.manifest === true;
|
|
2126
|
-
let
|
|
2127
|
-
isSsrBuild: true,
|
|
2128
|
-
getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
|
|
2129
|
-
serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
|
|
2130
|
-
} : { isSsrBuild: false };
|
|
2145
|
+
let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
|
|
2131
2146
|
firstLoad = false;
|
|
2132
2147
|
ctx = {
|
|
2148
|
+
environmentBuildContext,
|
|
2133
2149
|
reactRouterConfig,
|
|
2134
2150
|
rootDirectory,
|
|
2135
2151
|
entryClientFilePath,
|
|
2136
2152
|
entryServerFilePath,
|
|
2137
2153
|
publicPath,
|
|
2138
|
-
viteManifestEnabled
|
|
2139
|
-
...ssrBuildCtx
|
|
2154
|
+
viteManifestEnabled
|
|
2140
2155
|
};
|
|
2141
2156
|
};
|
|
2142
2157
|
let pluginIndex = (pluginName) => {
|
|
2143
2158
|
invariant(viteConfig);
|
|
2144
2159
|
return viteConfig.plugins.findIndex((plugin2) => plugin2.name === pluginName);
|
|
2145
2160
|
};
|
|
2146
|
-
let getServerEntry = async () => {
|
|
2161
|
+
let getServerEntry = async ({ routeIds }) => {
|
|
2147
2162
|
invariant(viteConfig, "viteconfig required to generate the server entry");
|
|
2148
|
-
let routes =
|
|
2163
|
+
let routes = routeIds ? (
|
|
2149
2164
|
// For server bundle builds, the server build should only import the
|
|
2150
2165
|
// routes for this bundle rather than importing all routes
|
|
2151
|
-
ctx.
|
|
2166
|
+
(0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
|
|
2152
2167
|
) : (
|
|
2153
2168
|
// Otherwise, all routes are imported as usual
|
|
2154
2169
|
ctx.reactRouterConfig.routes
|
|
2155
2170
|
);
|
|
2171
|
+
let prerenderPaths = await getPrerenderPaths(
|
|
2172
|
+
ctx.reactRouterConfig.prerender,
|
|
2173
|
+
routes
|
|
2174
|
+
);
|
|
2156
2175
|
return `
|
|
2157
2176
|
import * as entryServer from ${JSON.stringify(
|
|
2158
2177
|
resolveFileUrl(ctx, ctx.entryServerFilePath)
|
|
@@ -2167,7 +2186,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2167
2186
|
)};`;
|
|
2168
2187
|
}).join("\n")}
|
|
2169
2188
|
export { default as assets } from ${JSON.stringify(
|
|
2170
|
-
virtual.serverManifest.id
|
|
2189
|
+
`${virtual.serverManifest.id}${routeIds ? `?route-ids=${routeIds.join(",")}` : ""}`
|
|
2171
2190
|
)};
|
|
2172
2191
|
export const assetsBuildDirectory = ${JSON.stringify(
|
|
2173
2192
|
path6.relative(
|
|
@@ -2177,7 +2196,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2177
2196
|
)};
|
|
2178
2197
|
export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
|
|
2179
2198
|
export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
|
|
2180
|
-
export const
|
|
2199
|
+
export const ssr = ${ctx.reactRouterConfig.ssr};
|
|
2200
|
+
export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
|
|
2201
|
+
export const prerender = ${JSON.stringify(prerenderPaths)};
|
|
2181
2202
|
export const publicPath = ${JSON.stringify(ctx.publicPath)};
|
|
2182
2203
|
export const entry = { module: entryServer };
|
|
2183
2204
|
export const routes = {
|
|
@@ -2215,7 +2236,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2215
2236
|
);
|
|
2216
2237
|
return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
|
|
2217
2238
|
};
|
|
2218
|
-
let generateReactRouterManifestsForBuild = async (
|
|
2239
|
+
let generateReactRouterManifestsForBuild = async ({
|
|
2240
|
+
routeIds
|
|
2241
|
+
}) => {
|
|
2219
2242
|
invariant(viteConfig);
|
|
2220
2243
|
let viteManifest = await loadViteManifest(
|
|
2221
2244
|
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
@@ -2232,9 +2255,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2232
2255
|
ctx
|
|
2233
2256
|
);
|
|
2234
2257
|
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
2235
|
-
for (let
|
|
2258
|
+
for (let route of Object.values(ctx.reactRouterConfig.routes)) {
|
|
2236
2259
|
let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
2237
|
-
let sourceExports = routeManifestExports[
|
|
2260
|
+
let sourceExports = routeManifestExports[route.id];
|
|
2238
2261
|
let isRootRoute = route.parentId === void 0;
|
|
2239
2262
|
let hasClientAction = sourceExports.includes("clientAction");
|
|
2240
2263
|
let hasClientLoader = sourceExports.includes("clientLoader");
|
|
@@ -2292,10 +2315,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2292
2315
|
getRouteChunkModuleId(routeFile, "HydrateFallback")
|
|
2293
2316
|
) : void 0
|
|
2294
2317
|
};
|
|
2295
|
-
browserRoutes[
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
serverRoutes[key] = routeManifestEntry;
|
|
2318
|
+
browserRoutes[route.id] = routeManifestEntry;
|
|
2319
|
+
if (!routeIds || routeIds.includes(route.id)) {
|
|
2320
|
+
serverRoutes[route.id] = routeManifestEntry;
|
|
2299
2321
|
}
|
|
2300
2322
|
}
|
|
2301
2323
|
let fingerprintedValues = { entry, routes: browserRoutes };
|
|
@@ -2443,23 +2465,6 @@ var reactRouterVitePlugin = () => {
|
|
|
2443
2465
|
""
|
|
2444
2466
|
)
|
|
2445
2467
|
);
|
|
2446
|
-
let baseRollupOptions = {
|
|
2447
|
-
// Silence Rollup "use client" warnings
|
|
2448
|
-
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
2449
|
-
onwarn(warning, defaultHandler) {
|
|
2450
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
2451
|
-
return;
|
|
2452
|
-
}
|
|
2453
|
-
if (viteUserConfig.build?.rollupOptions?.onwarn) {
|
|
2454
|
-
viteUserConfig.build.rollupOptions.onwarn(
|
|
2455
|
-
warning,
|
|
2456
|
-
defaultHandler
|
|
2457
|
-
);
|
|
2458
|
-
} else {
|
|
2459
|
-
defaultHandler(warning);
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
};
|
|
2463
2468
|
return {
|
|
2464
2469
|
__reactRouterPluginContext: ctx,
|
|
2465
2470
|
appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
|
|
@@ -2517,73 +2522,11 @@ var reactRouterVitePlugin = () => {
|
|
|
2517
2522
|
// will throw an error that the file is not allowed to be read.
|
|
2518
2523
|
// https://vitejs.dev/config/server-options#server-fs-allow
|
|
2519
2524
|
server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
manifest: true,
|
|
2526
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig),
|
|
2527
|
-
rollupOptions: {
|
|
2528
|
-
...baseRollupOptions,
|
|
2529
|
-
preserveEntrySignatures: "exports-only",
|
|
2530
|
-
input: [
|
|
2531
|
-
ctx.entryClientFilePath,
|
|
2532
|
-
...Object.values(
|
|
2533
|
-
ctx.reactRouterConfig.routes
|
|
2534
|
-
).flatMap((route) => {
|
|
2535
|
-
let routeFilePath = path6.resolve(
|
|
2536
|
-
ctx.reactRouterConfig.appDirectory,
|
|
2537
|
-
route.file
|
|
2538
|
-
);
|
|
2539
|
-
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
2540
|
-
let code = fse.readFileSync(
|
|
2541
|
-
routeFilePath,
|
|
2542
|
-
"utf-8"
|
|
2543
|
-
);
|
|
2544
|
-
return [
|
|
2545
|
-
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
2546
|
-
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
2547
|
-
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(
|
|
2548
|
-
routeFilePath,
|
|
2549
|
-
exportName
|
|
2550
|
-
) : null
|
|
2551
|
-
) : []
|
|
2552
|
-
].filter(isNonNullable);
|
|
2553
|
-
})
|
|
2554
|
-
]
|
|
2555
|
-
}
|
|
2556
|
-
} : {
|
|
2557
|
-
// We move SSR-only assets to client assets. Note that the
|
|
2558
|
-
// SSR build can also emit code-split JS files (e.g. by
|
|
2559
|
-
// dynamic import) under the same assets directory
|
|
2560
|
-
// regardless of "ssrEmitAssets" option, so we also need to
|
|
2561
|
-
// keep these JS files have to be kept as-is.
|
|
2562
|
-
ssrEmitAssets: true,
|
|
2563
|
-
copyPublicDir: false,
|
|
2564
|
-
// Assets in the public directory are only used by the client
|
|
2565
|
-
manifest: true,
|
|
2566
|
-
// We need the manifest to detect SSR-only assets
|
|
2567
|
-
outDir: getServerBuildDirectory(ctx),
|
|
2568
|
-
rollupOptions: {
|
|
2569
|
-
...baseRollupOptions,
|
|
2570
|
-
preserveEntrySignatures: "exports-only",
|
|
2571
|
-
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id,
|
|
2572
|
-
output: {
|
|
2573
|
-
entryFileNames: ctx.reactRouterConfig.serverBuildFile,
|
|
2574
|
-
format: ctx.reactRouterConfig.serverModuleFormat
|
|
2575
|
-
}
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
} : void 0,
|
|
2580
|
-
// Vite config options for SPA preview mode
|
|
2581
|
-
...viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
|
|
2582
|
-
build: {
|
|
2583
|
-
manifest: true,
|
|
2584
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2585
|
-
}
|
|
2586
|
-
} : void 0
|
|
2525
|
+
build: ctx.environmentBuildContext?.options.build ?? (await getEnvironmentOptions(
|
|
2526
|
+
ctx,
|
|
2527
|
+
viteConfigEnv.isSsrBuild ? "ssr" : "client",
|
|
2528
|
+
{ viteCommand, viteUserConfig }
|
|
2529
|
+
)).build
|
|
2587
2530
|
};
|
|
2588
2531
|
},
|
|
2589
2532
|
async configResolved(resolvedViteConfig) {
|
|
@@ -2599,8 +2542,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2599
2542
|
let childCompilerConfigFile = await vite2.loadConfigFromFile(
|
|
2600
2543
|
{
|
|
2601
2544
|
command: viteConfig.command,
|
|
2602
|
-
mode: viteConfig.mode
|
|
2603
|
-
isSsrBuild: ctx.isSsrBuild
|
|
2545
|
+
mode: viteConfig.mode
|
|
2604
2546
|
},
|
|
2605
2547
|
viteConfig.configFile
|
|
2606
2548
|
);
|
|
@@ -2742,14 +2684,14 @@ var reactRouterVitePlugin = () => {
|
|
|
2742
2684
|
// After the SSR build is finished, we inspect the Vite manifest for
|
|
2743
2685
|
// the SSR build and move server-only assets to client assets directory
|
|
2744
2686
|
async handler() {
|
|
2745
|
-
if (!
|
|
2687
|
+
if (!viteConfigEnv.isSsrBuild) {
|
|
2746
2688
|
return;
|
|
2747
2689
|
}
|
|
2748
2690
|
invariant(viteConfig);
|
|
2749
2691
|
let clientBuildDirectory = getClientBuildDirectory(
|
|
2750
2692
|
ctx.reactRouterConfig
|
|
2751
2693
|
);
|
|
2752
|
-
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
2694
|
+
let serverBuildDirectory = ctx.environmentBuildContext?.options.build.outDir ?? getServerBuildDirectory(ctx);
|
|
2753
2695
|
let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
|
|
2754
2696
|
let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
|
|
2755
2697
|
let movedAssetPaths = [];
|
|
@@ -2783,7 +2725,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2783
2725
|
].join("\n")
|
|
2784
2726
|
);
|
|
2785
2727
|
}
|
|
2786
|
-
if (ctx.reactRouterConfig
|
|
2728
|
+
if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
|
|
2787
2729
|
await handlePrerender(
|
|
2788
2730
|
viteConfig,
|
|
2789
2731
|
ctx.reactRouterConfig,
|
|
@@ -2938,16 +2880,25 @@ var reactRouterVitePlugin = () => {
|
|
|
2938
2880
|
name: "react-router:virtual-modules",
|
|
2939
2881
|
enforce: "pre",
|
|
2940
2882
|
resolveId(id) {
|
|
2941
|
-
|
|
2942
|
-
|
|
2883
|
+
let [baseId, queryString] = id.split("?");
|
|
2884
|
+
const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === baseId);
|
|
2885
|
+
if (vmod2)
|
|
2886
|
+
return vmod2.resolvedId + (queryString ? `?${queryString}` : "");
|
|
2943
2887
|
},
|
|
2944
2888
|
async load(id) {
|
|
2945
|
-
|
|
2889
|
+
let [baseId, queryString] = id.split("?");
|
|
2890
|
+
switch (baseId) {
|
|
2946
2891
|
case virtual.serverBuild.resolvedId: {
|
|
2947
|
-
|
|
2892
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2893
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2894
|
+
return await getServerEntry({ routeIds });
|
|
2948
2895
|
}
|
|
2949
2896
|
case virtual.serverManifest.resolvedId: {
|
|
2950
|
-
let
|
|
2897
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2898
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2899
|
+
let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
|
|
2900
|
+
routeIds
|
|
2901
|
+
})).reactRouterServerManifest : await getReactRouterManifestForDev();
|
|
2951
2902
|
return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
|
|
2952
2903
|
es6: true
|
|
2953
2904
|
})};`;
|
|
@@ -3046,14 +2997,17 @@ var reactRouterVitePlugin = () => {
|
|
|
3046
2997
|
}
|
|
3047
2998
|
let route = getRoute(ctx.reactRouterConfig, id);
|
|
3048
2999
|
if (!route) return;
|
|
3049
|
-
if (!options?.ssr &&
|
|
3000
|
+
if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
|
|
3050
3001
|
let exportNames = getExportNames(code);
|
|
3051
|
-
let serverOnlyExports = exportNames.filter(
|
|
3052
|
-
(exp
|
|
3053
|
-
|
|
3002
|
+
let serverOnlyExports = exportNames.filter((exp) => {
|
|
3003
|
+
if (route.id === "root" && exp === "loader") {
|
|
3004
|
+
return false;
|
|
3005
|
+
}
|
|
3006
|
+
return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
|
|
3007
|
+
});
|
|
3054
3008
|
if (serverOnlyExports.length > 0) {
|
|
3055
3009
|
let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
|
|
3056
|
-
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://
|
|
3010
|
+
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3057
3011
|
throw Error(message);
|
|
3058
3012
|
}
|
|
3059
3013
|
if (route.id !== "root") {
|
|
@@ -3061,7 +3015,7 @@ var reactRouterVitePlugin = () => {
|
|
|
3061
3015
|
(exp) => exp === "HydrateFallback"
|
|
3062
3016
|
);
|
|
3063
3017
|
if (hasHydrateFallback) {
|
|
3064
|
-
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://
|
|
3018
|
+
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3065
3019
|
throw Error(message);
|
|
3066
3020
|
}
|
|
3067
3021
|
}
|
|
@@ -3354,6 +3308,12 @@ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteF
|
|
|
3354
3308
|
};
|
|
3355
3309
|
return info;
|
|
3356
3310
|
}
|
|
3311
|
+
function isPrerenderingEnabled(reactRouterConfig) {
|
|
3312
|
+
return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
|
|
3313
|
+
}
|
|
3314
|
+
function isSpaModeEnabled(reactRouterConfig) {
|
|
3315
|
+
return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
|
|
3316
|
+
}
|
|
3357
3317
|
async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
|
|
3358
3318
|
let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
|
|
3359
3319
|
let build = await import(url.pathToFileURL(serverBuildPath).toString());
|
|
@@ -3364,20 +3324,44 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
|
|
|
3364
3324
|
};
|
|
3365
3325
|
}
|
|
3366
3326
|
async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
|
|
3367
|
-
let { handler } = await getPrerenderBuildAndHandler(
|
|
3327
|
+
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
3368
3328
|
viteConfig,
|
|
3369
3329
|
serverBuildDirectory,
|
|
3370
3330
|
serverBuildFile
|
|
3371
3331
|
);
|
|
3372
|
-
let request = new Request(`http://localhost${reactRouterConfig.basename}
|
|
3332
|
+
let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
|
|
3333
|
+
headers: {
|
|
3334
|
+
// Enable SPA mode in the server runtime and only render down to the root
|
|
3335
|
+
"X-React-Router-SPA-Mode": "yes"
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3373
3338
|
let response = await handler(request);
|
|
3374
3339
|
let html = await response.text();
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3340
|
+
let isPrerenderSpaFallback = build.prerender.includes("/");
|
|
3341
|
+
let filename3 = isPrerenderSpaFallback ? "__spa-fallback__.html" : "index.html";
|
|
3342
|
+
if (response.status !== 200) {
|
|
3343
|
+
if (isPrerenderSpaFallback) {
|
|
3344
|
+
throw new Error(
|
|
3345
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3346
|
+
` + html
|
|
3347
|
+
);
|
|
3348
|
+
} else {
|
|
3349
|
+
throw new Error(
|
|
3350
|
+
`SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3351
|
+
` + html
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
|
|
3356
|
+
throw new Error(
|
|
3357
|
+
"SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
|
|
3358
|
+
);
|
|
3359
|
+
}
|
|
3360
|
+
await fse.writeFile(path6.join(clientBuildDirectory, filename3), html);
|
|
3361
|
+
let prettyDir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3362
|
+
let prettyPath = path6.join(prettyDir, filename3);
|
|
3363
|
+
let prefix = isPrerenderSpaFallback ? "Prerender" : "SPA Mode";
|
|
3364
|
+
viteConfig.logger.info(`${prefix}: Generated \`${prettyPath}\``);
|
|
3381
3365
|
}
|
|
3382
3366
|
async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
|
|
3383
3367
|
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
@@ -3386,29 +3370,22 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3386
3370
|
serverBuildPath
|
|
3387
3371
|
);
|
|
3388
3372
|
let routes = createPrerenderRoutes(build.routes);
|
|
3389
|
-
let
|
|
3390
|
-
if (typeof reactRouterConfig.prerender === "boolean") {
|
|
3391
|
-
invariant(reactRouterConfig.prerender, "Expected prerender:true");
|
|
3392
|
-
routesToPrerender = determineStaticPrerenderRoutes(
|
|
3393
|
-
routes,
|
|
3394
|
-
viteConfig,
|
|
3395
|
-
true
|
|
3396
|
-
);
|
|
3397
|
-
} else if (typeof reactRouterConfig.prerender === "function") {
|
|
3398
|
-
routesToPrerender = await reactRouterConfig.prerender({
|
|
3399
|
-
getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
|
|
3400
|
-
});
|
|
3401
|
-
} else {
|
|
3402
|
-
routesToPrerender = reactRouterConfig.prerender || ["/"];
|
|
3403
|
-
}
|
|
3373
|
+
let prerenderedRoutes = /* @__PURE__ */ new Set();
|
|
3404
3374
|
let headers = {
|
|
3405
3375
|
// Header that can be used in the loader to know if you're running at
|
|
3406
3376
|
// build time or runtime
|
|
3407
3377
|
"X-React-Router-Prerender": "yes"
|
|
3408
3378
|
};
|
|
3409
|
-
for (let path7 of
|
|
3379
|
+
for (let path7 of build.prerender) {
|
|
3410
3380
|
let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
|
|
3411
|
-
|
|
3381
|
+
invariant(
|
|
3382
|
+
matches,
|
|
3383
|
+
`Unable to prerender path because it does not match any routes: ${path7}`
|
|
3384
|
+
);
|
|
3385
|
+
matches.forEach((m) => prerenderedRoutes.add(m.route.id));
|
|
3386
|
+
let hasLoaders = matches.some(
|
|
3387
|
+
(m) => build.assets.routes[m.route.id]?.hasLoader
|
|
3388
|
+
);
|
|
3412
3389
|
let data;
|
|
3413
3390
|
if (hasLoaders) {
|
|
3414
3391
|
data = await prerenderData(
|
|
@@ -3448,14 +3425,34 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3448
3425
|
);
|
|
3449
3426
|
}
|
|
3450
3427
|
}
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3428
|
+
if (reactRouterConfig.ssr === false) {
|
|
3429
|
+
let errors = [];
|
|
3430
|
+
for (let [routeId, route] of Object.entries(build.routes)) {
|
|
3431
|
+
let invalidApis = [];
|
|
3432
|
+
if (route) {
|
|
3433
|
+
if (route.module.headers) invalidApis.push("headers");
|
|
3434
|
+
if (route.module.action) invalidApis.push("action");
|
|
3435
|
+
if (invalidApis.length > 0) {
|
|
3436
|
+
errors.push(
|
|
3437
|
+
`Prerender: ${invalidApis.length} invalid route export(s) in \`${route.id}\` when prerendering with \`ssr:false\`: ${invalidApis.join(", ")}. See https://reactrouter.com/how-to/spa for more information.`
|
|
3438
|
+
);
|
|
3439
|
+
}
|
|
3440
|
+
if (route.module.loader && !prerenderedRoutes.has(routeId)) {
|
|
3441
|
+
errors.push(
|
|
3442
|
+
`Prerender: 1 invalid route export in \`${route.id}\` when using \`ssr:false\` with \`prerender\` because the route is never prerendered so the loader will never be called. See https://reactrouter.com/how-to/spa for more information.`
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
if (errors.length > 0) {
|
|
3448
|
+
viteConfig.logger.error(errors.join("\n"));
|
|
3449
|
+
throw new Error(
|
|
3450
|
+
"Invalid route exports found when prerendering with `ssr:false`"
|
|
3451
|
+
);
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3457
3454
|
}
|
|
3458
|
-
function
|
|
3455
|
+
function getStaticPrerenderPaths(routes) {
|
|
3459
3456
|
let paths = ["/"];
|
|
3460
3457
|
let paramRoutes = [];
|
|
3461
3458
|
function recurse(subtree, prefix = "") {
|
|
@@ -3475,28 +3472,29 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
|
|
|
3475
3472
|
}
|
|
3476
3473
|
}
|
|
3477
3474
|
recurse(routes);
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
"You may want to use the `prerender()` API to prerender the following paths:",
|
|
3483
|
-
...paramRoutes.map((p) => " - " + p)
|
|
3484
|
-
].join("\n")
|
|
3485
|
-
);
|
|
3486
|
-
}
|
|
3487
|
-
return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
|
|
3475
|
+
return {
|
|
3476
|
+
paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
|
|
3477
|
+
paramRoutes
|
|
3478
|
+
};
|
|
3488
3479
|
}
|
|
3489
3480
|
async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3490
3481
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
|
|
3491
3482
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3492
3483
|
let response = await handler(request);
|
|
3493
3484
|
let data = await response.text();
|
|
3494
|
-
|
|
3485
|
+
if (response.status !== 200) {
|
|
3486
|
+
throw new Error(
|
|
3487
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
|
|
3488
|
+
${normalizedPath}`
|
|
3489
|
+
);
|
|
3490
|
+
}
|
|
3495
3491
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3496
3492
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3497
3493
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3498
3494
|
await fse.outputFile(outfile, data);
|
|
3499
|
-
viteConfig.logger.info(
|
|
3495
|
+
viteConfig.logger.info(
|
|
3496
|
+
`Prerender Data: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3497
|
+
);
|
|
3500
3498
|
return data;
|
|
3501
3499
|
}
|
|
3502
3500
|
async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
@@ -3507,54 +3505,83 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
|
|
|
3507
3505
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3508
3506
|
let response = await handler(request);
|
|
3509
3507
|
let html = await response.text();
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3508
|
+
if (response.status !== 200) {
|
|
3509
|
+
throw new Error(
|
|
3510
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3511
|
+
${html}`
|
|
3512
|
+
);
|
|
3513
3513
|
}
|
|
3514
3514
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3515
3515
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
|
|
3516
3516
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3517
3517
|
await fse.outputFile(outfile, html);
|
|
3518
|
-
viteConfig.logger.info(
|
|
3518
|
+
viteConfig.logger.info(
|
|
3519
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3520
|
+
);
|
|
3519
3521
|
}
|
|
3520
3522
|
async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3521
3523
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
|
|
3522
3524
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3523
3525
|
let response = await handler(request);
|
|
3524
3526
|
let text = await response.text();
|
|
3525
|
-
|
|
3527
|
+
if (response.status !== 200) {
|
|
3528
|
+
throw new Error(
|
|
3529
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3530
|
+
${text}`
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3526
3533
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3527
3534
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3528
3535
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3529
3536
|
await fse.outputFile(outfile, text);
|
|
3530
|
-
viteConfig.logger.info(
|
|
3531
|
-
}
|
|
3532
|
-
async function prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig) {
|
|
3533
|
-
let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(
|
|
3534
|
-
/\/\/+/g,
|
|
3535
|
-
"/"
|
|
3537
|
+
viteConfig.logger.info(
|
|
3538
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3536
3539
|
);
|
|
3537
|
-
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3538
|
-
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3539
|
-
await fse.ensureDir(path6.dirname(outfile));
|
|
3540
|
-
let manifestData = JSON.stringify(build.assets.routes);
|
|
3541
|
-
await fse.outputFile(outfile, manifestData);
|
|
3542
|
-
viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
|
|
3543
3540
|
}
|
|
3544
|
-
function
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3541
|
+
async function getPrerenderPaths(prerender, routes) {
|
|
3542
|
+
let prerenderPaths = [];
|
|
3543
|
+
if (prerender != null && prerender !== false) {
|
|
3544
|
+
let prerenderRoutes = createPrerenderRoutes(routes);
|
|
3545
|
+
if (prerender === true) {
|
|
3546
|
+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
|
|
3547
|
+
if (paramRoutes.length > 0) {
|
|
3548
|
+
console.warn(
|
|
3549
|
+
import_picocolors3.default.yellow(
|
|
3550
|
+
[
|
|
3551
|
+
"\u26A0\uFE0F Paths with dynamic/splat params cannot be prerendered when using `prerender: true`. You may want to use the `prerender()` API to prerender the following paths:",
|
|
3552
|
+
...paramRoutes.map((p) => " - " + p)
|
|
3553
|
+
].join("\n")
|
|
3554
|
+
)
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
prerenderPaths = paths;
|
|
3558
|
+
} else if (typeof prerender === "function") {
|
|
3559
|
+
prerenderPaths = await prerender({
|
|
3560
|
+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
|
|
3561
|
+
});
|
|
3562
|
+
} else {
|
|
3563
|
+
prerenderPaths = prerender || ["/"];
|
|
3564
|
+
}
|
|
3550
3565
|
}
|
|
3566
|
+
return prerenderPaths;
|
|
3551
3567
|
}
|
|
3552
|
-
function
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3568
|
+
function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
|
|
3569
|
+
return (routesByParentId[parentId] || []).map((route) => {
|
|
3570
|
+
let commonRoute = {
|
|
3571
|
+
id: route.id,
|
|
3572
|
+
path: route.path
|
|
3573
|
+
};
|
|
3574
|
+
if (route.index) {
|
|
3575
|
+
return {
|
|
3576
|
+
index: true,
|
|
3577
|
+
...commonRoute
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
return {
|
|
3581
|
+
children: createPrerenderRoutes(manifest, route.id, routesByParentId),
|
|
3582
|
+
...commonRoute
|
|
3583
|
+
};
|
|
3584
|
+
});
|
|
3558
3585
|
}
|
|
3559
3586
|
function groupRoutesByParentId2(manifest) {
|
|
3560
3587
|
let routes = {};
|
|
@@ -3569,26 +3596,54 @@ function groupRoutesByParentId2(manifest) {
|
|
|
3569
3596
|
});
|
|
3570
3597
|
return routes;
|
|
3571
3598
|
}
|
|
3572
|
-
function
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
}
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3599
|
+
function getAddressableRoutes(routes) {
|
|
3600
|
+
let nonAddressableIds = /* @__PURE__ */ new Set();
|
|
3601
|
+
for (let id in routes) {
|
|
3602
|
+
let route = routes[id];
|
|
3603
|
+
if (route.index) {
|
|
3604
|
+
invariant(
|
|
3605
|
+
route.parentId,
|
|
3606
|
+
`Expected index route "${route.id}" to have "parentId" set`
|
|
3607
|
+
);
|
|
3608
|
+
nonAddressableIds.add(route.parentId);
|
|
3609
|
+
}
|
|
3610
|
+
if (typeof route.path !== "string" && !route.index) {
|
|
3611
|
+
nonAddressableIds.add(id);
|
|
3612
|
+
}
|
|
3613
|
+
}
|
|
3614
|
+
return Object.values(routes).filter(
|
|
3615
|
+
(route) => !nonAddressableIds.has(route.id)
|
|
3616
|
+
);
|
|
3617
|
+
}
|
|
3618
|
+
function getRouteBranch(routes, routeId) {
|
|
3619
|
+
let branch = [];
|
|
3620
|
+
let currentRouteId = routeId;
|
|
3621
|
+
while (currentRouteId) {
|
|
3622
|
+
let route = routes[currentRouteId];
|
|
3623
|
+
invariant(route, `Missing route for ${currentRouteId}`);
|
|
3624
|
+
branch.push(route);
|
|
3625
|
+
currentRouteId = route.parentId;
|
|
3626
|
+
}
|
|
3627
|
+
return branch.reverse();
|
|
3628
|
+
}
|
|
3629
|
+
function hasServerBundles(buildManifest) {
|
|
3630
|
+
return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
|
|
3631
|
+
}
|
|
3632
|
+
function getRoutesByServerBundleId(buildManifest) {
|
|
3633
|
+
if (!buildManifest.routeIdToServerBundleId) {
|
|
3634
|
+
return {};
|
|
3635
|
+
}
|
|
3636
|
+
let routesByServerBundleId = {};
|
|
3637
|
+
for (let [routeId, serverBundleId] of Object.entries(
|
|
3638
|
+
buildManifest.routeIdToServerBundleId
|
|
3639
|
+
)) {
|
|
3640
|
+
routesByServerBundleId[serverBundleId] ??= {};
|
|
3641
|
+
let branch = getRouteBranch(buildManifest.routes, routeId);
|
|
3642
|
+
for (let route of branch) {
|
|
3643
|
+
routesByServerBundleId[serverBundleId][route.id] = route;
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
return routesByServerBundleId;
|
|
3592
3647
|
}
|
|
3593
3648
|
var resolveRouteFileCode = async (ctx, input) => {
|
|
3594
3649
|
if (typeof input === "string") return input;
|
|
@@ -3654,6 +3709,192 @@ function validateRouteChunks({
|
|
|
3654
3709
|
].join("\n\n")
|
|
3655
3710
|
);
|
|
3656
3711
|
}
|
|
3712
|
+
async function getBuildManifest(ctx) {
|
|
3713
|
+
let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
|
|
3714
|
+
if (!serverBundles) {
|
|
3715
|
+
return { routes };
|
|
3716
|
+
}
|
|
3717
|
+
let { normalizePath } = await import("vite");
|
|
3718
|
+
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
3719
|
+
let resolvedAppDirectory = path6.resolve(ctx.rootDirectory, appDirectory);
|
|
3720
|
+
let rootRelativeRoutes = Object.fromEntries(
|
|
3721
|
+
Object.entries(routes).map(([id, route]) => {
|
|
3722
|
+
let filePath = path6.join(resolvedAppDirectory, route.file);
|
|
3723
|
+
let rootRelativeFilePath = normalizePath(
|
|
3724
|
+
path6.relative(ctx.rootDirectory, filePath)
|
|
3725
|
+
);
|
|
3726
|
+
return [id, { ...route, file: rootRelativeFilePath }];
|
|
3727
|
+
})
|
|
3728
|
+
);
|
|
3729
|
+
let buildManifest = {
|
|
3730
|
+
serverBundles: {},
|
|
3731
|
+
routeIdToServerBundleId: {},
|
|
3732
|
+
routes: rootRelativeRoutes
|
|
3733
|
+
};
|
|
3734
|
+
await Promise.all(
|
|
3735
|
+
getAddressableRoutes(routes).map(async (route) => {
|
|
3736
|
+
let branch = getRouteBranch(routes, route.id);
|
|
3737
|
+
let serverBundleId = await serverBundles({
|
|
3738
|
+
branch: branch.map(
|
|
3739
|
+
(route2) => configRouteToBranchRoute({
|
|
3740
|
+
...route2,
|
|
3741
|
+
// Ensure absolute paths are passed to the serverBundles function
|
|
3742
|
+
file: path6.join(resolvedAppDirectory, route2.file)
|
|
3743
|
+
})
|
|
3744
|
+
)
|
|
3745
|
+
});
|
|
3746
|
+
if (typeof serverBundleId !== "string") {
|
|
3747
|
+
throw new Error(`The "serverBundles" function must return a string`);
|
|
3748
|
+
}
|
|
3749
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
|
|
3750
|
+
throw new Error(
|
|
3751
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
|
|
3755
|
+
buildManifest.serverBundles[serverBundleId] ??= {
|
|
3756
|
+
id: serverBundleId,
|
|
3757
|
+
file: normalizePath(
|
|
3758
|
+
path6.join(
|
|
3759
|
+
path6.relative(
|
|
3760
|
+
ctx.rootDirectory,
|
|
3761
|
+
path6.join(serverBuildDirectory, serverBundleId)
|
|
3762
|
+
),
|
|
3763
|
+
ctx.reactRouterConfig.serverBuildFile
|
|
3764
|
+
)
|
|
3765
|
+
)
|
|
3766
|
+
};
|
|
3767
|
+
})
|
|
3768
|
+
);
|
|
3769
|
+
return buildManifest;
|
|
3770
|
+
}
|
|
3771
|
+
function mergeBuildOptions(base, overrides) {
|
|
3772
|
+
let vite2 = getVite();
|
|
3773
|
+
return vite2.mergeConfig({ build: base }, { build: overrides }).build;
|
|
3774
|
+
}
|
|
3775
|
+
async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
|
|
3776
|
+
let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
|
|
3777
|
+
function getBaseBuildOptions({
|
|
3778
|
+
viteUserConfig
|
|
3779
|
+
}) {
|
|
3780
|
+
return {
|
|
3781
|
+
cssMinify: viteUserConfig.build?.cssMinify ?? true,
|
|
3782
|
+
manifest: true,
|
|
3783
|
+
// The manifest is enabled for all builds to detect SSR-only assets
|
|
3784
|
+
rollupOptions: {
|
|
3785
|
+
preserveEntrySignatures: "exports-only",
|
|
3786
|
+
// Silence Rollup "use client" warnings
|
|
3787
|
+
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
3788
|
+
onwarn(warning, defaultHandler) {
|
|
3789
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
3790
|
+
return;
|
|
3791
|
+
}
|
|
3792
|
+
let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
|
|
3793
|
+
if (userHandler) {
|
|
3794
|
+
userHandler(warning, defaultHandler);
|
|
3795
|
+
} else {
|
|
3796
|
+
defaultHandler(warning);
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
};
|
|
3801
|
+
}
|
|
3802
|
+
function getBaseServerBuildOptions({
|
|
3803
|
+
viteUserConfig
|
|
3804
|
+
}) {
|
|
3805
|
+
return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3806
|
+
// We move SSR-only assets to client assets. Note that the
|
|
3807
|
+
// SSR build can also emit code-split JS files (e.g. by
|
|
3808
|
+
// dynamic import) under the same assets directory
|
|
3809
|
+
// regardless of "ssrEmitAssets" option, so we also need to
|
|
3810
|
+
// keep these JS files have to be kept as-is.
|
|
3811
|
+
ssrEmitAssets: true,
|
|
3812
|
+
copyPublicDir: false,
|
|
3813
|
+
// Assets in the public directory are only used by the client
|
|
3814
|
+
rollupOptions: {
|
|
3815
|
+
output: {
|
|
3816
|
+
entryFileNames: serverBuildFile,
|
|
3817
|
+
format: serverModuleFormat
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
let environmentOptionsResolvers = {
|
|
3823
|
+
client: ({ viteUserConfig }) => ({
|
|
3824
|
+
build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3825
|
+
rollupOptions: {
|
|
3826
|
+
input: [
|
|
3827
|
+
ctx.entryClientFilePath,
|
|
3828
|
+
...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
|
|
3829
|
+
let routeFilePath = path6.resolve(
|
|
3830
|
+
ctx.reactRouterConfig.appDirectory,
|
|
3831
|
+
route.file
|
|
3832
|
+
);
|
|
3833
|
+
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
3834
|
+
let code = fse.readFileSync(routeFilePath, "utf-8");
|
|
3835
|
+
return [
|
|
3836
|
+
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
3837
|
+
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
3838
|
+
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
|
|
3839
|
+
) : []
|
|
3840
|
+
].filter(isNonNullable);
|
|
3841
|
+
})
|
|
3842
|
+
],
|
|
3843
|
+
output: {
|
|
3844
|
+
entryFileNames({ moduleIds }) {
|
|
3845
|
+
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
3846
|
+
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
|
|
3847
|
+
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
3848
|
+
return `assets/[name]${routeChunkSuffix}-[hash].js`;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
},
|
|
3852
|
+
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
3853
|
+
})
|
|
3854
|
+
})
|
|
3855
|
+
};
|
|
3856
|
+
if (hasServerBundles(buildManifest)) {
|
|
3857
|
+
for (let [serverBundleId, routes] of Object.entries(
|
|
3858
|
+
getRoutesByServerBundleId(buildManifest)
|
|
3859
|
+
)) {
|
|
3860
|
+
environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
|
|
3861
|
+
viteUserConfig
|
|
3862
|
+
}) => ({
|
|
3863
|
+
build: mergeBuildOptions(
|
|
3864
|
+
getBaseServerBuildOptions({ viteUserConfig }),
|
|
3865
|
+
{
|
|
3866
|
+
outDir: getServerBuildDirectory(ctx, { serverBundleId }),
|
|
3867
|
+
rollupOptions: {
|
|
3868
|
+
input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
|
|
3869
|
+
routes
|
|
3870
|
+
).join(",")}`
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
)
|
|
3874
|
+
});
|
|
3875
|
+
}
|
|
3876
|
+
} else {
|
|
3877
|
+
environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
|
|
3878
|
+
build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
|
|
3879
|
+
outDir: getServerBuildDirectory(ctx),
|
|
3880
|
+
rollupOptions: {
|
|
3881
|
+
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
|
|
3882
|
+
}
|
|
3883
|
+
})
|
|
3884
|
+
});
|
|
3885
|
+
}
|
|
3886
|
+
return environmentOptionsResolvers;
|
|
3887
|
+
}
|
|
3888
|
+
async function getEnvironmentOptions(ctx, environmentName, resolverOptions) {
|
|
3889
|
+
let buildManifest = await getBuildManifest(ctx);
|
|
3890
|
+
let environmentResolvers = await getEnvironmentOptionsResolvers(
|
|
3891
|
+
ctx,
|
|
3892
|
+
buildManifest
|
|
3893
|
+
);
|
|
3894
|
+
let resolver = environmentResolvers[environmentName];
|
|
3895
|
+
invariant(resolver, `Missing environment resolver for ${environmentName}`);
|
|
3896
|
+
return resolver(resolverOptions);
|
|
3897
|
+
}
|
|
3657
3898
|
function isNonNullable(x) {
|
|
3658
3899
|
return x != null;
|
|
3659
3900
|
}
|