Skip to content

Commit

Permalink
feat(routeRules): allow wildcard redirects (#1976)
Browse files Browse the repository at this point in the history
  • Loading branch information
JaZo authored Feb 27, 2024
1 parent 0fa67c7 commit d937b30
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 10 deletions.
2 changes: 2 additions & 0 deletions docs/1.guide/2.routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ export default defineNitroConfig({
'/assets/**': { headers: { 'cache-control': 's-maxage=0' } },
'/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
'/old-page': { redirect: '/new-page' },
'/old-page/**': { redirect: '/new-page/**' },
'/proxy/example': { proxy: 'https://example.com' },
'/proxy/**': { proxy: '/api/**' },
}
Expand All @@ -258,6 +259,7 @@ export default defineNuxtConfig({
'/assets/**': { headers: { 'cache-control': 's-maxage=0' } },
'/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
'/old-page': { redirect: '/new-page' },
'/old-page/**': { redirect: '/new-page/**' },
'/proxy/example': { proxy: 'https://example.com' },
'/proxy/**': { proxy: '/api/**' },
}
Expand Down
1 change: 1 addition & 0 deletions docs/3.config/0.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ routeRules: {
'/api/v1/**': { cors: true, headers: { 'access-control-allow-methods': 'GET' } },
'/old-page': { redirect: '/new-page' }, // uses status code 307 (Temporary Redirect)
'/old-page2': { redirect: { to:'/new-page2', statusCode: 301 } },
'/old-page/**': { redirect: '/new-page/**' },
'/proxy/example': { proxy: 'https://example.com' },
'/proxy/**': { proxy: '/api/**' },
}
Expand Down
4 changes: 4 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,10 @@ export function normalizeRouteRules(
? { to: routeConfig.redirect }
: routeConfig.redirect),
};
if (path.endsWith("/**")) {
// Internal flag
(routeRules.redirect as any)._redirectStripBase = path.slice(0, -3);
}
}
// Proxy
if (routeConfig.proxy) {
Expand Down
2 changes: 1 addition & 1 deletion src/presets/netlify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async function writeRedirects(nitro: Nitro) {
let code = routeRules.redirect.statusCode;
code = { 307: 302, 308: 301 }[code] || code;
contents =
`${key.replace("/**", "/*")}\t${routeRules.redirect.to}\t${code}\n` +
`${key.replace("/**", "/*")}\t${routeRules.redirect.to.replace("/**", "/:splat")}\t${code}\n` +
contents;
}

Expand Down
6 changes: 4 additions & 2 deletions src/presets/vercel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,14 @@ function generateBuildConfig(nitro: Nitro) {
.filter(([_, routeRules]) => routeRules.redirect || routeRules.headers)
.map(([path, routeRules]) => {
let route = {
src: path.replace("/**", "/.*"),
src: path.replace("/**", "/(.*)"),
};
if (routeRules.redirect) {
route = defu(route, {
status: routeRules.redirect.statusCode,
headers: { Location: routeRules.redirect.to },
headers: {
Location: routeRules.redirect.to.replace("/**", "/$1"),
},
});
}
if (routeRules.headers) {
Expand Down
18 changes: 13 additions & 5 deletions src/runtime/route-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,19 @@ export function createRouteRulesHandler(ctx: {
}
// Apply redirect options
if (routeRules.redirect) {
return sendRedirect(
event,
routeRules.redirect.to,
routeRules.redirect.statusCode
);
let target = routeRules.redirect.to;
if (target.endsWith("/**")) {
let targetPath = event.path;
const strpBase = (routeRules.redirect as any)._redirectStripBase;
if (strpBase) {
targetPath = withoutBase(targetPath, strpBase);
}
target = joinURL(target.slice(0, -3), targetPath);
} else if (event.path.includes("?")) {
const query = getQuery(event.path);
target = withQuery(target, query);
}
return sendRedirect(event, target, routeRules.redirect.statusCode);
}
// Apply proxy options
if (routeRules.proxy) {
Expand Down
1 change: 1 addition & 0 deletions test/fixture/nitro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export default defineNitroConfig({
"/rules/redirect/obj": {
redirect: { to: "https://nitro.unjs.io/", statusCode: 308 },
},
"/rules/redirect/wildcard/**": { redirect: "https://nitro.unjs.io/**" },
"/rules/nested/**": { redirect: "/base", headers: { "x-test": "test" } },
"/rules/nested/override": { redirect: { to: "/other" } },
"/rules/_/noncached/cached": { swr: true },
Expand Down
1 change: 1 addition & 0 deletions test/presets/netlify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe("nitro:preset:netlify", async () => {
/* eslint-disable no-tabs */
expect(redirects).toMatchInlineSnapshot(`
"/rules/nested/override /other 302
/rules/redirect/wildcard/* https://nitro.unjs.io/:splat 302
/rules/redirect/obj https://nitro.unjs.io/ 301
/rules/nested/* /base 302
/rules/redirect /base 302
Expand Down
11 changes: 9 additions & 2 deletions test/presets/vercel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ describe("nitro:preset:vercel", async () => {
"src": "/rules/redirect/obj",
"status": 308,
},
{
"headers": {
"Location": "https://nitro.unjs.io/$1",
},
"src": "/rules/redirect/wildcard/(.*)",
"status": 307,
},
{
"headers": {
"Location": "/other",
Expand Down Expand Up @@ -74,14 +81,14 @@ describe("nitro:preset:vercel", async () => {
"Location": "/base",
"x-test": "test",
},
"src": "/rules/nested/.*",
"src": "/rules/nested/(.*)",
"status": 307,
},
{
"headers": {
"cache-control": "public, max-age=3600, immutable",
},
"src": "/build/.*",
"src": "/build/(.*)",
},
{
"continue": true,
Expand Down
6 changes: 6 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ export function testNitro(
const obj = await callHandler({ url: "/rules/redirect/obj" });
expect(obj.status).toBe(308);
expect(obj.headers.location).toBe("https://nitro.unjs.io/");

const wildcard = await callHandler({
url: "/rules/redirect/wildcard/nuxt",
});
expect(wildcard.status).toBe(307);
expect(wildcard.headers.location).toBe("https://nitro.unjs.io/nuxt");
});

it("binary response", async () => {
Expand Down

0 comments on commit d937b30

Please sign in to comment.