[next] add .action handling for dynamic routes (#11461)

Follow-up to:
- https://github.com/vercel/vercel/pull/11454

Adds similar handling for dynamic routes
This commit is contained in:
Zack Tanner
2024-04-18 12:04:30 -07:00
committed by GitHub
parent 596b68ce56
commit 5bb96ea072
4 changed files with 52 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
"@vercel/next": patch
---
[next] add .action handling for dynamic routes

View File

@@ -432,6 +432,15 @@ export async function getDynamicRoutes({
dest: route.dest?.replace(/($|\?)/, '.rsc$1'), dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
}); });
routes.push({
...route,
src: route.src.replace(
new RegExp(escapeStringRegexp('(?:/)?$')),
'(?:\\.action)(?:/)?$'
),
dest: route.dest?.replace(/($|\?)/, '.action$1'),
});
routes.push(route); routes.push(route);
} }

View File

@@ -0,0 +1,17 @@
import { revalidatePath } from 'next/cache'
export const dynamic = 'force-static'
export default async function Page() {
async function serverAction() {
'use server';
await new Promise((resolve) => setTimeout(resolve, 1000));
revalidatePath('/dynamic');
}
return (
<form action={serverAction}>
<button>Submit</button>
</form>
);
}

View File

@@ -65,4 +65,25 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
expect(res.headers.get('x-matched-path')).toBe('/other.action'); expect(res.headers.get('x-matched-path')).toBe('/other.action');
expect(res.headers.get('x-vercel-cache')).toBe('MISS'); expect(res.headers.get('x-vercel-cache')).toBe('MISS');
}); });
it('should match the server action to the streaming prerender function (force-static dynamic segment)', async () => {
const data = await fetch(
`${ctx.deploymentUrl}/server-reference-manifest.json`
).then(res => res.json());
const actionId = findActionId(data, 'app/dynamic-static/page');
const res = await fetch(`${ctx.deploymentUrl}/dynamic-static`, {
method: 'POST',
body: `------WebKitFormBoundary8xC9UKOVzHBaGYkR\r\nContent-Disposition: form-data; name=\"1_$ACTION_ID_${actionId}\"\r\n\r\n\r\n------WebKitFormBoundary8xC9UKOVzHBaGYkR\r\nContent-Disposition: form-data; name=\"0\"\r\n\r\n[\"$K1\"]\r\n------WebKitFormBoundary8xC9UKOVzHBaGYkR--\r\n`,
headers: {
'Content-Type':
'multipart/form-data; boundary=----WebKitFormBoundary8xC9UKOVzHBaGYkR',
},
});
expect(res.status).toEqual(200);
expect(res.headers.get('x-matched-path')).toBe('/[dynamic-static].action');
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
});
}); });