@react-router/dev 0.0.0-experimental-a383e1e6e → 0.0.0-experimental-b9cf540fe
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 +9 -0
- package/bin.js +2 -2
- package/dist/cli/index.js +301 -159
- package/dist/config.js +1 -1
- package/dist/routes.js +1 -1
- package/dist/vite/cloudflare.js +1 -1
- package/dist/vite.js +462 -223
- 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-b9cf540fe
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -52,6 +52,7 @@ 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"));
|
|
57
58
|
var import_kebabCase = __toESM(require("lodash/kebabCase"));
|
|
@@ -271,6 +272,13 @@ var detectPackageManager = () => {
|
|
|
271
272
|
|
|
272
273
|
// config/config.ts
|
|
273
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);
|
|
274
282
|
var mergeReactRouterConfig = (...configs) => {
|
|
275
283
|
let reducer = (configA, configB) => {
|
|
276
284
|
let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
|
|
@@ -694,8 +702,6 @@ function generate(ctx, route) {
|
|
|
694
702
|
export type HeadersArgs = T.HeadersArgs
|
|
695
703
|
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
|
696
704
|
|
|
697
|
-
export type unstable_MiddlewareArgs = T.CreateServerMiddlewareArgs<Info>
|
|
698
|
-
export type unstable_ClientMiddlewareArgs = T.CreateClientMiddlewareArgs<Info>
|
|
699
705
|
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
|
700
706
|
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
|
701
707
|
export type ActionArgs = T.CreateServerActionArgs<Info>
|
|
@@ -1800,6 +1806,8 @@ var plugin = {
|
|
|
1800
1806
|
return function Wrapped() {
|
|
1801
1807
|
const props = {
|
|
1802
1808
|
params: useParams(),
|
|
1809
|
+
loaderData: useLoaderData(),
|
|
1810
|
+
actionData: useActionData(),
|
|
1803
1811
|
};
|
|
1804
1812
|
return h(HydrateFallback, props);
|
|
1805
1813
|
};
|
|
@@ -1893,27 +1901,18 @@ function toFunctionExpression(decl) {
|
|
|
1893
1901
|
}
|
|
1894
1902
|
|
|
1895
1903
|
// vite/plugin.ts
|
|
1896
|
-
var SERVER_ONLY_ROUTE_EXPORTS = [
|
|
1897
|
-
|
|
1898
|
-
"action",
|
|
1899
|
-
"unstable_middleware",
|
|
1900
|
-
"headers"
|
|
1901
|
-
];
|
|
1902
|
-
var CLIENT_ONLY_NON_COMPONENT_EXPORTS = [
|
|
1904
|
+
var SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
|
|
1905
|
+
var CLIENT_ROUTE_EXPORTS = [
|
|
1903
1906
|
"clientAction",
|
|
1904
1907
|
"clientLoader",
|
|
1905
|
-
"unstable_clientMiddleware",
|
|
1906
|
-
"handle",
|
|
1907
|
-
"meta",
|
|
1908
|
-
"links",
|
|
1909
|
-
"shouldRevalidate"
|
|
1910
|
-
];
|
|
1911
|
-
var CLIENT_ROUTE_EXPORTS = [
|
|
1912
|
-
...CLIENT_ONLY_NON_COMPONENT_EXPORTS,
|
|
1913
1908
|
"default",
|
|
1914
1909
|
"ErrorBoundary",
|
|
1910
|
+
"handle",
|
|
1915
1911
|
"HydrateFallback",
|
|
1916
|
-
"Layout"
|
|
1912
|
+
"Layout",
|
|
1913
|
+
"links",
|
|
1914
|
+
"meta",
|
|
1915
|
+
"shouldRevalidate"
|
|
1917
1916
|
];
|
|
1918
1917
|
var BUILD_CLIENT_ROUTE_QUERY_STRING = "?__react-router-build-client-route";
|
|
1919
1918
|
var isRouteEntryModuleId = (id) => {
|
|
@@ -2074,16 +2073,24 @@ var getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteF
|
|
|
2074
2073
|
);
|
|
2075
2074
|
return getExportNames(code);
|
|
2076
2075
|
};
|
|
2077
|
-
var
|
|
2078
|
-
|
|
2076
|
+
var resolveEnvironmentBuildContext = ({
|
|
2077
|
+
viteCommand,
|
|
2078
|
+
viteUserConfig
|
|
2079
|
+
}) => {
|
|
2080
|
+
if (!("__reactRouterEnvironmentBuildContext" in viteUserConfig) || !viteUserConfig.__reactRouterEnvironmentBuildContext) {
|
|
2079
2081
|
return null;
|
|
2080
2082
|
}
|
|
2081
|
-
|
|
2083
|
+
let buildContext = viteUserConfig.__reactRouterEnvironmentBuildContext;
|
|
2084
|
+
let resolvedBuildContext = {
|
|
2085
|
+
name: buildContext.name,
|
|
2086
|
+
options: buildContext.resolveOptions({ viteCommand, viteUserConfig })
|
|
2087
|
+
};
|
|
2088
|
+
return resolvedBuildContext;
|
|
2082
2089
|
};
|
|
2083
|
-
var getServerBuildDirectory = (ctx) => path6.join(
|
|
2090
|
+
var getServerBuildDirectory = (ctx, { serverBundleId } = {}) => path6.join(
|
|
2084
2091
|
ctx.reactRouterConfig.buildDirectory,
|
|
2085
2092
|
"server",
|
|
2086
|
-
...
|
|
2093
|
+
...serverBundleId ? [serverBundleId] : []
|
|
2087
2094
|
);
|
|
2088
2095
|
var getClientBuildDirectory = (reactRouterConfig) => path6.join(reactRouterConfig.buildDirectory, "client");
|
|
2089
2096
|
var defaultEntriesDir = path6.resolve(
|
|
@@ -2135,36 +2142,37 @@ var reactRouterVitePlugin = () => {
|
|
|
2135
2142
|
process.exit(1);
|
|
2136
2143
|
}
|
|
2137
2144
|
let viteManifestEnabled = viteUserConfig.build?.manifest === true;
|
|
2138
|
-
let
|
|
2139
|
-
isSsrBuild: true,
|
|
2140
|
-
getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
|
|
2141
|
-
serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
|
|
2142
|
-
} : { isSsrBuild: false };
|
|
2145
|
+
let environmentBuildContext = viteCommand === "build" ? resolveEnvironmentBuildContext({ viteCommand, viteUserConfig }) : null;
|
|
2143
2146
|
firstLoad = false;
|
|
2144
2147
|
ctx = {
|
|
2148
|
+
environmentBuildContext,
|
|
2145
2149
|
reactRouterConfig,
|
|
2146
2150
|
rootDirectory,
|
|
2147
2151
|
entryClientFilePath,
|
|
2148
2152
|
entryServerFilePath,
|
|
2149
2153
|
publicPath,
|
|
2150
|
-
viteManifestEnabled
|
|
2151
|
-
...ssrBuildCtx
|
|
2154
|
+
viteManifestEnabled
|
|
2152
2155
|
};
|
|
2153
2156
|
};
|
|
2154
2157
|
let pluginIndex = (pluginName) => {
|
|
2155
2158
|
invariant(viteConfig);
|
|
2156
2159
|
return viteConfig.plugins.findIndex((plugin2) => plugin2.name === pluginName);
|
|
2157
2160
|
};
|
|
2158
|
-
let getServerEntry = async () => {
|
|
2161
|
+
let getServerEntry = async ({ routeIds }) => {
|
|
2159
2162
|
invariant(viteConfig, "viteconfig required to generate the server entry");
|
|
2160
|
-
let routes =
|
|
2163
|
+
let routes = routeIds ? (
|
|
2161
2164
|
// For server bundle builds, the server build should only import the
|
|
2162
2165
|
// routes for this bundle rather than importing all routes
|
|
2163
|
-
ctx.
|
|
2166
|
+
(0, import_pick3.default)(ctx.reactRouterConfig.routes, routeIds)
|
|
2164
2167
|
) : (
|
|
2165
2168
|
// Otherwise, all routes are imported as usual
|
|
2166
2169
|
ctx.reactRouterConfig.routes
|
|
2167
2170
|
);
|
|
2171
|
+
let prerenderPaths = await getPrerenderPaths(
|
|
2172
|
+
ctx.reactRouterConfig.prerender,
|
|
2173
|
+
ctx.reactRouterConfig.ssr,
|
|
2174
|
+
routes
|
|
2175
|
+
);
|
|
2168
2176
|
return `
|
|
2169
2177
|
import * as entryServer from ${JSON.stringify(
|
|
2170
2178
|
resolveFileUrl(ctx, ctx.entryServerFilePath)
|
|
@@ -2179,7 +2187,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2179
2187
|
)};`;
|
|
2180
2188
|
}).join("\n")}
|
|
2181
2189
|
export { default as assets } from ${JSON.stringify(
|
|
2182
|
-
virtual.serverManifest.id
|
|
2190
|
+
`${virtual.serverManifest.id}${routeIds ? `?route-ids=${routeIds.join(",")}` : ""}`
|
|
2183
2191
|
)};
|
|
2184
2192
|
export const assetsBuildDirectory = ${JSON.stringify(
|
|
2185
2193
|
path6.relative(
|
|
@@ -2191,6 +2199,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2191
2199
|
export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
|
|
2192
2200
|
export const ssr = ${ctx.reactRouterConfig.ssr};
|
|
2193
2201
|
export const isSpaMode = ${isSpaModeEnabled(ctx.reactRouterConfig)};
|
|
2202
|
+
export const prerender = ${JSON.stringify(prerenderPaths)};
|
|
2194
2203
|
export const publicPath = ${JSON.stringify(ctx.publicPath)};
|
|
2195
2204
|
export const entry = { module: entryServer };
|
|
2196
2205
|
export const routes = {
|
|
@@ -2228,7 +2237,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2228
2237
|
);
|
|
2229
2238
|
return /* @__PURE__ */ new Set([...cssUrlPaths, ...chunkAssetPaths]);
|
|
2230
2239
|
};
|
|
2231
|
-
let generateReactRouterManifestsForBuild = async (
|
|
2240
|
+
let generateReactRouterManifestsForBuild = async ({
|
|
2241
|
+
routeIds
|
|
2242
|
+
}) => {
|
|
2232
2243
|
invariant(viteConfig);
|
|
2233
2244
|
let viteManifest = await loadViteManifest(
|
|
2234
2245
|
getClientBuildDirectory(ctx.reactRouterConfig)
|
|
@@ -2245,9 +2256,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2245
2256
|
ctx
|
|
2246
2257
|
);
|
|
2247
2258
|
let enforceSplitRouteModules = ctx.reactRouterConfig.future.unstable_splitRouteModules === "enforce";
|
|
2248
|
-
for (let
|
|
2259
|
+
for (let route of Object.values(ctx.reactRouterConfig.routes)) {
|
|
2249
2260
|
let routeFile = path6.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
2250
|
-
let sourceExports = routeManifestExports[
|
|
2261
|
+
let sourceExports = routeManifestExports[route.id];
|
|
2251
2262
|
let isRootRoute = route.parentId === void 0;
|
|
2252
2263
|
let hasClientAction = sourceExports.includes("clientAction");
|
|
2253
2264
|
let hasClientLoader = sourceExports.includes("clientLoader");
|
|
@@ -2305,10 +2316,9 @@ var reactRouterVitePlugin = () => {
|
|
|
2305
2316
|
getRouteChunkModuleId(routeFile, "HydrateFallback")
|
|
2306
2317
|
) : void 0
|
|
2307
2318
|
};
|
|
2308
|
-
browserRoutes[
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
serverRoutes[key] = routeManifestEntry;
|
|
2319
|
+
browserRoutes[route.id] = routeManifestEntry;
|
|
2320
|
+
if (!routeIds || routeIds.includes(route.id)) {
|
|
2321
|
+
serverRoutes[route.id] = routeManifestEntry;
|
|
2312
2322
|
}
|
|
2313
2323
|
}
|
|
2314
2324
|
let fingerprintedValues = { entry, routes: browserRoutes };
|
|
@@ -2456,23 +2466,6 @@ var reactRouterVitePlugin = () => {
|
|
|
2456
2466
|
""
|
|
2457
2467
|
)
|
|
2458
2468
|
);
|
|
2459
|
-
let baseRollupOptions = {
|
|
2460
|
-
// Silence Rollup "use client" warnings
|
|
2461
|
-
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
2462
|
-
onwarn(warning, defaultHandler) {
|
|
2463
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
2464
|
-
return;
|
|
2465
|
-
}
|
|
2466
|
-
if (viteUserConfig.build?.rollupOptions?.onwarn) {
|
|
2467
|
-
viteUserConfig.build.rollupOptions.onwarn(
|
|
2468
|
-
warning,
|
|
2469
|
-
defaultHandler
|
|
2470
|
-
);
|
|
2471
|
-
} else {
|
|
2472
|
-
defaultHandler(warning);
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
};
|
|
2476
2469
|
return {
|
|
2477
2470
|
__reactRouterPluginContext: ctx,
|
|
2478
2471
|
appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
|
|
@@ -2530,83 +2523,11 @@ var reactRouterVitePlugin = () => {
|
|
|
2530
2523
|
// will throw an error that the file is not allowed to be read.
|
|
2531
2524
|
// https://vitejs.dev/config/server-options#server-fs-allow
|
|
2532
2525
|
server: viteUserConfig.server?.fs?.allow ? { fs: { allow: defaultEntries } } : void 0,
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
manifest: true,
|
|
2539
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig),
|
|
2540
|
-
rollupOptions: {
|
|
2541
|
-
...baseRollupOptions,
|
|
2542
|
-
preserveEntrySignatures: "exports-only",
|
|
2543
|
-
output: {
|
|
2544
|
-
entryFileNames({ moduleIds }) {
|
|
2545
|
-
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
2546
|
-
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(
|
|
2547
|
-
routeChunkModuleId
|
|
2548
|
-
) : null;
|
|
2549
|
-
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
2550
|
-
return `assets/[name]${routeChunkSuffix}-[hash].js`;
|
|
2551
|
-
}
|
|
2552
|
-
},
|
|
2553
|
-
input: [
|
|
2554
|
-
ctx.entryClientFilePath,
|
|
2555
|
-
...Object.values(
|
|
2556
|
-
ctx.reactRouterConfig.routes
|
|
2557
|
-
).flatMap((route) => {
|
|
2558
|
-
let routeFilePath = path6.resolve(
|
|
2559
|
-
ctx.reactRouterConfig.appDirectory,
|
|
2560
|
-
route.file
|
|
2561
|
-
);
|
|
2562
|
-
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
2563
|
-
let code = fse.readFileSync(
|
|
2564
|
-
routeFilePath,
|
|
2565
|
-
"utf-8"
|
|
2566
|
-
);
|
|
2567
|
-
return [
|
|
2568
|
-
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
2569
|
-
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
2570
|
-
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(
|
|
2571
|
-
routeFilePath,
|
|
2572
|
-
exportName
|
|
2573
|
-
) : null
|
|
2574
|
-
) : []
|
|
2575
|
-
].filter(isNonNullable);
|
|
2576
|
-
})
|
|
2577
|
-
]
|
|
2578
|
-
}
|
|
2579
|
-
} : {
|
|
2580
|
-
// We move SSR-only assets to client assets. Note that the
|
|
2581
|
-
// SSR build can also emit code-split JS files (e.g. by
|
|
2582
|
-
// dynamic import) under the same assets directory
|
|
2583
|
-
// regardless of "ssrEmitAssets" option, so we also need to
|
|
2584
|
-
// keep these JS files have to be kept as-is.
|
|
2585
|
-
ssrEmitAssets: true,
|
|
2586
|
-
copyPublicDir: false,
|
|
2587
|
-
// Assets in the public directory are only used by the client
|
|
2588
|
-
manifest: true,
|
|
2589
|
-
// We need the manifest to detect SSR-only assets
|
|
2590
|
-
outDir: getServerBuildDirectory(ctx),
|
|
2591
|
-
rollupOptions: {
|
|
2592
|
-
...baseRollupOptions,
|
|
2593
|
-
preserveEntrySignatures: "exports-only",
|
|
2594
|
-
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id,
|
|
2595
|
-
output: {
|
|
2596
|
-
entryFileNames: ctx.reactRouterConfig.serverBuildFile,
|
|
2597
|
-
format: ctx.reactRouterConfig.serverModuleFormat
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
} : void 0,
|
|
2603
|
-
// Vite config options for SPA preview mode
|
|
2604
|
-
...viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
|
|
2605
|
-
build: {
|
|
2606
|
-
manifest: true,
|
|
2607
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
2608
|
-
}
|
|
2609
|
-
} : void 0
|
|
2526
|
+
build: ctx.environmentBuildContext?.options.build ?? (await getEnvironmentOptions(
|
|
2527
|
+
ctx,
|
|
2528
|
+
viteConfigEnv.isSsrBuild ? "ssr" : "client",
|
|
2529
|
+
{ viteCommand, viteUserConfig }
|
|
2530
|
+
)).build
|
|
2610
2531
|
};
|
|
2611
2532
|
},
|
|
2612
2533
|
async configResolved(resolvedViteConfig) {
|
|
@@ -2622,8 +2543,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2622
2543
|
let childCompilerConfigFile = await vite2.loadConfigFromFile(
|
|
2623
2544
|
{
|
|
2624
2545
|
command: viteConfig.command,
|
|
2625
|
-
mode: viteConfig.mode
|
|
2626
|
-
isSsrBuild: ctx.isSsrBuild
|
|
2546
|
+
mode: viteConfig.mode
|
|
2627
2547
|
},
|
|
2628
2548
|
viteConfig.configFile
|
|
2629
2549
|
);
|
|
@@ -2765,14 +2685,14 @@ var reactRouterVitePlugin = () => {
|
|
|
2765
2685
|
// After the SSR build is finished, we inspect the Vite manifest for
|
|
2766
2686
|
// the SSR build and move server-only assets to client assets directory
|
|
2767
2687
|
async handler() {
|
|
2768
|
-
if (!
|
|
2688
|
+
if (!viteConfigEnv.isSsrBuild) {
|
|
2769
2689
|
return;
|
|
2770
2690
|
}
|
|
2771
2691
|
invariant(viteConfig);
|
|
2772
2692
|
let clientBuildDirectory = getClientBuildDirectory(
|
|
2773
2693
|
ctx.reactRouterConfig
|
|
2774
2694
|
);
|
|
2775
|
-
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
2695
|
+
let serverBuildDirectory = ctx.environmentBuildContext?.options.build.outDir ?? getServerBuildDirectory(ctx);
|
|
2776
2696
|
let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
|
|
2777
2697
|
let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
|
|
2778
2698
|
let movedAssetPaths = [];
|
|
@@ -2806,7 +2726,7 @@ var reactRouterVitePlugin = () => {
|
|
|
2806
2726
|
].join("\n")
|
|
2807
2727
|
);
|
|
2808
2728
|
}
|
|
2809
|
-
if (ctx.reactRouterConfig
|
|
2729
|
+
if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
|
|
2810
2730
|
await handlePrerender(
|
|
2811
2731
|
viteConfig,
|
|
2812
2732
|
ctx.reactRouterConfig,
|
|
@@ -2961,16 +2881,25 @@ var reactRouterVitePlugin = () => {
|
|
|
2961
2881
|
name: "react-router:virtual-modules",
|
|
2962
2882
|
enforce: "pre",
|
|
2963
2883
|
resolveId(id) {
|
|
2964
|
-
|
|
2965
|
-
|
|
2884
|
+
let [baseId, queryString] = id.split("?");
|
|
2885
|
+
const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === baseId);
|
|
2886
|
+
if (vmod2)
|
|
2887
|
+
return vmod2.resolvedId + (queryString ? `?${queryString}` : "");
|
|
2966
2888
|
},
|
|
2967
2889
|
async load(id) {
|
|
2968
|
-
|
|
2890
|
+
let [baseId, queryString] = id.split("?");
|
|
2891
|
+
switch (baseId) {
|
|
2969
2892
|
case virtual.serverBuild.resolvedId: {
|
|
2970
|
-
|
|
2893
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2894
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2895
|
+
return await getServerEntry({ routeIds });
|
|
2971
2896
|
}
|
|
2972
2897
|
case virtual.serverManifest.resolvedId: {
|
|
2973
|
-
let
|
|
2898
|
+
let searchParams = new URLSearchParams(queryString);
|
|
2899
|
+
let routeIds = searchParams.get("route-ids")?.split(",") || void 0;
|
|
2900
|
+
let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
|
|
2901
|
+
routeIds
|
|
2902
|
+
})).reactRouterServerManifest : await getReactRouterManifestForDev();
|
|
2974
2903
|
return `export default ${(0, import_jsesc.default)(reactRouterManifest, {
|
|
2975
2904
|
es6: true
|
|
2976
2905
|
})};`;
|
|
@@ -3071,12 +3000,15 @@ var reactRouterVitePlugin = () => {
|
|
|
3071
3000
|
if (!route) return;
|
|
3072
3001
|
if (!options?.ssr && isSpaModeEnabled(ctx.reactRouterConfig)) {
|
|
3073
3002
|
let exportNames = getExportNames(code);
|
|
3074
|
-
let serverOnlyExports = exportNames.filter(
|
|
3075
|
-
(exp
|
|
3076
|
-
|
|
3003
|
+
let serverOnlyExports = exportNames.filter((exp) => {
|
|
3004
|
+
if (route.id === "root" && exp === "loader") {
|
|
3005
|
+
return false;
|
|
3006
|
+
}
|
|
3007
|
+
return SERVER_ONLY_ROUTE_EXPORTS.includes(exp);
|
|
3008
|
+
});
|
|
3077
3009
|
if (serverOnlyExports.length > 0) {
|
|
3078
3010
|
let str = serverOnlyExports.map((e) => `\`${e}\``).join(", ");
|
|
3079
|
-
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://
|
|
3011
|
+
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in \`${route.file}\`: ${str}. See https://reactrouter.com/how-to/spa for more information.`;
|
|
3080
3012
|
throw Error(message);
|
|
3081
3013
|
}
|
|
3082
3014
|
if (route.id !== "root") {
|
|
@@ -3084,7 +3016,7 @@ var reactRouterVitePlugin = () => {
|
|
|
3084
3016
|
(exp) => exp === "HydrateFallback"
|
|
3085
3017
|
);
|
|
3086
3018
|
if (hasHydrateFallback) {
|
|
3087
|
-
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in \`${route.file}\`. \`HydrateFallback\` is only permitted on the root route in SPA Mode. See https://
|
|
3019
|
+
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.`;
|
|
3088
3020
|
throw Error(message);
|
|
3089
3021
|
}
|
|
3090
3022
|
}
|
|
@@ -3271,7 +3203,14 @@ function uniqueNodes(nodes) {
|
|
|
3271
3203
|
}
|
|
3272
3204
|
function addRefreshWrapper(reactRouterConfig, code, id) {
|
|
3273
3205
|
let route = getRoute(reactRouterConfig, id);
|
|
3274
|
-
let acceptExports = route ?
|
|
3206
|
+
let acceptExports = route ? [
|
|
3207
|
+
"clientAction",
|
|
3208
|
+
"clientLoader",
|
|
3209
|
+
"handle",
|
|
3210
|
+
"meta",
|
|
3211
|
+
"links",
|
|
3212
|
+
"shouldRevalidate"
|
|
3213
|
+
] : [];
|
|
3275
3214
|
return REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id)) + code + REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route?.id));
|
|
3276
3215
|
}
|
|
3277
3216
|
var REACT_REFRESH_HEADER = `
|
|
@@ -3370,8 +3309,11 @@ async function getRouteMetadata(cache, ctx, viteChildCompiler, route, readRouteF
|
|
|
3370
3309
|
};
|
|
3371
3310
|
return info;
|
|
3372
3311
|
}
|
|
3312
|
+
function isPrerenderingEnabled(reactRouterConfig) {
|
|
3313
|
+
return reactRouterConfig.prerender != null && reactRouterConfig.prerender !== false;
|
|
3314
|
+
}
|
|
3373
3315
|
function isSpaModeEnabled(reactRouterConfig) {
|
|
3374
|
-
return reactRouterConfig.ssr === false && (reactRouterConfig
|
|
3316
|
+
return reactRouterConfig.ssr === false && !isPrerenderingEnabled(reactRouterConfig);
|
|
3375
3317
|
}
|
|
3376
3318
|
async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, serverBuildFile) {
|
|
3377
3319
|
let serverBuildPath = path6.join(serverBuildDirectory, serverBuildFile);
|
|
@@ -3383,20 +3325,44 @@ async function getPrerenderBuildAndHandler(viteConfig, serverBuildDirectory, ser
|
|
|
3383
3325
|
};
|
|
3384
3326
|
}
|
|
3385
3327
|
async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildFile, clientBuildDirectory) {
|
|
3386
|
-
let { handler } = await getPrerenderBuildAndHandler(
|
|
3328
|
+
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
3387
3329
|
viteConfig,
|
|
3388
3330
|
serverBuildDirectory,
|
|
3389
3331
|
serverBuildFile
|
|
3390
3332
|
);
|
|
3391
|
-
let request = new Request(`http://localhost${reactRouterConfig.basename}
|
|
3333
|
+
let request = new Request(`http://localhost${reactRouterConfig.basename}`, {
|
|
3334
|
+
headers: {
|
|
3335
|
+
// Enable SPA mode in the server runtime and only render down to the root
|
|
3336
|
+
"X-React-Router-SPA-Mode": "yes"
|
|
3337
|
+
}
|
|
3338
|
+
});
|
|
3392
3339
|
let response = await handler(request);
|
|
3393
3340
|
let html = await response.text();
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3341
|
+
let isPrerenderSpaFallback = build.prerender.includes("/");
|
|
3342
|
+
let filename3 = isPrerenderSpaFallback ? "__spa-fallback__.html" : "index.html";
|
|
3343
|
+
if (response.status !== 200) {
|
|
3344
|
+
if (isPrerenderSpaFallback) {
|
|
3345
|
+
throw new Error(
|
|
3346
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3347
|
+
` + html
|
|
3348
|
+
);
|
|
3349
|
+
} else {
|
|
3350
|
+
throw new Error(
|
|
3351
|
+
`SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
|
|
3352
|
+
` + html
|
|
3353
|
+
);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
|
|
3357
|
+
throw new Error(
|
|
3358
|
+
"SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
await fse.writeFile(path6.join(clientBuildDirectory, filename3), html);
|
|
3362
|
+
let prettyDir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3363
|
+
let prettyPath = path6.join(prettyDir, filename3);
|
|
3364
|
+
let prefix = isPrerenderSpaFallback ? "Prerender" : "SPA Mode";
|
|
3365
|
+
viteConfig.logger.info(`${prefix}: Generated \`${prettyPath}\``);
|
|
3400
3366
|
}
|
|
3401
3367
|
async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, serverBuildPath, clientBuildDirectory) {
|
|
3402
3368
|
let { build, handler } = await getPrerenderBuildAndHandler(
|
|
@@ -3405,29 +3371,22 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3405
3371
|
serverBuildPath
|
|
3406
3372
|
);
|
|
3407
3373
|
let routes = createPrerenderRoutes(build.routes);
|
|
3408
|
-
let
|
|
3409
|
-
if (typeof reactRouterConfig.prerender === "boolean") {
|
|
3410
|
-
invariant(reactRouterConfig.prerender, "Expected prerender:true");
|
|
3411
|
-
routesToPrerender = determineStaticPrerenderRoutes(
|
|
3412
|
-
routes,
|
|
3413
|
-
viteConfig,
|
|
3414
|
-
true
|
|
3415
|
-
);
|
|
3416
|
-
} else if (typeof reactRouterConfig.prerender === "function") {
|
|
3417
|
-
routesToPrerender = await reactRouterConfig.prerender({
|
|
3418
|
-
getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
|
|
3419
|
-
});
|
|
3420
|
-
} else {
|
|
3421
|
-
routesToPrerender = reactRouterConfig.prerender || ["/"];
|
|
3422
|
-
}
|
|
3374
|
+
let prerenderedRoutes = /* @__PURE__ */ new Set();
|
|
3423
3375
|
let headers = {
|
|
3424
3376
|
// Header that can be used in the loader to know if you're running at
|
|
3425
3377
|
// build time or runtime
|
|
3426
3378
|
"X-React-Router-Prerender": "yes"
|
|
3427
3379
|
};
|
|
3428
|
-
for (let path7 of
|
|
3380
|
+
for (let path7 of build.prerender) {
|
|
3429
3381
|
let matches = (0, import_react_router2.matchRoutes)(routes, `/${path7}/`.replace(/^\/\/+/, "/"));
|
|
3430
|
-
|
|
3382
|
+
invariant(
|
|
3383
|
+
matches,
|
|
3384
|
+
`Unable to prerender path because it does not match any routes: ${path7}`
|
|
3385
|
+
);
|
|
3386
|
+
matches.forEach((m) => prerenderedRoutes.add(m.route.id));
|
|
3387
|
+
let hasLoaders = matches.some(
|
|
3388
|
+
(m) => build.assets.routes[m.route.id]?.hasLoader
|
|
3389
|
+
);
|
|
3431
3390
|
let data;
|
|
3432
3391
|
if (hasLoaders) {
|
|
3433
3392
|
data = await prerenderData(
|
|
@@ -3467,8 +3426,34 @@ async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirecto
|
|
|
3467
3426
|
);
|
|
3468
3427
|
}
|
|
3469
3428
|
}
|
|
3429
|
+
if (reactRouterConfig.ssr === false) {
|
|
3430
|
+
let errors = [];
|
|
3431
|
+
for (let [routeId, route] of Object.entries(build.routes)) {
|
|
3432
|
+
let invalidApis = [];
|
|
3433
|
+
if (route) {
|
|
3434
|
+
if (route.module.headers) invalidApis.push("headers");
|
|
3435
|
+
if (route.module.action) invalidApis.push("action");
|
|
3436
|
+
if (invalidApis.length > 0) {
|
|
3437
|
+
errors.push(
|
|
3438
|
+
`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.`
|
|
3439
|
+
);
|
|
3440
|
+
}
|
|
3441
|
+
if (route.module.loader && !prerenderedRoutes.has(routeId)) {
|
|
3442
|
+
errors.push(
|
|
3443
|
+
`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.`
|
|
3444
|
+
);
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
if (errors.length > 0) {
|
|
3449
|
+
viteConfig.logger.error(errors.join("\n"));
|
|
3450
|
+
throw new Error(
|
|
3451
|
+
"Invalid route exports found when prerendering with `ssr:false`"
|
|
3452
|
+
);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3470
3455
|
}
|
|
3471
|
-
function
|
|
3456
|
+
function getStaticPrerenderPaths(routes) {
|
|
3472
3457
|
let paths = ["/"];
|
|
3473
3458
|
let paramRoutes = [];
|
|
3474
3459
|
function recurse(subtree, prefix = "") {
|
|
@@ -3488,28 +3473,29 @@ function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = fal
|
|
|
3488
3473
|
}
|
|
3489
3474
|
}
|
|
3490
3475
|
recurse(routes);
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
"You may want to use the `prerender()` API to prerender the following paths:",
|
|
3496
|
-
...paramRoutes.map((p) => " - " + p)
|
|
3497
|
-
].join("\n")
|
|
3498
|
-
);
|
|
3499
|
-
}
|
|
3500
|
-
return paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
|
|
3476
|
+
return {
|
|
3477
|
+
paths: paths.map((p) => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1")),
|
|
3478
|
+
paramRoutes
|
|
3479
|
+
};
|
|
3501
3480
|
}
|
|
3502
3481
|
async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3503
3482
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
|
|
3504
3483
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3505
3484
|
let response = await handler(request);
|
|
3506
3485
|
let data = await response.text();
|
|
3507
|
-
|
|
3486
|
+
if (response.status !== 200) {
|
|
3487
|
+
throw new Error(
|
|
3488
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${path6}\` path.
|
|
3489
|
+
${normalizedPath}`
|
|
3490
|
+
);
|
|
3491
|
+
}
|
|
3508
3492
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3509
3493
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3510
3494
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3511
3495
|
await fse.outputFile(outfile, data);
|
|
3512
|
-
viteConfig.logger.info(
|
|
3496
|
+
viteConfig.logger.info(
|
|
3497
|
+
`Prerender Data: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3498
|
+
);
|
|
3513
3499
|
return data;
|
|
3514
3500
|
}
|
|
3515
3501
|
async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
@@ -3520,42 +3506,65 @@ async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reac
|
|
|
3520
3506
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3521
3507
|
let response = await handler(request);
|
|
3522
3508
|
let html = await response.text();
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3509
|
+
if (response.status !== 200) {
|
|
3510
|
+
throw new Error(
|
|
3511
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3512
|
+
${html}`
|
|
3513
|
+
);
|
|
3526
3514
|
}
|
|
3527
3515
|
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3528
3516
|
let outfile = path6.join(outdir, ...normalizedPath.split("/"), "index.html");
|
|
3529
3517
|
await fse.ensureDir(path6.dirname(outfile));
|
|
3530
3518
|
await fse.outputFile(outfile, html);
|
|
3531
|
-
viteConfig.logger.info(
|
|
3519
|
+
viteConfig.logger.info(
|
|
3520
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3521
|
+
);
|
|
3532
3522
|
}
|
|
3533
3523
|
async function prerenderResourceRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
3534
3524
|
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/").replace(/\/$/g, "");
|
|
3535
3525
|
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
3536
3526
|
let response = await handler(request);
|
|
3537
3527
|
let text = await response.text();
|
|
3538
|
-
validatePrerenderedResponse(response, text, "Prerender", normalizedPath);
|
|
3539
|
-
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3540
|
-
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3541
|
-
await fse.ensureDir(path6.dirname(outfile));
|
|
3542
|
-
await fse.outputFile(outfile, text);
|
|
3543
|
-
viteConfig.logger.info(`Prerender: Generated ${import_picocolors3.default.bold(outfile)}`);
|
|
3544
|
-
}
|
|
3545
|
-
function validatePrerenderedResponse(response, html, prefix, path7) {
|
|
3546
3528
|
if (response.status !== 200) {
|
|
3547
3529
|
throw new Error(
|
|
3548
|
-
|
|
3549
|
-
${
|
|
3530
|
+
`Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering the \`${normalizedPath}\` path.
|
|
3531
|
+
${text}`
|
|
3550
3532
|
);
|
|
3551
3533
|
}
|
|
3534
|
+
let outdir = path6.relative(process.cwd(), clientBuildDirectory);
|
|
3535
|
+
let outfile = path6.join(outdir, ...normalizedPath.split("/"));
|
|
3536
|
+
await fse.ensureDir(path6.dirname(outfile));
|
|
3537
|
+
await fse.outputFile(outfile, text);
|
|
3538
|
+
viteConfig.logger.info(
|
|
3539
|
+
`Prerender: ${prerenderPath} -> ${import_picocolors3.default.bold(outfile)}`
|
|
3540
|
+
);
|
|
3552
3541
|
}
|
|
3553
|
-
function
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
)
|
|
3542
|
+
async function getPrerenderPaths(prerender, ssr, routes) {
|
|
3543
|
+
let prerenderPaths = [];
|
|
3544
|
+
if (prerender != null && prerender !== false) {
|
|
3545
|
+
let prerenderRoutes = createPrerenderRoutes(routes);
|
|
3546
|
+
if (prerender === true) {
|
|
3547
|
+
let { paths, paramRoutes } = getStaticPrerenderPaths(prerenderRoutes);
|
|
3548
|
+
if (!ssr && paramRoutes.length > 0) {
|
|
3549
|
+
console.warn(
|
|
3550
|
+
import_picocolors3.default.yellow(
|
|
3551
|
+
[
|
|
3552
|
+
"\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:",
|
|
3553
|
+
...paramRoutes.map((p) => " - " + p)
|
|
3554
|
+
].join("\n")
|
|
3555
|
+
)
|
|
3556
|
+
);
|
|
3557
|
+
}
|
|
3558
|
+
prerenderPaths = paths;
|
|
3559
|
+
} else if (typeof prerender === "function") {
|
|
3560
|
+
prerenderPaths = await prerender({
|
|
3561
|
+
getStaticPaths: () => getStaticPrerenderPaths(prerenderRoutes).paths
|
|
3562
|
+
});
|
|
3563
|
+
} else {
|
|
3564
|
+
prerenderPaths = prerender || ["/"];
|
|
3565
|
+
}
|
|
3558
3566
|
}
|
|
3567
|
+
return prerenderPaths;
|
|
3559
3568
|
}
|
|
3560
3569
|
function groupRoutesByParentId2(manifest) {
|
|
3561
3570
|
let routes = {};
|
|
@@ -3573,26 +3582,70 @@ function groupRoutesByParentId2(manifest) {
|
|
|
3573
3582
|
function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
|
|
3574
3583
|
return (routesByParentId[parentId] || []).map((route) => {
|
|
3575
3584
|
let commonRoute = {
|
|
3576
|
-
// Always include root due to default boundaries
|
|
3577
|
-
hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
|
|
3578
3585
|
id: route.id,
|
|
3579
|
-
path: route.path
|
|
3580
|
-
loader: route.module.loader ? () => null : void 0,
|
|
3581
|
-
action: void 0,
|
|
3582
|
-
handle: route.module.handle
|
|
3583
|
-
// middleware is not necessary here since we just need to know which
|
|
3584
|
-
// routes have loaders so we know what paths to prerender
|
|
3586
|
+
path: route.path
|
|
3585
3587
|
};
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3588
|
+
if (route.index) {
|
|
3589
|
+
return {
|
|
3590
|
+
index: true,
|
|
3591
|
+
...commonRoute
|
|
3592
|
+
};
|
|
3593
|
+
}
|
|
3594
|
+
return {
|
|
3591
3595
|
children: createPrerenderRoutes(manifest, route.id, routesByParentId),
|
|
3592
3596
|
...commonRoute
|
|
3593
3597
|
};
|
|
3594
3598
|
});
|
|
3595
3599
|
}
|
|
3600
|
+
function getAddressableRoutes(routes) {
|
|
3601
|
+
let nonAddressableIds = /* @__PURE__ */ new Set();
|
|
3602
|
+
for (let id in routes) {
|
|
3603
|
+
let route = routes[id];
|
|
3604
|
+
if (route.index) {
|
|
3605
|
+
invariant(
|
|
3606
|
+
route.parentId,
|
|
3607
|
+
`Expected index route "${route.id}" to have "parentId" set`
|
|
3608
|
+
);
|
|
3609
|
+
nonAddressableIds.add(route.parentId);
|
|
3610
|
+
}
|
|
3611
|
+
if (typeof route.path !== "string" && !route.index) {
|
|
3612
|
+
nonAddressableIds.add(id);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
return Object.values(routes).filter(
|
|
3616
|
+
(route) => !nonAddressableIds.has(route.id)
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
function getRouteBranch(routes, routeId) {
|
|
3620
|
+
let branch = [];
|
|
3621
|
+
let currentRouteId = routeId;
|
|
3622
|
+
while (currentRouteId) {
|
|
3623
|
+
let route = routes[currentRouteId];
|
|
3624
|
+
invariant(route, `Missing route for ${currentRouteId}`);
|
|
3625
|
+
branch.push(route);
|
|
3626
|
+
currentRouteId = route.parentId;
|
|
3627
|
+
}
|
|
3628
|
+
return branch.reverse();
|
|
3629
|
+
}
|
|
3630
|
+
function hasServerBundles(buildManifest) {
|
|
3631
|
+
return Object.keys(buildManifest.serverBundles ?? {}).length > 0;
|
|
3632
|
+
}
|
|
3633
|
+
function getRoutesByServerBundleId(buildManifest) {
|
|
3634
|
+
if (!buildManifest.routeIdToServerBundleId) {
|
|
3635
|
+
return {};
|
|
3636
|
+
}
|
|
3637
|
+
let routesByServerBundleId = {};
|
|
3638
|
+
for (let [routeId, serverBundleId] of Object.entries(
|
|
3639
|
+
buildManifest.routeIdToServerBundleId
|
|
3640
|
+
)) {
|
|
3641
|
+
routesByServerBundleId[serverBundleId] ??= {};
|
|
3642
|
+
let branch = getRouteBranch(buildManifest.routes, routeId);
|
|
3643
|
+
for (let route of branch) {
|
|
3644
|
+
routesByServerBundleId[serverBundleId][route.id] = route;
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
return routesByServerBundleId;
|
|
3648
|
+
}
|
|
3596
3649
|
var resolveRouteFileCode = async (ctx, input) => {
|
|
3597
3650
|
if (typeof input === "string") return input;
|
|
3598
3651
|
invariant(input.viteChildCompiler);
|
|
@@ -3657,6 +3710,192 @@ function validateRouteChunks({
|
|
|
3657
3710
|
].join("\n\n")
|
|
3658
3711
|
);
|
|
3659
3712
|
}
|
|
3713
|
+
async function getBuildManifest(ctx) {
|
|
3714
|
+
let { routes, serverBundles, appDirectory } = ctx.reactRouterConfig;
|
|
3715
|
+
if (!serverBundles) {
|
|
3716
|
+
return { routes };
|
|
3717
|
+
}
|
|
3718
|
+
let { normalizePath } = await import("vite");
|
|
3719
|
+
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
3720
|
+
let resolvedAppDirectory = path6.resolve(ctx.rootDirectory, appDirectory);
|
|
3721
|
+
let rootRelativeRoutes = Object.fromEntries(
|
|
3722
|
+
Object.entries(routes).map(([id, route]) => {
|
|
3723
|
+
let filePath = path6.join(resolvedAppDirectory, route.file);
|
|
3724
|
+
let rootRelativeFilePath = normalizePath(
|
|
3725
|
+
path6.relative(ctx.rootDirectory, filePath)
|
|
3726
|
+
);
|
|
3727
|
+
return [id, { ...route, file: rootRelativeFilePath }];
|
|
3728
|
+
})
|
|
3729
|
+
);
|
|
3730
|
+
let buildManifest = {
|
|
3731
|
+
serverBundles: {},
|
|
3732
|
+
routeIdToServerBundleId: {},
|
|
3733
|
+
routes: rootRelativeRoutes
|
|
3734
|
+
};
|
|
3735
|
+
await Promise.all(
|
|
3736
|
+
getAddressableRoutes(routes).map(async (route) => {
|
|
3737
|
+
let branch = getRouteBranch(routes, route.id);
|
|
3738
|
+
let serverBundleId = await serverBundles({
|
|
3739
|
+
branch: branch.map(
|
|
3740
|
+
(route2) => configRouteToBranchRoute({
|
|
3741
|
+
...route2,
|
|
3742
|
+
// Ensure absolute paths are passed to the serverBundles function
|
|
3743
|
+
file: path6.join(resolvedAppDirectory, route2.file)
|
|
3744
|
+
})
|
|
3745
|
+
)
|
|
3746
|
+
});
|
|
3747
|
+
if (typeof serverBundleId !== "string") {
|
|
3748
|
+
throw new Error(`The "serverBundles" function must return a string`);
|
|
3749
|
+
}
|
|
3750
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(serverBundleId)) {
|
|
3751
|
+
throw new Error(
|
|
3752
|
+
`The "serverBundles" function must only return strings containing alphanumeric characters, hyphens and underscores.`
|
|
3753
|
+
);
|
|
3754
|
+
}
|
|
3755
|
+
buildManifest.routeIdToServerBundleId[route.id] = serverBundleId;
|
|
3756
|
+
buildManifest.serverBundles[serverBundleId] ??= {
|
|
3757
|
+
id: serverBundleId,
|
|
3758
|
+
file: normalizePath(
|
|
3759
|
+
path6.join(
|
|
3760
|
+
path6.relative(
|
|
3761
|
+
ctx.rootDirectory,
|
|
3762
|
+
path6.join(serverBuildDirectory, serverBundleId)
|
|
3763
|
+
),
|
|
3764
|
+
ctx.reactRouterConfig.serverBuildFile
|
|
3765
|
+
)
|
|
3766
|
+
)
|
|
3767
|
+
};
|
|
3768
|
+
})
|
|
3769
|
+
);
|
|
3770
|
+
return buildManifest;
|
|
3771
|
+
}
|
|
3772
|
+
function mergeBuildOptions(base, overrides) {
|
|
3773
|
+
let vite2 = getVite();
|
|
3774
|
+
return vite2.mergeConfig({ build: base }, { build: overrides }).build;
|
|
3775
|
+
}
|
|
3776
|
+
async function getEnvironmentOptionsResolvers(ctx, buildManifest) {
|
|
3777
|
+
let { serverBuildFile, serverModuleFormat } = ctx.reactRouterConfig;
|
|
3778
|
+
function getBaseBuildOptions({
|
|
3779
|
+
viteUserConfig
|
|
3780
|
+
}) {
|
|
3781
|
+
return {
|
|
3782
|
+
cssMinify: viteUserConfig.build?.cssMinify ?? true,
|
|
3783
|
+
manifest: true,
|
|
3784
|
+
// The manifest is enabled for all builds to detect SSR-only assets
|
|
3785
|
+
rollupOptions: {
|
|
3786
|
+
preserveEntrySignatures: "exports-only",
|
|
3787
|
+
// Silence Rollup "use client" warnings
|
|
3788
|
+
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
3789
|
+
onwarn(warning, defaultHandler) {
|
|
3790
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
let userHandler = viteUserConfig.build?.rollupOptions?.onwarn;
|
|
3794
|
+
if (userHandler) {
|
|
3795
|
+
userHandler(warning, defaultHandler);
|
|
3796
|
+
} else {
|
|
3797
|
+
defaultHandler(warning);
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
function getBaseServerBuildOptions({
|
|
3804
|
+
viteUserConfig
|
|
3805
|
+
}) {
|
|
3806
|
+
return mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3807
|
+
// We move SSR-only assets to client assets. Note that the
|
|
3808
|
+
// SSR build can also emit code-split JS files (e.g. by
|
|
3809
|
+
// dynamic import) under the same assets directory
|
|
3810
|
+
// regardless of "ssrEmitAssets" option, so we also need to
|
|
3811
|
+
// keep these JS files have to be kept as-is.
|
|
3812
|
+
ssrEmitAssets: true,
|
|
3813
|
+
copyPublicDir: false,
|
|
3814
|
+
// Assets in the public directory are only used by the client
|
|
3815
|
+
rollupOptions: {
|
|
3816
|
+
output: {
|
|
3817
|
+
entryFileNames: serverBuildFile,
|
|
3818
|
+
format: serverModuleFormat
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
});
|
|
3822
|
+
}
|
|
3823
|
+
let environmentOptionsResolvers = {
|
|
3824
|
+
client: ({ viteUserConfig }) => ({
|
|
3825
|
+
build: mergeBuildOptions(getBaseBuildOptions({ viteUserConfig }), {
|
|
3826
|
+
rollupOptions: {
|
|
3827
|
+
input: [
|
|
3828
|
+
ctx.entryClientFilePath,
|
|
3829
|
+
...Object.values(ctx.reactRouterConfig.routes).flatMap((route) => {
|
|
3830
|
+
let routeFilePath = path6.resolve(
|
|
3831
|
+
ctx.reactRouterConfig.appDirectory,
|
|
3832
|
+
route.file
|
|
3833
|
+
);
|
|
3834
|
+
let isRootRoute = route.file === ctx.reactRouterConfig.routes.root.file;
|
|
3835
|
+
let code = fse.readFileSync(routeFilePath, "utf-8");
|
|
3836
|
+
return [
|
|
3837
|
+
`${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
3838
|
+
...ctx.reactRouterConfig.future.unstable_splitRouteModules && !isRootRoute ? routeChunkExportNames.map(
|
|
3839
|
+
(exportName) => code.includes(exportName) ? getRouteChunkModuleId(routeFilePath, exportName) : null
|
|
3840
|
+
) : []
|
|
3841
|
+
].filter(isNonNullable);
|
|
3842
|
+
})
|
|
3843
|
+
],
|
|
3844
|
+
output: {
|
|
3845
|
+
entryFileNames({ moduleIds }) {
|
|
3846
|
+
let routeChunkModuleId = moduleIds.find(isRouteChunkModuleId);
|
|
3847
|
+
let routeChunkName = routeChunkModuleId ? getRouteChunkNameFromModuleId(routeChunkModuleId) : null;
|
|
3848
|
+
let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
|
|
3849
|
+
return `assets/[name]${routeChunkSuffix}-[hash].js`;
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
},
|
|
3853
|
+
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
3854
|
+
})
|
|
3855
|
+
})
|
|
3856
|
+
};
|
|
3857
|
+
if (hasServerBundles(buildManifest)) {
|
|
3858
|
+
for (let [serverBundleId, routes] of Object.entries(
|
|
3859
|
+
getRoutesByServerBundleId(buildManifest)
|
|
3860
|
+
)) {
|
|
3861
|
+
environmentOptionsResolvers[`ssr-bundle-${serverBundleId}`] = ({
|
|
3862
|
+
viteUserConfig
|
|
3863
|
+
}) => ({
|
|
3864
|
+
build: mergeBuildOptions(
|
|
3865
|
+
getBaseServerBuildOptions({ viteUserConfig }),
|
|
3866
|
+
{
|
|
3867
|
+
outDir: getServerBuildDirectory(ctx, { serverBundleId }),
|
|
3868
|
+
rollupOptions: {
|
|
3869
|
+
input: `${virtual.serverBuild.id}?route-ids=${Object.keys(
|
|
3870
|
+
routes
|
|
3871
|
+
).join(",")}`
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
)
|
|
3875
|
+
});
|
|
3876
|
+
}
|
|
3877
|
+
} else {
|
|
3878
|
+
environmentOptionsResolvers.ssr = ({ viteUserConfig }) => ({
|
|
3879
|
+
build: mergeBuildOptions(getBaseServerBuildOptions({ viteUserConfig }), {
|
|
3880
|
+
outDir: getServerBuildDirectory(ctx),
|
|
3881
|
+
rollupOptions: {
|
|
3882
|
+
input: viteUserConfig.build?.rollupOptions?.input ?? virtual.serverBuild.id
|
|
3883
|
+
}
|
|
3884
|
+
})
|
|
3885
|
+
});
|
|
3886
|
+
}
|
|
3887
|
+
return environmentOptionsResolvers;
|
|
3888
|
+
}
|
|
3889
|
+
async function getEnvironmentOptions(ctx, environmentName, resolverOptions) {
|
|
3890
|
+
let buildManifest = await getBuildManifest(ctx);
|
|
3891
|
+
let environmentResolvers = await getEnvironmentOptionsResolvers(
|
|
3892
|
+
ctx,
|
|
3893
|
+
buildManifest
|
|
3894
|
+
);
|
|
3895
|
+
let resolver = environmentResolvers[environmentName];
|
|
3896
|
+
invariant(resolver, `Missing environment resolver for ${environmentName}`);
|
|
3897
|
+
return resolver(resolverOptions);
|
|
3898
|
+
}
|
|
3660
3899
|
function isNonNullable(x) {
|
|
3661
3900
|
return x != null;
|
|
3662
3901
|
}
|