diff --git a/.changeset/dry-beers-grow.md b/.changeset/dry-beers-grow.md new file mode 100644 index 000000000000..8e3ddffd1dae --- /dev/null +++ b/.changeset/dry-beers-grow.md @@ -0,0 +1,15 @@ +--- +'astro': minor +--- + +Redirects configuration + +This change moves the `redirects` configuration out of experimental. If you were previously using experimental redirects, remove the following experimental flag: + +```js +experimental: { + redirects: true, +} +``` + +If you have been waiting for stabilization before using redirects, now you can do so. Check out [the docs on redirects](https://docs.astro.build/en/core-concepts/routing/#redirects) to learn how to use this built-in feature. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index af48c4010c57..0a972d4b07f3 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -108,7 +108,6 @@ export interface CLIFlags { drafts?: boolean; open?: boolean; experimentalAssets?: boolean; - experimentalRedirects?: boolean; } /** @@ -455,10 +454,10 @@ export interface AstroUserConfig { /** * @docs - * @name redirects (Experimental) + * @name redirects * @type {Record} * @default `{}` - * @version 2.6.0 + * @version 2.9.0 * @description Specify a mapping of redirects where the key is the route to match * and the value is the path to redirect to. * @@ -1228,27 +1227,6 @@ export interface AstroUserConfig { * ``` */ assets?: boolean; - - /** - * @docs - * @name experimental.redirects - * @type {boolean} - * @default `false` - * @version 2.6.0 - * @description - * Enable experimental support for redirect configuration. With this enabled - * you can set redirects via the top-level `redirects` property. To enable - * this feature, set `experimental.redirects` to `true`. - * - * ```js - * { - * experimental: { - * redirects: true, - * }, - * } - * ``` - */ - redirects?: boolean; }; // Legacy options to be removed diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 3ae36ac57572..34af2291c287 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -37,13 +37,12 @@ import { import { runHookBuildGenerated } from '../../integrations/index.js'; import { isServerLikeOutput } from '../../prerender/utils.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; -import { callEndpoint, throwIfRedirectNotAllowed } from '../endpoint/index.js'; +import { callEndpoint } from '../endpoint/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import { debug, info } from '../logger/core.js'; import { getRedirectLocationOrThrow, RedirectSinglePageBuiltModule, - routeIsRedirect, } from '../redirects/index.js'; import { createEnvironment, createRenderContext, tryRenderPage } from '../render/index.js'; import { callGetStaticPaths } from '../render/route-cache.js'; @@ -228,10 +227,6 @@ async function generatePage( builtPaths: Set, manifest: SSRManifest ) { - if (routeIsRedirect(pageData.route) && !opts.settings.config.experimental.redirects) { - throw new Error(`To use redirects first set experimental.redirects to \`true\``); - } - let timeStart = performance.now(); const pageInfo = getPageDataByComponent(internals, pageData.route.component); @@ -561,7 +556,6 @@ async function generatePath( ); if (result.type === 'response') { - throwIfRedirectNotAllowed(result.response, opts.settings.config); // If there's no body, do nothing if (!result.response.body) return; const ab = await result.response.arrayBuffer(); diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts index a3bec4f8ca40..1be371523834 100644 --- a/packages/astro/src/core/config/config.ts +++ b/packages/astro/src/core/config/config.ts @@ -100,8 +100,6 @@ export function resolveFlags(flags: Partial): CLIFlags { drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined, experimentalAssets: typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined, - experimentalRedirects: - typeof flags.experimentalRedirects === 'boolean' ? flags.experimentalRedirects : undefined, }; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 3065a1c540df..7a27f1abea21 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -45,7 +45,6 @@ const ASTRO_CONFIG_DEFAULTS = { redirects: {}, experimental: { assets: false, - redirects: false, }, } satisfies AstroUserConfig & { server: { open: boolean } }; @@ -233,7 +232,6 @@ export const AstroConfigSchema = z.object({ experimental: z .object({ assets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.assets), - redirects: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.redirects), }) .passthrough() .refine( diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index a5097957f593..9fe3b42ab2c1 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -1,6 +1,5 @@ import type { APIContext, - AstroConfig, EndpointHandler, EndpointOutput, MiddlewareEndpointHandler, @@ -9,7 +8,6 @@ import type { } from '../../@types/astro'; import type { Environment, RenderContext } from '../render/index'; -import { isServerLikeOutput } from '../../prerender/utils.js'; import { renderEndpoint } from '../../runtime/server/index.js'; import { ASTRO_VERSION } from '../constants.js'; import { AstroCookies, attachToResponse } from '../cookies/index.js'; @@ -161,17 +159,3 @@ export async function callEndpoint cookies: context.cookies, }; } - -function isRedirect(statusCode: number) { - return statusCode >= 300 && statusCode < 400; -} - -export function throwIfRedirectNotAllowed(response: Response, config: AstroConfig) { - if ( - !isServerLikeOutput(config) && - isRedirect(response.status) && - !config.experimental.redirects - ) { - throw new AstroError(AstroErrorData.StaticRedirectNotAvailable); - } -} diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index d7b8c9a9eb54..3571152d315d 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -3,7 +3,6 @@ import type http from 'node:http'; import type { ComponentInstance, ManifestData, RouteData, SSRManifest } from '../@types/astro'; import { attachToResponse } from '../core/cookies/index.js'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; -import { throwIfRedirectNotAllowed } from '../core/endpoint/index.js'; import { AstroErrorData, isAstroError } from '../core/errors/index.js'; import { warn } from '../core/logger/core.js'; import { loadMiddleware } from '../core/middleware/loadMiddleware.js'; @@ -146,16 +145,6 @@ export async function handleRoute({ return handle404Response(origin, incomingRequest, incomingResponse); } - if (matchedRoute.route.type === 'redirect' && !settings.config.experimental.redirects) { - writeWebResponse( - incomingResponse, - new Response(`To enable redirect set experimental.redirects to \`true\`.`, { - status: 400, - }) - ); - return; - } - const { config } = settings; const filePath: URL | undefined = matchedRoute.filePath; const { route, preloadedComponent } = matchedRoute; @@ -210,7 +199,6 @@ export async function handleRoute({ manifest, }); } - throwIfRedirectNotAllowed(result.response, config); await writeWebResponse(incomingResponse, result.response); } else { let contentType = 'text/plain'; @@ -249,14 +237,13 @@ export async function handleRoute({ manifest, }); } - throwIfRedirectNotAllowed(result, config); let response = result; // Response.status is read-only, so a clone is required to override if (status && response.status !== status) { response = new Response(result.body, { ...result, status }); } - return await writeSSRResult(request, response, incomingResponse); + await writeSSRResult(request, response, incomingResponse); } } diff --git a/packages/astro/test/dev-routing.test.js b/packages/astro/test/dev-routing.test.js index be31864936e2..c42c25dc03d2 100644 --- a/packages/astro/test/dev-routing.test.js +++ b/packages/astro/test/dev-routing.test.js @@ -43,11 +43,6 @@ describe('Development Routing', () => { const response = await fixture.fetch('/2'); expect(response.status).to.equal(404); }); - - it('500 when redirecting in SSG mode', async () => { - const response = await fixture.fetch('/redirect'); - expect(response.status).to.equal(500); - }); }); describe('No subpath used', () => { diff --git a/packages/astro/test/redirects.test.js b/packages/astro/test/redirects.test.js index 3f017275aa25..ecb13993a5ee 100644 --- a/packages/astro/test/redirects.test.js +++ b/packages/astro/test/redirects.test.js @@ -15,9 +15,6 @@ describe('Astro.redirect', () => { redirects: { '/api/redirect': '/test', }, - experimental: { - redirects: true, - }, }); await fixture.build(); }); @@ -71,9 +68,6 @@ describe('Astro.redirect', () => { fixture = await loadFixture({ root: './fixtures/ssr-redirect/', output: 'static', - experimental: { - redirects: true, - }, redirects: { '/': '/test', '/one': '/test', @@ -159,9 +153,6 @@ describe('Astro.redirect', () => { fixture = await loadFixture({ root: './fixtures/ssr-redirect/', output: 'static', - experimental: { - redirects: true, - }, redirects: { '/one': '/', }, @@ -194,9 +185,6 @@ describe('Astro.redirect', () => { build: { redirects: false, }, - experimental: { - redirects: true, - }, }); await fixture.build(); }); diff --git a/packages/integrations/cloudflare/test/directory.test.js b/packages/integrations/cloudflare/test/directory.test.js index 371c5f3ff29c..a252b03e9254 100644 --- a/packages/integrations/cloudflare/test/directory.test.js +++ b/packages/integrations/cloudflare/test/directory.test.js @@ -14,9 +14,6 @@ describe('mode: "directory"', () => { redirects: { '/old': '/', }, - experimental: { - redirects: true, - }, }); await fixture.build(); }); diff --git a/packages/integrations/netlify/README.md b/packages/integrations/netlify/README.md index d814fccd1af7..eb1ae8878d6f 100644 --- a/packages/integrations/netlify/README.md +++ b/packages/integrations/netlify/README.md @@ -142,7 +142,7 @@ export default defineConfig({ ### Static sites -For static sites you usually don't need an adapter. However, if you use `redirects` configuration (experimental) in your Astro config, the Netlify adapter can be used to translate this to the proper `_redirects` format. +For static sites you usually don't need an adapter. However, if you use `redirects` configuration in your Astro config, the Netlify adapter can be used to translate this to the proper `_redirects` format. ```js import { defineConfig } from 'astro/config'; @@ -154,9 +154,6 @@ export default defineConfig({ redirects: { '/blog/old-post': '/blog/new-post', }, - experimental: { - redirects: true, - }, }); ``` diff --git a/packages/integrations/netlify/test/functions/redirects.test.js b/packages/integrations/netlify/test/functions/redirects.test.js index 566b88f4d74a..39c496cdf21a 100644 --- a/packages/integrations/netlify/test/functions/redirects.test.js +++ b/packages/integrations/netlify/test/functions/redirects.test.js @@ -18,9 +18,6 @@ describe('SSG - Redirects', () => { redirects: { '/other': '/', }, - experimental: { - redirects: true, - }, }); await fixture.build(); }); diff --git a/packages/integrations/netlify/test/static/redirects.test.js b/packages/integrations/netlify/test/static/redirects.test.js index d2f87d4f6267..ae3ff1eb843c 100644 --- a/packages/integrations/netlify/test/static/redirects.test.js +++ b/packages/integrations/netlify/test/static/redirects.test.js @@ -11,9 +11,6 @@ describe('SSG - Redirects', () => { root: new URL('./fixtures/redirects/', import.meta.url).toString(), output: 'static', adapter: netlifyStatic(), - experimental: { - redirects: true, - }, site: `http://example.com`, integrations: [testIntegration()], redirects: { diff --git a/packages/integrations/vercel/test/redirects.test.js b/packages/integrations/vercel/test/redirects.test.js index 35bbfcd519a2..df17664eec6e 100644 --- a/packages/integrations/vercel/test/redirects.test.js +++ b/packages/integrations/vercel/test/redirects.test.js @@ -18,9 +18,6 @@ describe('Redirects', () => { '/blog/[...slug]': '/team/articles/[...slug]', }, trailingSlash: 'always', - experimental: { - redirects: true, - }, }); await fixture.build(); });