mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
[next] fix app dir edge functions with basePath (#10465)
x-ref: https://github.com/vercel/vercel/pull/10394
This commit is contained in:
5
.changeset/curvy-swans-tickle.md
Normal file
5
.changeset/curvy-swans-tickle.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@vercel/next": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix Next.js with `basePath` + Edge runtime + App Router on a top level `page.jsx`
|
||||||
@@ -91,6 +91,7 @@ import {
|
|||||||
getOperationType,
|
getOperationType,
|
||||||
isApiPage,
|
isApiPage,
|
||||||
getFunctionsConfigManifest,
|
getFunctionsConfigManifest,
|
||||||
|
normalizeEdgeFunctionPath,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
export const version = 2;
|
export const version = 2;
|
||||||
@@ -2720,7 +2721,15 @@ async function getServerlessPages(params: {
|
|||||||
for (const edgeFunctionFile of Object.keys(
|
for (const edgeFunctionFile of Object.keys(
|
||||||
middlewareManifest?.functions ?? {}
|
middlewareManifest?.functions ?? {}
|
||||||
)) {
|
)) {
|
||||||
const edgePath = (edgeFunctionFile.slice(1) || 'index') + '.js';
|
let edgePath =
|
||||||
|
middlewareManifest?.functions?.[edgeFunctionFile].name ||
|
||||||
|
edgeFunctionFile;
|
||||||
|
|
||||||
|
edgePath = normalizeEdgeFunctionPath(
|
||||||
|
edgePath,
|
||||||
|
params.appPathRoutesManifest || {}
|
||||||
|
);
|
||||||
|
edgePath = (edgePath || 'index') + '.js';
|
||||||
delete normalizedAppPaths[edgePath];
|
delete normalizedAppPaths[edgePath];
|
||||||
delete pages[edgePath];
|
delete pages[edgePath];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1245,10 +1245,9 @@ export async function serverBuild({
|
|||||||
if (ogRoute.endsWith('/route')) {
|
if (ogRoute.endsWith('/route')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
route = path.posix.join(
|
route = normalizeIndexOutput(
|
||||||
'./',
|
path.posix.join('./', entryDirectory, route === '/' ? '/index' : route),
|
||||||
entryDirectory,
|
true
|
||||||
route === '/' ? '/index' : route
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (lambdas[route]) {
|
if (lambdas[route]) {
|
||||||
|
|||||||
@@ -2344,7 +2344,7 @@ export function normalizeIndexOutput(
|
|||||||
outputName: string,
|
outputName: string,
|
||||||
isServerMode: boolean
|
isServerMode: boolean
|
||||||
) {
|
) {
|
||||||
if (outputName !== '/index' && isServerMode) {
|
if (outputName !== 'index' && outputName !== '/index' && isServerMode) {
|
||||||
return outputName.replace(/\/index$/, '');
|
return outputName.replace(/\/index$/, '');
|
||||||
}
|
}
|
||||||
return outputName;
|
return outputName;
|
||||||
@@ -2521,6 +2521,29 @@ function normalizeRegions(regions: Regions): undefined | string | string[] {
|
|||||||
return newRegions;
|
return newRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalizeEdgeFunctionPath(
|
||||||
|
shortPath: string,
|
||||||
|
appPathRoutesManifest: Record<string, string>
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
shortPath.startsWith('app/') &&
|
||||||
|
(shortPath.endsWith('/page') ||
|
||||||
|
shortPath.endsWith('/route') ||
|
||||||
|
shortPath === 'app/_not-found')
|
||||||
|
) {
|
||||||
|
const ogRoute = shortPath.replace(/^app\//, '/');
|
||||||
|
shortPath = (
|
||||||
|
appPathRoutesManifest[ogRoute] ||
|
||||||
|
shortPath.replace(/(^|\/)(page|route)$/, '')
|
||||||
|
).replace(/^\//, '');
|
||||||
|
|
||||||
|
if (!shortPath || shortPath === '/') {
|
||||||
|
shortPath = 'index';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shortPath;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getMiddlewareBundle({
|
export async function getMiddlewareBundle({
|
||||||
entryPath,
|
entryPath,
|
||||||
outputDirectory,
|
outputDirectory,
|
||||||
@@ -2699,27 +2722,19 @@ export async function getMiddlewareBundle({
|
|||||||
// app/index/page -> index/index
|
// app/index/page -> index/index
|
||||||
if (shortPath.startsWith('pages/')) {
|
if (shortPath.startsWith('pages/')) {
|
||||||
shortPath = shortPath.replace(/^pages\//, '');
|
shortPath = shortPath.replace(/^pages\//, '');
|
||||||
} else if (
|
} else {
|
||||||
shortPath.startsWith('app/') &&
|
shortPath = normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest);
|
||||||
(shortPath.endsWith('/page') ||
|
|
||||||
shortPath.endsWith('/route') ||
|
|
||||||
shortPath === 'app/_not-found')
|
|
||||||
) {
|
|
||||||
const ogRoute = shortPath.replace(/^app\//, '/');
|
|
||||||
shortPath = (
|
|
||||||
appPathRoutesManifest[ogRoute] ||
|
|
||||||
shortPath.replace(/(^|\/)(page|route)$/, '')
|
|
||||||
).replace(/^\//, '');
|
|
||||||
|
|
||||||
if (!shortPath || shortPath === '/') {
|
|
||||||
shortPath = 'index';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (routesManifest?.basePath) {
|
if (routesManifest?.basePath) {
|
||||||
shortPath = path.posix
|
shortPath = normalizeIndexOutput(
|
||||||
.join(routesManifest.basePath, shortPath)
|
path.posix.join(
|
||||||
.replace(/^\//, '');
|
'./',
|
||||||
|
routesManifest?.basePath,
|
||||||
|
shortPath.replace(/^\//, '')
|
||||||
|
),
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.edgeFunction.name = shortPath;
|
worker.edgeFunction.name = shortPath;
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
return <div>another</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
return <div>dynamic</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
const Layout = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
return <div>Home</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
return <div>test</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
reactStrictMode: true,
|
||||||
|
basePath: '/test',
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = nextConfig;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"next": "canary",
|
||||||
|
"react": "latest",
|
||||||
|
"react-dom": "latest"
|
||||||
|
},
|
||||||
|
"ignoreNextjsUpdates": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"builds": [{ "src": "package.json", "use": "@vercel/next" }]
|
||||||
|
}
|
||||||
@@ -553,3 +553,52 @@ it('Should de-dupe correctly when limit is close (uncompressed)', async () => {
|
|||||||
expect(lambdas.size).toBe(2);
|
expect(lambdas.size).toBe(2);
|
||||||
expect(lambdas.size).toBeLessThan(totalLambdas);
|
expect(lambdas.size).toBeLessThan(totalLambdas);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle edge functions in app with basePath', async () => {
|
||||||
|
const {
|
||||||
|
buildResult: { output },
|
||||||
|
} = await runBuildLambda(path.join(__dirname, 'edge-app-dir-basepath'));
|
||||||
|
|
||||||
|
console.error(output);
|
||||||
|
|
||||||
|
expect(output['test']).toBeDefined();
|
||||||
|
expect(output['test']).toBeDefined();
|
||||||
|
expect(output['test'].type).toBe('EdgeFunction');
|
||||||
|
expect(output['test'].type).toBe('EdgeFunction');
|
||||||
|
|
||||||
|
expect(output['test/another']).toBeDefined();
|
||||||
|
expect(output['test/another.rsc']).toBeDefined();
|
||||||
|
expect(output['test/another'].type).toBe('EdgeFunction');
|
||||||
|
expect(output['test/another.rsc'].type).toBe('EdgeFunction');
|
||||||
|
|
||||||
|
expect(output['test/dynamic/[slug]']).toBeDefined();
|
||||||
|
expect(output['test/dynamic/[slug].rsc']).toBeDefined();
|
||||||
|
expect(output['test/dynamic/[slug]'].type).toBe('EdgeFunction');
|
||||||
|
expect(output['test/dynamic/[slug].rsc'].type).toBe('EdgeFunction');
|
||||||
|
|
||||||
|
expect(output['test/dynamic/[slug]']).toBeDefined();
|
||||||
|
expect(output['test/dynamic/[slug].rsc']).toBeDefined();
|
||||||
|
expect(output['test/dynamic/[slug]'].type).toBe('EdgeFunction');
|
||||||
|
expect(output['test/dynamic/[slug].rsc'].type).toBe('EdgeFunction');
|
||||||
|
|
||||||
|
expect(output['test/test']).toBeDefined();
|
||||||
|
expect(output['test/test.rsc']).toBeDefined();
|
||||||
|
expect(output['test/test'].type).toBe('EdgeFunction');
|
||||||
|
expect(output['test/test.rsc'].type).toBe('EdgeFunction');
|
||||||
|
|
||||||
|
expect(output['test/_not-found']).toBeDefined();
|
||||||
|
expect(output['test/_not-found'].type).toBe('Lambda');
|
||||||
|
|
||||||
|
const lambdas = new Set();
|
||||||
|
const edgeFunctions = new Set();
|
||||||
|
|
||||||
|
for (const item of Object.values(output)) {
|
||||||
|
if (item.type === 'Lambda') {
|
||||||
|
lambdas.add(item);
|
||||||
|
} else if (item.type === 'EdgeFunction') {
|
||||||
|
edgeFunctions.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(lambdas.size).toBe(1);
|
||||||
|
expect(edgeFunctions.size).toBe(4);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user