mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-06 04:22:01 +00:00
[next]: ensure user rewrites match to action outputs (#11628)
The builder normalizes user rewrites that target pages that have special outputs (`.rsc`, `.prefetch.rsc`). When we added support for `.action` outputs, we need to perform this same normalization to ensure that user rewrites still match. If the rewrite was a greedy match (eg `/:path*`) it'd be ok, but more specific rewrites would have the issue.
This commit is contained in:
5
.changeset/smart-horses-rescue.md
Normal file
5
.changeset/smart-horses-rescue.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@vercel/next': patch
|
||||
---
|
||||
|
||||
Ensure user rewrites still match to action outputs
|
||||
@@ -252,9 +252,19 @@ export async function serverBuild({
|
||||
|
||||
for (const rewrite of afterFilesRewrites) {
|
||||
if (rewrite.src && rewrite.dest) {
|
||||
// ensures that userland rewrites are still correctly matched to their special outputs
|
||||
// PPR should match .prefetch.rsc, .rsc, and .action
|
||||
// non-PPR should match .rsc and .action
|
||||
// we only add `.action` handling to the regex if flagged on in the build
|
||||
const rscSuffix = isAppPPREnabled
|
||||
? `(\\.prefetch)?\\.rsc${hasActionOutputSupport ? '|\\.action' : ''}`
|
||||
: hasActionOutputSupport
|
||||
? '(\\.action|\\.rsc)'
|
||||
: '\\.rsc';
|
||||
|
||||
rewrite.src = rewrite.src.replace(
|
||||
/\/?\(\?:\/\)\?/,
|
||||
`(?<rscsuff>${isAppPPREnabled ? '(\\.prefetch)?' : ''}\\.rsc)?(?:/)?`
|
||||
`(?<rscsuff>${rscSuffix})?(?:/)?`
|
||||
);
|
||||
let destQueryIndex = rewrite.dest.indexOf('?');
|
||||
|
||||
|
||||
@@ -273,6 +273,26 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||
expect(body).toContain(JSON.stringify(['id', '1', 'd']));
|
||||
expect(body).not.toContain(JSON.stringify(['id', '1.action', 'd']));
|
||||
});
|
||||
|
||||
it('should work when a rewrite targets an action', async () => {
|
||||
const targetPath = `${basePath}/rsc/static`;
|
||||
const canonicalPath = `/rewrite/${basePath}/rsc/static`;
|
||||
const actionId = findActionId(targetPath, runtime);
|
||||
|
||||
const res = await fetch(
|
||||
`${ctx.deploymentUrl}${canonicalPath}`,
|
||||
generateFormDataPayload(actionId)
|
||||
);
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.headers.get('x-matched-path')).toBe(targetPath + '.action');
|
||||
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||
if (runtime === 'node') {
|
||||
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||
} else {
|
||||
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('pages', () => {
|
||||
|
||||
@@ -1 +1,14 @@
|
||||
module.exports = {};
|
||||
module.exports = {
|
||||
rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/rewrite/rsc/static',
|
||||
destination: '/rsc/static',
|
||||
},
|
||||
{
|
||||
source: '/rewrite/edge/rsc/static',
|
||||
destination: '/edge/rsc/static',
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user