Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/react-router-dev/vite/optimize-deps-entries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { escapePath as escapePathAsGlob } from "tinyglobby";
import type { ResolvedReactRouterConfig } from "../config/config";
import { resolveRelativeRouteFilePath } from "./resolve-relative-route-file-path";
import { getVite } from "./vite";

export function getOptimizeDepsEntries({
entryClientFilePath,
reactRouterConfig,
}: {
entryClientFilePath: string;
reactRouterConfig: ResolvedReactRouterConfig;
}) {
if (!reactRouterConfig.future.unstable_optimizeDeps) {
return [];
}

const vite = getVite();
const viteMajorVersion = parseInt(vite.version.split(".")[0], 10);

return [
vite.normalizePath(entryClientFilePath),
...Object.values(reactRouterConfig.routes).map((route) =>
resolveRelativeRouteFilePath(route, reactRouterConfig),
),
].map((entry) =>
// In Vite 7, the `optimizeDeps.entries` option only accepts glob patterns.
// In prior versions, absolute file paths were treated differently.
viteMajorVersion >= 7 ? escapePathAsGlob(entry) : entry,
);
}
30 changes: 6 additions & 24 deletions packages/react-router-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
} from "./styles";
import * as VirtualModule from "./virtual-module";
import { resolveFileUrl } from "./resolve-file-url";
import { resolveRelativeRouteFilePath } from "./resolve-relative-route-file-path";
import { combineURLs } from "./combine-urls";
import { removeExports } from "./remove-exports";
import { ssrExternals } from "./ssr-externals";
Expand All @@ -79,6 +80,7 @@ import {
resolveEntryFiles,
configRouteToBranchRoute,
} from "../config/config";
import { getOptimizeDepsEntries } from "./optimize-deps-entries";
import { decorateComponentExportsWithProps } from "./with-props";
import validatePluginOrder from "./plugins/validate-plugin-order";

Expand Down Expand Up @@ -263,17 +265,6 @@ const normalizeRelativeFilePath = (
return vite.normalizePath(relativePath).split("?")[0];
};

const resolveRelativeRouteFilePath = (
route: RouteManifestEntry,
reactRouterConfig: ResolvedReactRouterConfig,
) => {
let vite = getVite();
let file = route.file;
let fullPath = path.resolve(reactRouterConfig.appDirectory, file);

return vite.normalizePath(fullPath);
};

let virtual = {
serverBuild: VirtualModule.create("server-build"),
serverManifest: VirtualModule.create("server-manifest"),
Expand Down Expand Up @@ -1177,7 +1168,6 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {

// Ensure sync import of Vite works after async preload
let vite = getVite();
let viteMajorVersion = parseInt(vite.version.split(".")[0], 10);

viteUserConfig = _viteUserConfig;
viteConfigEnv = _viteConfigEnv;
Expand Down Expand Up @@ -1259,18 +1249,10 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
resolve: serverEnvironment.resolve,
},
optimizeDeps: {
entries: ctx.reactRouterConfig.future.unstable_optimizeDeps
? [
vite.normalizePath(ctx.entryClientFilePath),
...Object.values(ctx.reactRouterConfig.routes).map((route) =>
resolveRelativeRouteFilePath(route, ctx.reactRouterConfig),
),
].map((entry) =>
// In Vite 7, the `optimizeDeps.entries` option only accepts glob patterns.
// In prior versions, absolute file paths were treated differently.
viteMajorVersion >= 7 ? escapePathAsGlob(entry) : entry,
)
: [],
entries: getOptimizeDepsEntries({
entryClientFilePath: ctx.entryClientFilePath,
reactRouterConfig: ctx.reactRouterConfig,
}),
include: [
// Pre-bundle React dependencies to avoid React duplicates,
// even if React dependencies are not direct dependencies.
Expand Down
14 changes: 14 additions & 0 deletions packages/react-router-dev/vite/resolve-relative-route-file-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import path from "pathe";
import type { ResolvedReactRouterConfig } from "../config/config";
import type { RouteManifestEntry } from "../config/routes";
import { getVite } from "./vite";

export function resolveRelativeRouteFilePath(
route: RouteManifestEntry,
reactRouterConfig: ResolvedReactRouterConfig,
) {
let vite = getVite();
let file = route.file;
let fullPath = path.resolve(reactRouterConfig.appDirectory, file);
return vite.normalizePath(fullPath);
}
46 changes: 38 additions & 8 deletions packages/react-router-dev/vite/rsc/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import {
type ResolvedReactRouterConfig,
createConfigLoader,
} from "../../config/config";
import { preloadVite } from "../vite";
import { hasDependency } from "../has-dependency";
import { getOptimizeDepsEntries } from "../optimize-deps-entries";
import { createVirtualRouteConfig } from "./virtual-route-config";
import {
transformVirtualRouteModules,
Expand All @@ -38,6 +40,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
name: "react-router/rsc",
async config(viteUserConfig, { command, mode }) {
await initEsModuleLexer;
await preloadVite();

viteCommand = command;
const rootDirectory = getRootDirectory(viteUserConfig);
Expand Down Expand Up @@ -84,6 +87,10 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
],
},
optimizeDeps: {
entries: getOptimizeDepsEntries({
entryClientFilePath: defaultEntries.client,
reactRouterConfig: config,
}),
esbuildOptions: {
jsx: "automatic",
},
Expand All @@ -106,19 +113,46 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
environments: {
client: {
build: {
rollupOptions: { input: { index: virtual.clientEntry.id } },
rollupOptions: {
input: {
index: defaultEntries.client,
},
},
outDir: join(config.buildDirectory, "client"),
},
},
rsc: {
build: {
rollupOptions: { input: { index: virtual.rscEntry.id } },
rollupOptions: {
input: {
// We use a virtual entry here so that consumers can import
// it as `virtual:react-router/unstable_rsc/rsc-entry`
// without needing to know the actual file path, which is
// important when using the default entries.
index: defaultEntries.rsc,
},
output: {
entryFileNames: config.serverBuildFile,
format: config.serverModuleFormat,
},
},
outDir: join(config.buildDirectory, "server"),
},
},
ssr: {
build: {
rollupOptions: { input: { index: virtual.ssrEntry.id } },
rollupOptions: {
input: {
index: defaultEntries.ssr,
},
output: {
// Note: We don't set `entryFileNames` here because it's
// considered private to the RSC environment build, and
// @vitejs/plugin-rsc currently breaks if it's set to
// something other than `index.js`.
format: config.serverModuleFormat,
},
},
outDir: join(config.buildDirectory, "server/__ssr_build"),
},
},
Expand Down Expand Up @@ -223,11 +257,9 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
},

{
name: "react-router/rsc/virtual-entries",
name: "react-router/rsc/virtual-rsc-entry",
resolveId(id) {
if (id === virtual.rscEntry.id) return defaultEntries.rsc;
if (id === virtual.ssrEntry.id) return defaultEntries.ssr;
if (id === virtual.clientEntry.id) return defaultEntries.client;
},
},
{
Expand Down Expand Up @@ -433,8 +465,6 @@ const virtual = {
hmrRuntime: create("unstable_rsc/runtime"),
basename: create("unstable_rsc/basename"),
rscEntry: create("unstable_rsc/rsc-entry"),
ssrEntry: create("unstable_rsc/ssr-entry"),
clientEntry: create("unstable_rsc/client-entry"),
};

function invalidateVirtualModules(viteDevServer: Vite.ViteDevServer) {
Expand Down
Loading