mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
[remix] Allow runtime to be defined from a parent route (#9473)
Make it so that the `export const config = { runtime }` value is "inherited" from a parent route, if it is defined.
For example, "edge" can be defined in `app/root.tsx`, and so all routes will use the Edge runtime by default, unless `"runtime": "nodejs"` is used more specifically in a route deeper in the route hierarchy.
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
|||||||
scanParentDirs,
|
scanParentDirs,
|
||||||
walkParentDirs,
|
walkParentDirs,
|
||||||
} from '@vercel/build-utils';
|
} from '@vercel/build-utils';
|
||||||
import { getConfig } from '@vercel/static-config';
|
import { getConfig, BaseFunctionConfig } from '@vercel/static-config';
|
||||||
import { nodeFileTrace } from '@vercel/nft';
|
import { nodeFileTrace } from '@vercel/nft';
|
||||||
import { readConfig, RemixConfig } from '@remix-run/dev/dist/config';
|
import { readConfig, RemixConfig } from '@remix-run/dev/dist/config';
|
||||||
import type {
|
import type {
|
||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
findConfig,
|
findConfig,
|
||||||
getPathFromRoute,
|
getPathFromRoute,
|
||||||
getRegExpFromPath,
|
getRegExpFromPath,
|
||||||
|
getRouteIterator,
|
||||||
isLayoutRoute,
|
isLayoutRoute,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
@@ -181,16 +182,17 @@ module.exports = config;`;
|
|||||||
const remixRoutes = Object.values(remixConfig.routes);
|
const remixRoutes = Object.values(remixConfig.routes);
|
||||||
|
|
||||||
// Figure out which pages should be edge functions
|
// Figure out which pages should be edge functions
|
||||||
const edgePages = new Set<ConfigRoute>();
|
let hasEdgeRoute = false;
|
||||||
|
const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig>();
|
||||||
const project = new Project();
|
const project = new Project();
|
||||||
for (const route of remixRoutes) {
|
for (const route of remixRoutes) {
|
||||||
const routePath = join(remixConfig.appDirectory, route.file);
|
const routePath = join(remixConfig.appDirectory, route.file);
|
||||||
const staticConfig = getConfig(project, routePath);
|
const staticConfig = getConfig(project, routePath);
|
||||||
const isEdge =
|
if (staticConfig) {
|
||||||
staticConfig?.runtime === 'edge' ||
|
staticConfigsMap.set(route, staticConfig);
|
||||||
staticConfig?.runtime === 'experimental-edge';
|
}
|
||||||
if (isEdge) {
|
if (staticConfig?.runtime && isEdgeRuntime(staticConfig.runtime)) {
|
||||||
edgePages.add(route);
|
hasEdgeRoute = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +214,7 @@ module.exports = config;`;
|
|||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
nodeVersion
|
nodeVersion
|
||||||
),
|
),
|
||||||
edgePages.size > 0
|
hasEdgeRoute
|
||||||
? createRenderEdgeFunction(
|
? createRenderEdgeFunction(
|
||||||
entrypointFsDirname,
|
entrypointFsDirname,
|
||||||
repoRootPath,
|
repoRootPath,
|
||||||
@@ -238,7 +240,16 @@ module.exports = config;`;
|
|||||||
if (isLayoutRoute(route.id, remixRoutes)) continue;
|
if (isLayoutRoute(route.id, remixRoutes)) continue;
|
||||||
|
|
||||||
const path = getPathFromRoute(route, remixConfig.routes);
|
const path = getPathFromRoute(route, remixConfig.routes);
|
||||||
const isEdge = edgePages.has(route);
|
|
||||||
|
let isEdge = false;
|
||||||
|
for (const currentRoute of getRouteIterator(route, remixConfig.routes)) {
|
||||||
|
const staticConfig = staticConfigsMap.get(currentRoute);
|
||||||
|
if (staticConfig?.runtime) {
|
||||||
|
isEdge = isEdgeRuntime(staticConfig.runtime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fn =
|
const fn =
|
||||||
isEdge && edgeFunction
|
isEdge && edgeFunction
|
||||||
? // `EdgeFunction` currently requires the "name" property to be set.
|
? // `EdgeFunction` currently requires the "name" property to be set.
|
||||||
@@ -461,3 +472,7 @@ async function ensureResolvable(start: string, base: string, pkgName: string) {
|
|||||||
`Failed to resolve "${pkgName}". To fix this error, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
|
`Failed to resolve "${pkgName}". To fix this error, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isEdgeRuntime(runtime: string): boolean {
|
||||||
|
return runtime === 'edge' || runtime === 'experimental-edge';
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,21 +25,27 @@ export function isLayoutRoute(
|
|||||||
return routes.some(r => r.parentId === routeId);
|
return routes.some(r => r.parentId === routeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* getRouteIterator(route: ConfigRoute, routes: RouteManifest) {
|
||||||
|
let currentRoute: ConfigRoute = route;
|
||||||
|
do {
|
||||||
|
yield currentRoute;
|
||||||
|
if (currentRoute.parentId) {
|
||||||
|
currentRoute = routes[currentRoute.parentId];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (currentRoute);
|
||||||
|
}
|
||||||
|
|
||||||
export function getPathFromRoute(
|
export function getPathFromRoute(
|
||||||
route: ConfigRoute,
|
route: ConfigRoute,
|
||||||
routes: RouteManifest
|
routes: RouteManifest
|
||||||
): string {
|
): string {
|
||||||
let currentRoute: ConfigRoute | undefined = route;
|
|
||||||
const pathParts: string[] = [];
|
const pathParts: string[] = [];
|
||||||
do {
|
for (const currentRoute of getRouteIterator(route, routes)) {
|
||||||
if (currentRoute.index) pathParts.push('index');
|
if (currentRoute.index) pathParts.push('index');
|
||||||
if (currentRoute.path) pathParts.push(currentRoute.path);
|
if (currentRoute.path) pathParts.push(currentRoute.path);
|
||||||
if (currentRoute.parentId) {
|
}
|
||||||
currentRoute = routes[currentRoute.parentId];
|
|
||||||
} else {
|
|
||||||
currentRoute = undefined;
|
|
||||||
}
|
|
||||||
} while (currentRoute);
|
|
||||||
const path = pathParts.reverse().join('/');
|
const path = pathParts.reverse().join('/');
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
12
packages/remix/test/fixtures/01-remix-basics/app/routes/projects.tsx
vendored
Normal file
12
packages/remix/test/fixtures/01-remix-basics/app/routes/projects.tsx
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Outlet } from '@remix-run/react';
|
||||||
|
|
||||||
|
export const config = { runtime: 'edge' };
|
||||||
|
|
||||||
|
export default function Projects() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Projects</h1>
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
packages/remix/test/fixtures/01-remix-basics/app/routes/projects/edge.tsx
vendored
Normal file
13
packages/remix/test/fixtures/01-remix-basics/app/routes/projects/edge.tsx
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { useLoaderData } from "@remix-run/react";
|
||||||
|
|
||||||
|
// `"runtime": "edge"` is implied here because the parent route defined it
|
||||||
|
|
||||||
|
export async function loader() {
|
||||||
|
const isEdge = typeof process.version === 'undefined';
|
||||||
|
return { isEdge };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Edge() {
|
||||||
|
const data = useLoaderData<typeof loader>();
|
||||||
|
return <div>{JSON.stringify(data)}</div>;
|
||||||
|
}
|
||||||
14
packages/remix/test/fixtures/01-remix-basics/app/routes/projects/node.tsx
vendored
Normal file
14
packages/remix/test/fixtures/01-remix-basics/app/routes/projects/node.tsx
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { useLoaderData } from "@remix-run/react";
|
||||||
|
|
||||||
|
// Explicitly override the `"runtime": "edge"` defined by the parent route
|
||||||
|
export const config = { runtime: 'nodejs' };
|
||||||
|
|
||||||
|
export async function loader() {
|
||||||
|
const isEdge = typeof process.version === 'undefined';
|
||||||
|
return { isEdge };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Node() {
|
||||||
|
const data = useLoaderData<typeof loader>();
|
||||||
|
return <div>{JSON.stringify(data)}</div>;
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
{ "path": "/nested/another", "mustContain": "Nested another page" },
|
{ "path": "/nested/another", "mustContain": "Nested another page" },
|
||||||
{ "path": "/nested/index", "mustContain": "Not Found" },
|
{ "path": "/nested/index", "mustContain": "Not Found" },
|
||||||
{ "path": "/asdf", "mustContain": "Not Found" },
|
{ "path": "/asdf", "mustContain": "Not Found" },
|
||||||
{ "path": "/instanceof", "mustContain": "InstanceOfRequest: true" }
|
{ "path": "/instanceof", "mustContain": "InstanceOfRequest: true" },
|
||||||
|
{ "path": "/projects/edge", "mustContain": "\"isEdge\":true" },
|
||||||
|
{ "path": "/projects/node", "mustContain": "\"isEdge\":false" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user