Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route chunks: Add caching #11948

Merged
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
25 changes: 25 additions & 0 deletions packages/react-router-dev/vite/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type CacheEntry<T> = { value: T; version: string };

export type Cache = Map<string, CacheEntry<any>>;

export function getOrSetFromCache<T>(
cache: Cache,
key: string,
version: string,
getValue: () => T
): T {
if (!cache) {
return getValue();
}

let entry = cache.get(key) as CacheEntry<T> | undefined;

if (entry?.version === version) {
return entry.value as T;
}

let value = getValue();
let newEntry: CacheEntry<T> = { value, version };
cache.set(key, newEntry);
return value;
}
64 changes: 49 additions & 15 deletions packages/react-router-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type {
Manifest as ReactRouterManifest,
} from "../manifest";
import invariant from "../invariant";
import type { Cache } from "./cache";
import type { NodeRequestHandler } from "./node-adapter";
import { fromNodeRequest, toNodeRequest } from "./node-adapter";
import { getStylesForUrl, isCssModulesFile } from "./styles";
Expand Down Expand Up @@ -198,6 +199,17 @@ let browserManifestId = VirtualModule.id("browser-manifest");
let hmrRuntimeId = VirtualModule.id("hmr-runtime");
let injectHmrRuntimeId = VirtualModule.id("inject-hmr-runtime");

const normalizeRelativeFilePath = (
file: string,
reactRouterConfig: ResolvedReactRouterConfig
) => {
let vite = importViteEsmSync();
let fullPath = path.resolve(reactRouterConfig.appDirectory, file);
let relativePath = path.relative(reactRouterConfig.appDirectory, fullPath);

return vite.normalizePath(relativePath);
};

const resolveRelativeRouteFilePath = (
route: RouteManifestEntry,
reactRouterConfig: ResolvedReactRouterConfig
Expand Down Expand Up @@ -476,6 +488,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
let viteChildCompiler: Vite.ViteDevServer | null = null;
let routeConfigViteServer: Vite.ViteDevServer | null = null;
let viteNodeRunner: ViteNodeRunner | null = null;
let cache: Cache = new Map();

let ssrExternals = isInReactRouterMonorepo()
? [
Expand Down Expand Up @@ -673,7 +686,10 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
let hasClientLoader = sourceExports.includes("clientLoader");

let { hasClientActionChunk, hasClientLoaderChunk } =
await detectRouteChunksIfEnabled(ctx, { routeFile, viteChildCompiler });
await detectRouteChunksIfEnabled(cache, ctx, routeFile, {
routeFile,
viteChildCompiler,
});

let clientActionAssets = hasClientActionChunk
? getReactRouterManifestBuildAssets(
Expand Down Expand Up @@ -783,7 +799,10 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
);

let { hasClientActionChunk, hasClientLoaderChunk } =
await detectRouteChunksIfEnabled(ctx, { routeFile, viteChildCompiler });
await detectRouteChunksIfEnabled(cache, ctx, routeFile, {
routeFile,
viteChildCompiler,
});

routes[key] = {
id: route.id,
Expand Down Expand Up @@ -1390,8 +1409,13 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
routeModuleId
);

let { hasRouteChunks, hasClientActionChunk, hasClientLoaderChunk } =
await detectRouteChunksIfEnabled(ctx, code);
let {
hasRouteChunks = false,
hasClientActionChunk = false,
hasClientLoaderChunk = false,
} = options?.ssr
? {}
: await detectRouteChunksIfEnabled(cache, ctx, id, code);

let reexports = sourceExports
.filter(
Expand All @@ -1401,19 +1425,15 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
CLIENT_ROUTE_EXPORTS.includes(exportName)
)
.filter((exportName) =>
!options?.ssr && hasClientActionChunk
? exportName !== "clientAction"
: true
hasClientActionChunk ? exportName !== "clientAction" : true
)
.filter((exportName) =>
!options?.ssr && hasClientLoaderChunk
? exportName !== "clientLoader"
: true
hasClientLoaderChunk ? exportName !== "clientLoader" : true
)
.join(", ");

return `export { ${reexports} } from "./${routeFileName}${
!options?.ssr && hasRouteChunks ? MAIN_ROUTE_CHUNK_QUERY_STRING : ""
hasRouteChunks ? MAIN_ROUTE_CHUNK_QUERY_STRING : ""
}";`;
},
},
Expand All @@ -1426,7 +1446,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
// Ignore anything that isn't marked as a route chunk
if (!id.includes(ROUTE_CHUNK_QUERY_STRING)) return;

let chunks = await getRouteChunksIfEnabled(ctx, code);
let chunks = await getRouteChunksIfEnabled(cache, ctx, id, code);

if (chunks === null) {
return "// Route chunks disabled";
Expand Down Expand Up @@ -1713,6 +1733,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {

let oldRouteMetadata = serverManifest.routes[route.id];
let newRouteMetadata = await getRouteMetadata(
cache,
ctx,
viteChildCompiler,
route,
Expand Down Expand Up @@ -1899,6 +1920,7 @@ function getRoute(
}

async function getRouteMetadata(
cache: Cache,
ctx: ReactRouterPluginContext,
viteChildCompiler: Vite.ViteDevServer | null,
route: RouteManifestEntry,
Expand All @@ -1913,7 +1935,7 @@ async function getRouteMetadata(
);

let { hasClientActionChunk, hasClientLoaderChunk } =
await detectRouteChunksIfEnabled(ctx, {
await detectRouteChunksIfEnabled(cache, ctx, routeFile, {
routeFile,
readRouteFile,
viteChildCompiler,
Expand Down Expand Up @@ -2206,7 +2228,9 @@ const resolveRouteFileCode = async (
};

async function detectRouteChunksIfEnabled(
cache: Cache,
ctx: ReactRouterPluginContext,
id: string,
input: ResolveRouteFileCodeInput
): Promise<ReturnType<typeof detectRouteChunks>> {
if (!ctx.reactRouterConfig.future.unstable_routeChunks) {
Expand All @@ -2226,11 +2250,17 @@ async function detectRouteChunksIfEnabled(
};
}

return detectRouteChunks({ code });
let cacheKey =
normalizeRelativeFilePath(id, ctx.reactRouterConfig) +
(typeof input === "string" ? "" : "?read");

return detectRouteChunks(code, cache, cacheKey);
}

async function getRouteChunksIfEnabled(
cache: Cache,
ctx: ReactRouterPluginContext,
id: string,
input: ResolveRouteFileCodeInput
): Promise<ReturnType<typeof getRouteChunks> | null> {
if (!ctx.reactRouterConfig.future.unstable_routeChunks) {
Expand All @@ -2239,5 +2269,9 @@ async function getRouteChunksIfEnabled(

let code = await resolveRouteFileCode(ctx, input);

return getRouteChunks({ code });
let cacheKey =
normalizeRelativeFilePath(id, ctx.reactRouterConfig) +
(typeof input === "string" ? "" : "?read");

return getRouteChunks(code, cache, cacheKey);
}
Loading
Loading