From 03f15c41f13b7b707e2c13676c09e286c9a387f9 Mon Sep 17 00:00:00 2001 From: Alexander Niebuhr Date: Tue, 7 Jan 2025 16:52:23 +0100 Subject: [PATCH] chore: update adapters to better support astro v5 (#454) Co-authored-by: Florian Lefebvre --- packages/integrations/cloudflare/package.json | 1 - .../cloudflare/src/entrypoints/middleware.ts | 27 ++--- packages/integrations/cloudflare/src/index.ts | 55 +++++++-- .../src/utils/generate-routes-json.ts | 19 +-- .../cloudflare/test/routes-json.test.js | 111 +++++++++++++++++- 5 files changed, 172 insertions(+), 41 deletions(-) diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index 193e6d32b6..04eb856bfa 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -31,7 +31,6 @@ "@astrojs/internal-helpers": "0.4.2", "@astrojs/underscore-redirects": "^0.5.0", "@cloudflare/workers-types": "^4.20241230.0", - "@inox-tools/astro-when": "^1.0.2", "esbuild": "^0.24.0", "estree-walker": "^3.0.3", "magic-string": "^0.30.17", diff --git a/packages/integrations/cloudflare/src/entrypoints/middleware.ts b/packages/integrations/cloudflare/src/entrypoints/middleware.ts index b5073cd0e1..187aface59 100644 --- a/packages/integrations/cloudflare/src/entrypoints/middleware.ts +++ b/packages/integrations/cloudflare/src/entrypoints/middleware.ts @@ -1,23 +1,12 @@ -import { When, whenAmI } from '@it-astro:when'; import type { MiddlewareHandler } from 'astro'; -const middlewares: Record = { - [When.Client]: () => { - throw new Error('Client should not run a middleware!'); - }, - [When.DevServer]: (_, next) => next(), - [When.Server]: (_, next) => next(), - [When.Prerender]: (ctx, next) => { +export const onRequest: MiddlewareHandler = (context, next) => { + if (context.isPrerendered) { // @ts-expect-error - if (ctx.locals.runtime === undefined) { - // @ts-expect-error - ctx.locals.runtime = { - env: process.env, - }; - } - return next(); - }, - [When.StaticBuild]: (_, next) => next(), -}; + context.locals.runtime ??= { + env: process.env, + }; + } -export const onRequest = middlewares[whenAmI]; + return next(); +}; diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 549398cd1c..fdef2eb281 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -1,4 +1,10 @@ -import type { AstroConfig, AstroIntegration, HookParameters, IntegrationRouteData } from 'astro'; +import type { + AstroConfig, + AstroIntegration, + HookParameters, + IntegrationResolvedRoute, + IntegrationRouteData, +} from 'astro'; import type { PluginOption } from 'vite'; import { createReadStream } from 'node:fs'; @@ -10,7 +16,6 @@ import { removeLeadingForwardSlash, } from '@astrojs/internal-helpers/path'; import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects'; -import astroWhen from '@inox-tools/astro-when'; import { AstroError } from 'astro/errors'; import { defaultClientConditions } from 'vite'; import { type GetPlatformProxyOptions, getPlatformProxy } from 'wrangler'; @@ -86,6 +91,28 @@ function setProcessEnv(config: AstroConfig, env: Record) { } } +function resolvedRouteToRouteData( + assets: HookParameters<'astro:build:done'>['assets'], + route: IntegrationResolvedRoute +): IntegrationRouteData { + return { + pattern: route.patternRegex, + component: route.entrypoint, + prerender: route.isPrerendered, + route: route.pattern, + generate: route.generate, + params: route.params, + segments: route.segments, + type: route.type, + pathname: route.pathname, + redirect: route.redirect, + distURL: assets.get(route.pattern), + redirectRoute: route.redirectRoute + ? resolvedRouteToRouteData(assets, route.redirectRoute) + : undefined, + }; +} + export default function createIntegration(args?: Options): AstroIntegration { let _config: AstroConfig; let finalBuildOutput: HookParameters<'astro:config:done'>['buildOutput']; @@ -94,6 +121,8 @@ export default function createIntegration(args?: Options): AstroIntegration { args?.cloudflareModules ?? true ); + let _routes: IntegrationResolvedRoute[]; + return { name: '@astrojs/cloudflare', hooks: { @@ -129,7 +158,6 @@ export default function createIntegration(args?: Options): AstroIntegration { }, ], }, - integrations: [astroWhen()], image: setImageConfig(args?.imageService ?? 'compile', config.image, command, logger), }); if (args?.platformProxy?.configPath) { @@ -144,6 +172,9 @@ export default function createIntegration(args?: Options): AstroIntegration { order: 'pre', }); }, + 'astro:routes:resolved': ({ routes }) => { + _routes = routes; + }, 'astro:config:done': ({ setAdapter, config, buildOutput, logger }) => { if (buildOutput === 'static') { logger.warn( @@ -167,7 +198,11 @@ export default function createIntegration(args?: Options): AstroIntegration { hybridOutput: 'stable', staticOutput: 'unsupported', i18nDomains: 'experimental', - sharpImageService: 'limited', + sharpImageService: { + support: 'limited', + message: + 'Cloudflare does not support sharp. You can use the `compile` image service to compile images at build time. It will not work for any on-demand rendered images.', + }, envGetSecret: 'stable', }, }); @@ -260,7 +295,7 @@ export default function createIntegration(args?: Options): AstroIntegration { }; } }, - 'astro:build:done': async ({ pages, routes, dir, logger }) => { + 'astro:build:done': async ({ pages, dir, logger, assets }) => { await cloudflareModulePlugin.afterBuildCompleted(_config); const PLATFORM_FILES = ['_headers', '_redirects', '_routes.json']; if (_config.base !== '/') { @@ -285,7 +320,7 @@ export default function createIntegration(args?: Options): AstroIntegration { redirectsExists = false; } - const redirects: IntegrationRouteData['segments'][] = []; + const redirects: IntegrationResolvedRoute['segments'][] = []; if (redirectsExists) { const rl = createInterface({ input: createReadStream(new URL('./_redirects', _config.outDir)), @@ -324,7 +359,7 @@ export default function createIntegration(args?: Options): AstroIntegration { await createRoutesFile( _config, logger, - routes, + _routes, pages, redirects, args?.routes?.extend?.include, @@ -333,8 +368,10 @@ export default function createIntegration(args?: Options): AstroIntegration { } const redirectRoutes: [IntegrationRouteData, string][] = []; - for (const route of routes) { - if (route.type === 'redirect') redirectRoutes.push([route, '']); + for (const route of _routes) { + // TODO: Replace workaround after upstream @astrojs/underscore-redirects is changed, to support new IntegrationResolvedRoute type + if (route.type === 'redirect') + redirectRoutes.push([resolvedRouteToRouteData(assets, route), '']); } const trueRedirects = createRedirectsFromAstroRoutes({ diff --git a/packages/integrations/cloudflare/src/utils/generate-routes-json.ts b/packages/integrations/cloudflare/src/utils/generate-routes-json.ts index 3d7f8a6431..8828fd52f4 100644 --- a/packages/integrations/cloudflare/src/utils/generate-routes-json.ts +++ b/packages/integrations/cloudflare/src/utils/generate-routes-json.ts @@ -1,4 +1,9 @@ -import type { AstroConfig, AstroIntegrationLogger, IntegrationRouteData, RoutePart } from 'astro'; +import type { + AstroConfig, + AstroIntegrationLogger, + IntegrationResolvedRoute, + RoutePart, +} from 'astro'; import { existsSync } from 'node:fs'; import { writeFile } from 'node:fs/promises'; @@ -63,7 +68,7 @@ async function writeRoutesFileToOutDir( } } -function segmentsToCfSyntax(segments: IntegrationRouteData['segments'], _config: AstroConfig) { +function segmentsToCfSyntax(segments: IntegrationResolvedRoute['segments'], _config: AstroConfig) { const pathSegments = []; if (removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base)).length > 0) { pathSegments.push(removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base))); @@ -163,11 +168,11 @@ class PathTrie { export async function createRoutesFile( _config: AstroConfig, logger: AstroIntegrationLogger, - routes: IntegrationRouteData[], + routes: IntegrationResolvedRoute[], pages: { pathname: string; }[], - redirects: IntegrationRouteData['segments'][], + redirects: IntegrationResolvedRoute['segments'][], includeExtends: | { pattern: string; @@ -223,17 +228,17 @@ export async function createRoutesFile( let hasPrerendered404 = false; for (const route of routes) { const convertedPath = segmentsToCfSyntax(route.segments, _config); - if (route.pathname === '/404' && route.prerender === true) hasPrerendered404 = true; + if (route.pathname === '/404' && route.isPrerendered === true) hasPrerendered404 = true; // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (route.type) { case 'page': - if (route.prerender === false) includePaths.push(convertedPath); + if (route.isPrerendered === false) includePaths.push(convertedPath); break; case 'endpoint': - if (route.prerender === false) includePaths.push(convertedPath); + if (route.isPrerendered === false) includePaths.push(convertedPath); else excludePaths.push(convertedPath); break; diff --git a/packages/integrations/cloudflare/test/routes-json.test.js b/packages/integrations/cloudflare/test/routes-json.test.js index 7cf69f8ccd..c2910ceb78 100644 --- a/packages/integrations/cloudflare/test/routes-json.test.js +++ b/packages/integrations/cloudflare/test/routes-json.test.js @@ -23,7 +23,7 @@ describe('_routes.json generation', () => { assert.deepEqual(routes, { version: 1, - include: ['/_image', '/a/*'], + include: ['/_server-islands/*', '/_image', '/a/*'], exclude: ['/_astro/*', '/redirectme', '/public.txt', '/a', '/a/redirect', '/404', '/b'], }); }); @@ -101,7 +101,7 @@ describe('_routes.json generation', () => { assert.deepEqual(routes, { version: 1, - include: ['/_image', '/a/*', '/another'], + include: ['/_server-islands/*', '/_image', '/a/*', '/another'], exclude: ['/_astro/*', '/redirectme', '/public.txt', '/a', '/a/redirect', '/404', '/b'], }); }); @@ -131,7 +131,7 @@ describe('_routes.json generation', () => { assert.deepEqual(routes, { version: 1, - include: ['/_image', '/a/*'], + include: ['/_server-islands/*', '/_image', '/a/*'], exclude: [ '/_astro/*', '/redirectme', @@ -167,6 +167,7 @@ describe('_routes.json generation', () => { version: 1, include: [ '/', + '/_server-islands/*', '/_image', '/dynamicPages/*', '/mixedPages/dynamic', @@ -234,8 +235,108 @@ describe('_routes.json generation', () => { assert.deepEqual(routes, { version: 1, - include: ['/_image', '/dynamic'], - exclude: [], + include: ['/*'], + exclude: [ + '/_astro/*', + '/redirectme', + '/public.txt', + '/a/*', + '/404', + '/0', + '/1', + '/2', + '/3', + '/4', + '/5', + '/6', + '/7', + '/8', + '/9', + '/10', + '/11', + '/12', + '/13', + '/14', + '/15', + '/16', + '/17', + '/18', + '/19', + '/20', + '/21', + '/22', + '/23', + '/24', + '/25', + '/26', + '/27', + '/28', + '/29', + '/30', + '/31', + '/32', + '/33', + '/34', + '/35', + '/36', + '/37', + '/38', + '/39', + '/40', + '/41', + '/42', + '/43', + '/44', + '/45', + '/46', + '/47', + '/48', + '/49', + '/50', + '/51', + '/52', + '/53', + '/54', + '/55', + '/56', + '/57', + '/58', + '/59', + '/60', + '/61', + '/62', + '/63', + '/64', + '/65', + '/66', + '/67', + '/68', + '/69', + '/70', + '/71', + '/72', + '/73', + '/74', + '/75', + '/76', + '/77', + '/78', + '/79', + '/80', + '/81', + '/82', + '/83', + '/84', + '/85', + '/86', + '/87', + '/88', + '/89', + '/90', + '/91', + '/92', + '/93', + ], }); }); });