From 45ad326932971b44630a32d9092c9505f24f42f8 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 31 Jul 2024 11:51:13 +0100 Subject: [PATCH] feat: stabilise the rewrite APIs (#11542) * feat: stabilise the rewrite APIs * chore: rewrite changeset * oops * Apply suggestions from code review Co-authored-by: Sarah Rainsberger * chore: fix linting * fix: update exemple * code formatting * edit changeset code examples --------- Co-authored-by: Sarah Rainsberger Co-authored-by: Erika <3019731+Princesseuh@users.noreply.github.com> --- .changeset/thick-cats-compete.md | 63 +++++++++++++++++++ packages/astro/src/@types/astro.ts | 56 ----------------- packages/astro/src/container/index.ts | 1 - packages/astro/src/core/app/types.ts | 2 - packages/astro/src/core/build/generate.ts | 1 - .../src/core/build/plugins/plugin-manifest.ts | 1 - packages/astro/src/core/config/schema.ts | 3 +- .../src/core/middleware/callMiddleware.ts | 19 +----- packages/astro/src/core/render-context.ts | 51 ++++----------- .../src/vite-plugin-astro-server/plugin.ts | 1 - packages/astro/test/actions.test.js | 3 - packages/astro/test/astro-cookies.test.js | 3 - .../test/fixtures/actions/astro.config.mjs | 1 - .../test/fixtures/reroute/astro.config.mjs | 5 +- .../rewrite-custom-404/astro.config.mjs | 5 +- .../astro.config.mjs | 5 +- .../astro.config.mjs | 5 +- .../rewrite-runtime-error/astro.config.mjs | 5 +- .../fixtures/rewrite-server/astro.config.mjs | 5 +- .../astro.config.mjs | 5 +- 20 files changed, 85 insertions(+), 155 deletions(-) create mode 100644 .changeset/thick-cats-compete.md diff --git a/.changeset/thick-cats-compete.md b/.changeset/thick-cats-compete.md new file mode 100644 index 000000000000..8ff59668de21 --- /dev/null +++ b/.changeset/thick-cats-compete.md @@ -0,0 +1,63 @@ +--- +'astro': minor +--- + +The `experimental.rewriting` feature introduced behind a flag in [v4.8.0](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md#480) is no longer experimental and is available for general use. + +`Astro.rewrite()` and `context.rewrite()` allow you to render a different page without changing the URL in the browser. Unlike using a redirect, your visitor is kept on the original page they visited. + +Rewrites can be useful for showing the same content at multiple paths (e.g. /products/shoes/men/ and /products/men/shoes/) without needing to maintain two identical source files. + +Rewrites are supported in Astro pages, endpoints, and middleware. + +Return `Astro.rewrite()` in the frontmatter of a `.astro` page component to display a different page's content, such as fallback localized content: + +```astro +--- +--- +// src/pages/es-cu/articles/introduction.astro +return Astro.rewrite("/es/articles/introduction") +--- +} +--- +``` + +Use `context.rewrite()` in endpoints, for example to reroute to a different page: + +```js +// src/pages/api.js +export function GET(context) { + if (!context.locals.allowed) { + return context.rewrite('/'); + } +} +``` + +The middleware `next()` function now accepts a parameter with the same type as the `rewrite()` function. For example, with `next("/")`, you can call the next middleware function with a new `Request`. + +```js +// src/middleware.js +export function onRequest(context, next) { + if (!context.cookies.get('allowed')) { + return next('/'); // new signature + } + return next(); +} +``` + +If you were previously using this feature, please remove the experimental flag from your Astro config: + +```diff +// astro.config.mjs +export default defineConfig({ +- experimental: { +- rewriting: true +- } +}) +``` + +If you have been waiting for stabilization before using rewrites in Astro, you can now do so. + +Please see [the routing guide in docs](https://docs.astro.build/en/guides/routing/#rewrites) for more about using this feature. + + diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index ffc92950e49a..f83c4446327e 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1962,62 +1962,6 @@ export interface AstroUserConfig { */ globalRoutePriority?: boolean; - /** - * @docs - * @name experimental.rewriting - * @type {boolean} - * @default `false` - * @version 4.8.0 - * @description - * - * Enables a routing feature for rewriting requests in Astro pages, endpoints and Astro middleware, giving you programmatic control over your routes. - * - * ```js - * { - * experimental: { - * rewriting: true, - * }, - * } - * ``` - * - * Use `Astro.rewrite` in your `.astro` files to reroute to a different page: - * - * ```astro "rewrite" - * --- - * // src/pages/dashboard.astro - * if (!Astro.props.allowed) { - * return Astro.rewrite("/") - * } - * --- - * ``` - * - * Use `context.rewrite` in your endpoint files to reroute to a different page: - * - * ```js - * // src/pages/api.js - * export function GET(ctx) { - * if (!ctx.locals.allowed) { - * return ctx.rewrite("/") - * } - * } - * ``` - * - * Use `next("/")` in your middleware file to reroute to a different page, and then call the next middleware function: - * - * ```js - * // src/middleware.js - * export function onRequest(ctx, next) { - * if (!ctx.cookies.get("allowed")) { - * return next("/") // new signature - * } - * return next(); - * } - * ``` - * - * For a complete overview, and to give feedback on this experimental API, see the [Rerouting RFC](https://github.com/withastro/roadmap/blob/feat/reroute/proposals/0047-rerouting.md). - */ - rewriting?: boolean; - /** * @docs * @name experimental.env diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 7e88f00e58dd..d17ec7846d51 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -113,7 +113,6 @@ function createManifest( return { hrefRoot: import.meta.url, - rewritingEnabled: false, trailingSlash: manifest?.trailingSlash ?? ASTRO_CONFIG_DEFAULTS.trailingSlash, buildFormat: manifest?.buildFormat ?? ASTRO_CONFIG_DEFAULTS.build.format, compressHTML: manifest?.compressHTML ?? ASTRO_CONFIG_DEFAULTS.compressHTML, diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index db65683520b5..2e4e8d8057e9 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -69,8 +69,6 @@ export type SSRManifest = { i18n: SSRManifestI18n | undefined; middleware: MiddlewareHandler; checkOrigin: boolean; - // TODO: remove once the experimental flag is removed - rewritingEnabled: boolean; // TODO: remove experimental prefix experimentalEnvGetSecretEnabled: boolean; }; diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 46fa13346423..8e0e3ddac296 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -578,7 +578,6 @@ function createBuildManifest( i18n: i18nManifest, buildFormat: settings.config.build.format, middleware, - rewritingEnabled: settings.config.experimental.rewriting, checkOrigin: settings.config.security?.checkOrigin ?? false, experimentalEnvGetSecretEnabled: false, }; diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index df7f7b8bddba..11e06074e958 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -279,7 +279,6 @@ function buildManifest( i18n: i18nManifest, buildFormat: settings.config.build.format, checkOrigin: settings.config.security?.checkOrigin ?? false, - rewritingEnabled: settings.config.experimental.rewriting, serverIslandNameMap: Array.from(settings.serverIslandNameMap), experimentalEnvGetSecretEnabled: settings.config.experimental.env !== undefined && diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index fcb2d9a84b1a..3a1b89ec65aa 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -36,6 +36,7 @@ import { appendForwardSlash, prependForwardSlash, removeTrailingForwardSlash } f // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ComplexifyUnionObj {} + type ComplexifyWithUnion = T & ComplexifyUnionObj; type ComplexifyWithOmit = Omit; @@ -87,7 +88,6 @@ export const ASTRO_CONFIG_DEFAULTS = { contentCollectionCache: false, clientPrerender: false, globalRoutePriority: false, - rewriting: false, serverIslands: false, env: { validateSecrets: false, @@ -524,7 +524,6 @@ export const AstroConfigSchema = z.object({ .boolean() .optional() .default(ASTRO_CONFIG_DEFAULTS.experimental.globalRoutePriority), - rewriting: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.rewriting), env: z .object({ schema: EnvSchema.optional(), diff --git a/packages/astro/src/core/middleware/callMiddleware.ts b/packages/astro/src/core/middleware/callMiddleware.ts index 5f4fb3d0f5e5..5f2102f75f74 100644 --- a/packages/astro/src/core/middleware/callMiddleware.ts +++ b/packages/astro/src/core/middleware/callMiddleware.ts @@ -5,7 +5,6 @@ import type { RewritePayload, } from '../../@types/astro.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; -import type { Logger } from '../logger/core.js'; /** * Utility function that is in charge of calling the middleware. @@ -47,27 +46,13 @@ export async function callMiddleware( responseFunction: ( apiContext: APIContext, rewritePayload?: RewritePayload - ) => Promise | Response, - // TODO: remove these two arguments once rerouting goes out of experimental - enableRerouting: boolean, - logger: Logger + ) => Promise | Response ): Promise { let nextCalled = false; let responseFunctionPromise: Promise | Response | undefined = undefined; const next: MiddlewareNext = async (payload) => { nextCalled = true; - - if (enableRerouting) { - responseFunctionPromise = responseFunction(apiContext, payload); - } else { - if (payload) { - logger.warn( - 'router', - 'The rewrite API is experimental. To use this feature, add the `rewriting` flag to the `experimental` object in your Astro config.' - ); - } - responseFunctionPromise = responseFunction(apiContext); - } + responseFunctionPromise = responseFunction(apiContext, payload); // We need to pass the APIContext pass to `callMiddleware` because it can be mutated across middleware functions return responseFunctionPromise; }; diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts index 902ba0fc234e..c55abc381207 100644 --- a/packages/astro/src/core/render-context.ts +++ b/packages/astro/src/core/render-context.ts @@ -137,24 +137,17 @@ export class RenderContext { } const lastNext = async (ctx: APIContext, payload?: RewritePayload) => { if (payload) { - if (this.pipeline.manifest.rewritingEnabled) { - pipeline.logger.debug('router', 'Called rewriting to:', payload); - // we intentionally let the error bubble up - const [routeData, component] = await pipeline.tryRewrite( - payload, - this.request, - this.originalRoute - ); - this.routeData = routeData; - componentInstance = component; - this.isRewriting = true; - this.status = 200; - } else { - this.pipeline.logger.error( - 'router', - 'The rewrite API is experimental. To use this feature, add the `rewriting` flag to the `experimental` object in your Astro config.' - ); - } + pipeline.logger.debug('router', 'Called rewriting to:', payload); + // we intentionally let the error bubble up + const [routeData, component] = await pipeline.tryRewrite( + payload, + this.request, + this.originalRoute + ); + this.routeData = routeData; + componentInstance = component; + this.isRewriting = true; + this.status = 200; } let response: Response; @@ -207,13 +200,7 @@ export class RenderContext { return response; }; - const response = await callMiddleware( - middleware, - apiContext, - lastNext, - this.pipeline.manifest.rewritingEnabled, - this.pipeline.logger - ); + const response = await callMiddleware(middleware, apiContext, lastNext); if (response.headers.get(ROUTE_TYPE_HEADER)) { response.headers.delete(ROUTE_TYPE_HEADER); } @@ -234,20 +221,6 @@ export class RenderContext { async #executeRewrite(reroutePayload: RewritePayload) { this.pipeline.logger.debug('router', 'Calling rewrite: ', reroutePayload); - if (!this.pipeline.manifest.rewritingEnabled) { - this.pipeline.logger.error( - 'router', - 'The rewrite API is experimental. To use this feature, add the `rewriting` flag to the `experimental` object in your Astro config.' - ); - return new Response( - 'The rewrite API is experimental. To use this feature, add the `rewriting` flag to the `experimental` object in your Astro config.', - { - status: 500, - statusText: - 'The rewrite API is experimental. To use this feature, add the `rewriting` flag to the `experimental` object in your Astro config.', - } - ); - } const [routeData, component, newURL] = await this.pipeline.tryRewrite( reroutePayload, this.request, diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 2d072b71fc02..a342220ed6c2 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -147,7 +147,6 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest inlinedScripts: new Map(), i18n: i18nManifest, checkOrigin: settings.config.security?.checkOrigin ?? false, - rewritingEnabled: settings.config.experimental.rewriting, experimentalEnvGetSecretEnabled: false, middleware(_, next) { return next(); diff --git a/packages/astro/test/actions.test.js b/packages/astro/test/actions.test.js index f1ab92202c6d..7c84c458d937 100644 --- a/packages/astro/test/actions.test.js +++ b/packages/astro/test/actions.test.js @@ -10,9 +10,6 @@ describe('Astro Actions', () => { fixture = await loadFixture({ root: './fixtures/actions/', adapter: testAdapter(), - experimental: { - rewriting: true, - }, }); }); diff --git a/packages/astro/test/astro-cookies.test.js b/packages/astro/test/astro-cookies.test.js index a9cdc336277d..482474b54be2 100644 --- a/packages/astro/test/astro-cookies.test.js +++ b/packages/astro/test/astro-cookies.test.js @@ -13,9 +13,6 @@ describe('Astro.cookies', () => { root: './fixtures/astro-cookies/', output: 'server', adapter: testAdapter(), - experimental: { - rewriting: true, - }, }); }); diff --git a/packages/astro/test/fixtures/actions/astro.config.mjs b/packages/astro/test/fixtures/actions/astro.config.mjs index 812c9ac1590d..fc6477578bdf 100644 --- a/packages/astro/test/fixtures/actions/astro.config.mjs +++ b/packages/astro/test/fixtures/actions/astro.config.mjs @@ -4,7 +4,6 @@ import { defineConfig } from 'astro/config'; export default defineConfig({ output: 'server', experimental: { - rewriting: true, actions: true, }, }); diff --git a/packages/astro/test/fixtures/reroute/astro.config.mjs b/packages/astro/test/fixtures/reroute/astro.config.mjs index af13ef19b477..c800d0ddaacc 100644 --- a/packages/astro/test/fixtures/reroute/astro.config.mjs +++ b/packages/astro/test/fixtures/reroute/astro.config.mjs @@ -1,9 +1,6 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - rewriting: true - }, site: "https://example.com" }); diff --git a/packages/astro/test/fixtures/rewrite-custom-404/astro.config.mjs b/packages/astro/test/fixtures/rewrite-custom-404/astro.config.mjs index af13ef19b477..c800d0ddaacc 100644 --- a/packages/astro/test/fixtures/rewrite-custom-404/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-custom-404/astro.config.mjs @@ -1,9 +1,6 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - rewriting: true - }, site: "https://example.com" }); diff --git a/packages/astro/test/fixtures/rewrite-i18n-manual-routing/astro.config.mjs b/packages/astro/test/fixtures/rewrite-i18n-manual-routing/astro.config.mjs index 5d19c8dcc394..76463af6d3f3 100644 --- a/packages/astro/test/fixtures/rewrite-i18n-manual-routing/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-i18n-manual-routing/astro.config.mjs @@ -1,10 +1,7 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - rewriting: true - }, i18n: { routing: "manual", locales: ["en", "es"], diff --git a/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs index af13ef19b477..c800d0ddaacc 100644 --- a/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs @@ -1,9 +1,6 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - rewriting: true - }, site: "https://example.com" }); diff --git a/packages/astro/test/fixtures/rewrite-runtime-error/astro.config.mjs b/packages/astro/test/fixtures/rewrite-runtime-error/astro.config.mjs index af13ef19b477..c800d0ddaacc 100644 --- a/packages/astro/test/fixtures/rewrite-runtime-error/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-runtime-error/astro.config.mjs @@ -1,9 +1,6 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - rewriting: true - }, site: "https://example.com" }); diff --git a/packages/astro/test/fixtures/rewrite-server/astro.config.mjs b/packages/astro/test/fixtures/rewrite-server/astro.config.mjs index 8905b41e64f4..ecd3b251872e 100644 --- a/packages/astro/test/fixtures/rewrite-server/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-server/astro.config.mjs @@ -1,10 +1,7 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ output: "server", - experimental: { - rewriting: true - }, site: "https://example.com" }); diff --git a/packages/astro/test/fixtures/rewrite-trailing-slash-never/astro.config.mjs b/packages/astro/test/fixtures/rewrite-trailing-slash-never/astro.config.mjs index e1cf101b989e..321f4da994d1 100644 --- a/packages/astro/test/fixtures/rewrite-trailing-slash-never/astro.config.mjs +++ b/packages/astro/test/fixtures/rewrite-trailing-slash-never/astro.config.mjs @@ -1,11 +1,8 @@ -import { defineConfig } from 'astro/config'; +import {defineConfig} from 'astro/config'; // https://astro.build/config export default defineConfig({ trailingSlash: "never", - experimental: { - rewriting: true - }, base: "base", site: "https://example.com" });