diff --git a/.changeset/long-lions-do.md b/.changeset/long-lions-do.md new file mode 100644 index 0000000000..4fd5e2c70f --- /dev/null +++ b/.changeset/long-lions-do.md @@ -0,0 +1,22 @@ +--- +'astro': minor +--- + +Adds a new property `isPrerendered` to the globals `Astro` and `APIContext` . This boolean value represents whether or not the current page is prerendered: + +```astro +--- +// src/pages/index.astro + +export const prerender = true +--- +``` + +```js +// src/middleware.js + +export const onRequest = (ctx, next) => { + console.log(ctx.prerender) // it will log true + return next() +} +``` diff --git a/.changeset/nasty-crabs-worry.md b/.changeset/nasty-crabs-worry.md index 10ad6ed33f..f2a935404b 100644 --- a/.changeset/nasty-crabs-worry.md +++ b/.changeset/nasty-crabs-worry.md @@ -5,7 +5,7 @@ Adds a new property to the globals `Astro` and `APIContext` called `routePattern`. The `routePattern` represents the current route (component) that is being rendered by Astro. It's usually a path pattern will look like this: `blog/[slug]`: -```asto +```astro --- // src/pages/blog/[slug].astro const route = Astro.routePattern; diff --git a/packages/astro/src/actions/runtime/middleware.ts b/packages/astro/src/actions/runtime/middleware.ts index d92bfd28e7..b51322b1de 100644 --- a/packages/astro/src/actions/runtime/middleware.ts +++ b/packages/astro/src/actions/runtime/middleware.ts @@ -21,7 +21,7 @@ export type Locals = { }; export const onRequest = defineMiddleware(async (context, next) => { - if ((context as any)._isPrerendered) { + if (context.isPrerendered) { if (context.request.method === 'POST') { // eslint-disable-next-line no-console console.warn( diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts index c8ce1f2c83..b79e5c768a 100644 --- a/packages/astro/src/core/middleware/index.ts +++ b/packages/astro/src/core/middleware/index.ts @@ -70,6 +70,7 @@ function createContext({ }, }); }, + isPrerendered: false, get preferredLocale(): string | undefined { return (preferredLocale ??= computePreferredLocale(request, userDefinedLocales)); }, diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts index b4b3abb9c2..df86598b51 100644 --- a/packages/astro/src/core/render-context.ts +++ b/packages/astro/src/core/render-context.ts @@ -107,8 +107,6 @@ export class RenderContext { const { cookies, middleware, pipeline } = this; const { logger, serverLike, streaming, manifest } = pipeline; - const isPrerendered = !serverLike || this.routeData.prerender; - const props = Object.keys(this.props).length > 0 ? this.props @@ -121,7 +119,7 @@ export class RenderContext { serverLike, base: manifest.base, }); - const apiContext = this.createAPIContext(props, isPrerendered); + const apiContext = this.createAPIContext(props); this.counter++; if (this.counter === 4) { @@ -208,7 +206,7 @@ export class RenderContext { return response; } - createAPIContext(props: APIContext['props'], isPrerendered: boolean): APIContext { + createAPIContext(props: APIContext['props']): APIContext { const context = this.createActionAPIContext(); const redirect = (path: string, status = 302) => new Response(null, { status, headers: { Location: path } }); @@ -218,11 +216,6 @@ export class RenderContext { redirect, getActionResult: createGetActionResult(context.locals), callAction: createCallAction(context), - // Used internally by Actions middleware. - // TODO: discuss exposing this information from APIContext. - // middleware runs on prerendered routes in the dev server, - // so this is useful information to have. - _isPrerendered: isPrerendered, }); } @@ -261,6 +254,7 @@ export class RenderContext { return { cookies, routePattern: this.routeData.route, + isPrerendered: this.routeData.prerender, get clientAddress() { return renderContext.clientAddress(); }, @@ -446,6 +440,7 @@ export class RenderContext { generator: astroStaticPartial.generator, glob: astroStaticPartial.glob, routePattern: this.routeData.route, + isPrerendered: this.routeData.prerender, cookies, get clientAddress() { return renderContext.clientAddress(); diff --git a/packages/astro/src/types/public/context.ts b/packages/astro/src/types/public/context.ts index cd51f8b6bb..8d7c4fb307 100644 --- a/packages/astro/src/types/public/context.ts +++ b/packages/astro/src/types/public/context.ts @@ -339,6 +339,11 @@ interface AstroSharedContext< * The current locale computed from the URL of the request. It matches the locales in `i18n.locales`, and returns `undefined` otherwise. */ currentLocale: string | undefined; + + /** + * Whether the current route is prerendered or not. + */ + isPrerendered: boolean; } /** diff --git a/packages/astro/test/astro-global.test.js b/packages/astro/test/astro-global.test.js index 353de4a1f7..2b400e87f7 100644 --- a/packages/astro/test/astro-global.test.js +++ b/packages/astro/test/astro-global.test.js @@ -47,7 +47,7 @@ describe('Astro Global', () => { ); }); - it('Astro.route.pattern has the right value in pages and components', async () => { + it('Astro.routePattern has the right value in pages and components', async () => { let html = await fixture.fetch('/blog').then((res) => res.text()); let $ = cheerio.load(html); assert.match($('#pattern').text(), /Astro route pattern: \//); @@ -60,6 +60,18 @@ describe('Astro Global', () => { /Astro route pattern middleware: \/omit-markdown-extensions/, ); }); + + it('Astro.isPrerendered has the right value in pages and components', async () => { + let html = await fixture.fetch('/blog', {}).then((res) => res.text()); + let $ = cheerio.load(html); + assert.match($('#prerender').text(), /Astro route prerender: true/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: true/); + + html = await fixture.fetch('/blog/about', {}).then((res) => res.text()); + $ = cheerio.load(html); + assert.match($('#prerender').text(), /Astro route prerender: false/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: false/); + }); }); describe('build', () => { @@ -96,7 +108,7 @@ describe('Astro Global', () => { assert.equal($('.post-url[href]').length, 8); }); - it('Astro.route.pattern has the right value in pages and components', async () => { + it('Astro.routePattern has the right value in pages and components', async () => { let html = await fixture.readFile('/index.html'); let $ = cheerio.load(html); assert.match($('#pattern').text(), /Astro route pattern: \//); @@ -118,6 +130,19 @@ describe('Astro Global', () => { 'Astro route pattern middleware: /posts/[page]', ); }); + + it('Astro.isPrerendered has the right value in pages and components', async () => { + let html = await fixture.readFile('/index.html'); + let $ = cheerio.load(html); + assert.match($('#prerender').text(), /Astro route prerender: true/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: true/); + + html = await fixture.readFile('/about/index.html'); + $ = cheerio.load(html); + // It's prerendered since there's no adapter + assert.match($('#prerender').text(), /Astro route prerender: true/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: true/); + }); }); describe('app', () => { @@ -143,7 +168,7 @@ describe('Astro Global', () => { assert.equal($('#site').attr('href'), 'https://mysite.dev/subsite/'); }); - it('Astro.route.pattern has the right value in pages and components', async () => { + it('Astro.routePattern has the right value in pages and components', async () => { let response = await app.render(new Request('https://example.com/')); let html = await response.text(); let $ = cheerio.load(html); @@ -158,6 +183,19 @@ describe('Astro Global', () => { /Astro route pattern middleware: \/omit-markdown-extensions/, ); }); + + it('Astro.isPrerendered has the right value in pages and components', async () => { + let html = await app.render(new Request('https://example.com/')).then((res) => res.text()); + let $ = cheerio.load(html); + // It's NOT prerendered since there's an adapter + output server + assert.match($('#prerender').text(), /Astro route prerender: false/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: false/); + + html = await app.render(new Request('https://example.com/about')).then((res) => res.text()); + $ = cheerio.load(html); + assert.match($('#prerender').text(), /Astro route prerender: false/); + assert.match($('#prerender-middleware').text(), /Astro route prerender middleware: false/); + }); }); }); diff --git a/packages/astro/test/fixtures/astro-global/src/components/Route.astro b/packages/astro/test/fixtures/astro-global/src/components/Route.astro index 9dea56df0c..8881588692 100644 --- a/packages/astro/test/fixtures/astro-global/src/components/Route.astro +++ b/packages/astro/test/fixtures/astro-global/src/components/Route.astro @@ -1,6 +1,10 @@ --- const pattern = Astro.routePattern; const localsPattern = Astro.locals.localsPattern; +const isPrerendered = JSON.stringify(Astro.isPrerendered); +const localsPrerendered = JSON.stringify(Astro.locals.localsPrerendered); ---

Astro route pattern: {pattern}

Astro route pattern middleware: {localsPattern}

+

Astro route prerender: {isPrerendered}

+

Astro route prerender middleware: {localsPrerendered}

\ No newline at end of file diff --git a/packages/astro/test/fixtures/astro-global/src/middleware.js b/packages/astro/test/fixtures/astro-global/src/middleware.js index ee6e8a4e84..2c549e0060 100644 --- a/packages/astro/test/fixtures/astro-global/src/middleware.js +++ b/packages/astro/test/fixtures/astro-global/src/middleware.js @@ -2,7 +2,8 @@ export function onRequest(ctx, next) { ctx.locals = { - localsPattern: ctx.routePattern + localsPattern: ctx.routePattern, + localsPrerendered: ctx.isPrerendered }; return next() } diff --git a/packages/astro/test/fixtures/astro-global/src/pages/about.astro b/packages/astro/test/fixtures/astro-global/src/pages/about.astro new file mode 100644 index 0000000000..edafce0d2e --- /dev/null +++ b/packages/astro/test/fixtures/astro-global/src/pages/about.astro @@ -0,0 +1,13 @@ +--- +import Route from '../components/Route.astro' + +export const prerender = false +--- + + + Test + + + + + diff --git a/packages/astro/test/fixtures/astro-global/src/pages/glob.astro b/packages/astro/test/fixtures/astro-global/src/pages/glob.astro index cf237581a7..c25d3733dc 100644 --- a/packages/astro/test/fixtures/astro-global/src/pages/glob.astro +++ b/packages/astro/test/fixtures/astro-global/src/pages/glob.astro @@ -9,7 +9,7 @@ const data = await Astro.glob('./post/**/*'); {data.map((page: any) => (
-

Title

+

Title

Read
))} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dc6a790465..ecfeac33a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8752,10 +8752,12 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lilconfig@2.1.0: