From 621d2d25529728b36c62633d6650a0b9eaba08e3 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 28 Oct 2024 20:51:31 +0100 Subject: [PATCH 01/24] feat: work on astro:routes:resolved --- .../astro/src/core/routing/manifest/create.ts | 3 ++ packages/astro/src/integrations/hooks.ts | 36 ++++++++++++++++++- .../astro/src/types/public/integrations.ts | 12 +++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index 33b5216998db..ef437f730960 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -20,6 +20,7 @@ import { routeComparator } from '../priority.js'; import { getRouteGenerator } from './generator.js'; import { getPattern } from './pattern.js'; import { getRoutePrerenderOption } from './prerender.js'; +import { runHookRoutesResolved } from '../../../integrations/hooks.js'; const require = createRequire(import.meta.url); interface Item { @@ -727,6 +728,8 @@ export async function createRouteManifest( } } + await runHookRoutesResolved({ routes, settings, logger }); + return { routes, }; diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 4c1d4a1ae2c1..206f6a3a5ea9 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -24,7 +24,9 @@ import type { import type { AstroIntegration, AstroRenderer, + BaseIntegrationHooks, HookParameters, + IntegrationResolvedRoute, IntegrationRouteData, RouteOptions, } from '../types/public/integrations.js'; @@ -39,7 +41,7 @@ async function withTakingALongTimeMsg({ logger, }: { name: string; - hookName: string; + hookName: keyof BaseIntegrationHooks; hookResult: T | Promise; timeoutMs?: number; logger: Logger; @@ -579,6 +581,7 @@ export async function runHookBuildGenerated({ type RunHookBuildDone = { settings: AstroSettings; pages: string[]; + // TODO: deprecate routes: RouteData[]; logging: Logger; }; @@ -648,6 +651,37 @@ export async function runHookRouteSetup({ } } +export async function runHookRoutesResolved({ + routes, + settings, + logger, +}: { routes: Array; settings: AstroSettings; logger: Logger }) { + for (const integration of settings.config.integrations) { + if (integration?.hooks?.['astro:routes:resolved']) { + const integrationLogger = getLogger(integration, logger); + + await withTakingALongTimeMsg({ + name: integration.name, + hookName: 'astro:routes:resolved', + hookResult: integration.hooks['astro:routes:resolved']({ + routes: routes.map((route) => toIntegrationResolvedRoute(route)), + logger: integrationLogger, + }), + logger, + }); + } + } +} + +function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute { + return { + prerendered: route.prerender, + entrypoint: route.component, + pattern: route.route, + params: route.params, + }; +} + function toIntegrationRouteData(route: RouteData): IntegrationRouteData { return { route: route.route, diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 4d0709fab468..88a2df1779e4 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -232,6 +232,10 @@ export interface BaseIntegrationHooks { route: RouteOptions; logger: AstroIntegrationLogger; }) => void | Promise; + 'astro:routes:resolved': (options: { + routes: Array; + logger: AstroIntegrationLogger; + }) => void | Promise; } export interface AstroIntegration { @@ -255,3 +259,11 @@ export type IntegrationRouteData = Omit< */ redirectRoute?: IntegrationRouteData; }; + +// TODO: document +export interface IntegrationResolvedRoute { + pattern: string; + entrypoint: string; + prerendered: boolean; + params: Array; +} From fbb04e92a86ba39daf363d6c0791f994096d5079 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 29 Oct 2024 13:39:04 +0100 Subject: [PATCH 02/24] feat: work on jsdoc --- packages/astro/src/integrations/hooks.ts | 3 ++- .../astro/src/types/public/integrations.ts | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 206f6a3a5ea9..ed7ca6d06711 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -581,7 +581,6 @@ export async function runHookBuildGenerated({ type RunHookBuildDone = { settings: AstroSettings; pages: string[]; - // TODO: deprecate routes: RouteData[]; logging: Logger; }; @@ -679,6 +678,8 @@ function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute entrypoint: route.component, pattern: route.route, params: route.params, + // TODO: supports other origins + origin: 'user', }; } diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 88a2df1779e4..9c1af3164262 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -225,6 +225,7 @@ export interface BaseIntegrationHooks { 'astro:build:done': (options: { pages: { pathname: string }[]; dir: URL; + /** @deprecated Use `routes` from `astro:routes:resolved` instead */ routes: IntegrationRouteData[]; logger: AstroIntegrationLogger; }) => void | Promise; @@ -260,10 +261,29 @@ export type IntegrationRouteData = Omit< redirectRoute?: IntegrationRouteData; }; -// TODO: document export interface IntegrationResolvedRoute { + /** + * The current **pattern** of the route. For example: + * - `src/pages/index.astro` has a pattern of `/` + * - `src/pages/blog/[...slug].astro` has a pattern of `/blog/[...slug]` + * - `src/pages/site/[blog]/[...slug].astro` has a pattern of `/site/[blog]/[...slug]` + */ pattern: string; + /** + * Source component URL + */ entrypoint: string; + /** + * Whether the route is prerendered or not + */ prerendered: boolean; + /** + * Dynamic and spread route params + * ex. "/pages/[lang]/[...slug].astro" will output the params ['lang', '...slug'] + */ params: Array; + /** + * Whether the route comes from Astro core, an integration or the user's project + */ + origin: 'core' | 'integration' | 'user'; } From 98e77c9639cc0f058175651246f7549bcc8cbce9 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 29 Oct 2024 13:52:50 +0100 Subject: [PATCH 03/24] feat: support origin --- packages/astro/src/actions/integration.ts | 3 +- packages/astro/src/assets/endpoint/config.ts | 1 + packages/astro/src/container/index.ts | 2 ++ .../routing/astro-designed-error-pages.ts | 2 ++ .../astro/src/core/routing/manifest/create.ts | 3 ++ .../core/routing/manifest/serialization.ts | 1 + .../astro/src/core/server-islands/endpoint.ts | 1 + packages/astro/src/integrations/hooks.ts | 5 ++-- packages/astro/src/types/astro.ts | 6 ++-- .../astro/src/types/public/integrations.ts | 28 ++++++++----------- packages/astro/src/types/public/internal.ts | 16 +++++++++++ .../index.ts | 4 +-- 12 files changed, 46 insertions(+), 26 deletions(-) diff --git a/packages/astro/src/actions/integration.ts b/packages/astro/src/actions/integration.ts index 830420836a3d..4c5a19a7abfb 100644 --- a/packages/astro/src/actions/integration.ts +++ b/packages/astro/src/actions/integration.ts @@ -18,10 +18,11 @@ export default function astroIntegrationActionsRouteHandler({ name: VIRTUAL_MODULE_ID, hooks: { async 'astro:config:setup'(params) { - params.injectRoute({ + settings.injectedRoutes.push({ pattern: '/_actions/[...path]', entrypoint: 'astro/actions/runtime/route.js', prerender: false, + origin: 'core', }); params.addMiddleware({ diff --git a/packages/astro/src/assets/endpoint/config.ts b/packages/astro/src/assets/endpoint/config.ts index a910df25cc62..4ffade76caea 100644 --- a/packages/astro/src/assets/endpoint/config.ts +++ b/packages/astro/src/assets/endpoint/config.ts @@ -63,5 +63,6 @@ function getImageEndpointData( pathname: settings.config.image.endpoint.route, prerender: false, fallbackRoutes: [], + origin: 'core', }; } diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 7694f3afa24b..a3006ddebbaa 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -544,6 +544,8 @@ export class experimental_AstroContainer { type, fallbackRoutes: [], isIndex: false, + // TODO: check what we should use there + origin: 'user', }; } diff --git a/packages/astro/src/core/routing/astro-designed-error-pages.ts b/packages/astro/src/core/routing/astro-designed-error-pages.ts index 671221b5d68a..42034ff5c7e0 100644 --- a/packages/astro/src/core/routing/astro-designed-error-pages.ts +++ b/packages/astro/src/core/routing/astro-designed-error-pages.ts @@ -15,6 +15,7 @@ export const DEFAULT_404_ROUTE: RouteData = { route: '/404', fallbackRoutes: [], isIndex: false, + origin: 'core', }; export const DEFAULT_500_ROUTE: RouteData = { @@ -29,6 +30,7 @@ export const DEFAULT_500_ROUTE: RouteData = { route: '/500', fallbackRoutes: [], isIndex: false, + origin: 'core', }; export function ensure404Route(manifest: ManifestData) { diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index ef437f730960..c06e701b0ff6 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -256,6 +256,7 @@ function createFileBasedRoutes( prerender, fallbackRoutes: [], distURL: [], + origin: 'user', }); } } @@ -321,6 +322,7 @@ function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): Rou prerender: prerenderInjected ?? prerender, fallbackRoutes: [], distURL: [], + origin: 'integration', }); } @@ -390,6 +392,7 @@ function createRedirectRoutes( redirectRoute: routeMap.get(destination), fallbackRoutes: [], distURL: [], + origin: 'user', }); } diff --git a/packages/astro/src/core/routing/manifest/serialization.ts b/packages/astro/src/core/routing/manifest/serialization.ts index c0cf600f0b79..3d6214876c00 100644 --- a/packages/astro/src/core/routing/manifest/serialization.ts +++ b/packages/astro/src/core/routing/manifest/serialization.ts @@ -41,5 +41,6 @@ export function deserializeRouteData(rawRouteData: SerializedRouteData): RouteDa return deserializeRouteData(fallback); }), isIndex: rawRouteData.isIndex, + origin: rawRouteData.origin, }; } diff --git a/packages/astro/src/core/server-islands/endpoint.ts b/packages/astro/src/core/server-islands/endpoint.ts index 540f75b843e6..89ccaf403869 100644 --- a/packages/astro/src/core/server-islands/endpoint.ts +++ b/packages/astro/src/core/server-islands/endpoint.ts @@ -31,6 +31,7 @@ export function getServerIslandRouteData(config: ConfigFields) { isIndex: false, fallbackRoutes: [], route: SERVER_ISLAND_ROUTE, + origin: 'core', }; return route; } diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index ed7ca6d06711..92f38a2eeca7 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -206,7 +206,7 @@ export async function runHookConfigSetup({ ); injectRoute.entrypoint = injectRoute.entryPoint as string; } - updatedSettings.injectedRoutes.push(injectRoute); + updatedSettings.injectedRoutes.push({ ...injectRoute, origin: 'integration' }); }, addWatchFile: (path) => { updatedSettings.watchFiles.push(path instanceof URL ? fileURLToPath(path) : path); @@ -678,8 +678,7 @@ function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute entrypoint: route.component, pattern: route.route, params: route.params, - // TODO: supports other origins - origin: 'user', + origin: route.origin, }; } diff --git a/packages/astro/src/types/astro.ts b/packages/astro/src/types/astro.ts index 7e2f2af7e073..654652c422b3 100644 --- a/packages/astro/src/types/astro.ts +++ b/packages/astro/src/types/astro.ts @@ -10,12 +10,10 @@ import type { ContentEntryType, DataEntryType } from './public/content.js'; import type { AstroAdapter, AstroRenderer, - InjectedRoute, InjectedScriptStage, InjectedType, - ResolvedInjectedRoute, } from './public/integrations.js'; -import type { RouteData } from './public/internal.js'; +import type { InternalInjectedRoute, RouteData, ResolvedInjectedRoute } from './public/internal.js'; import type { DevToolbarAppEntry } from './public/toolbar.js'; export type SerializedRouteData = Omit< @@ -35,7 +33,7 @@ export interface AstroSettings { config: AstroConfig; adapter: AstroAdapter | undefined; preferences: AstroPreferences; - injectedRoutes: InjectedRoute[]; + injectedRoutes: InternalInjectedRoute[]; resolvedInjectedRoutes: ResolvedInjectedRoute[]; pageExtensions: string[]; contentEntryTypes: ContentEntryType[]; diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 9c1af3164262..3f4f9bdb2887 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -8,7 +8,7 @@ import type { getToolbarServerCommunicationHelpers } from '../../integrations/ho import type { DeepPartial } from '../../type-utils.js'; import type { AstroConfig } from './config.js'; import type { RefreshContentOptions } from './content.js'; -import type { RouteData } from './internal.js'; +import type { InternalInjectedRoute, RouteData } from './internal.js'; import type { DevToolbarAppEntry } from './toolbar.js'; export interface RouteOptions { @@ -138,15 +138,7 @@ export type AstroAdapterFeatureMap = { */ export type InjectedScriptStage = 'before-hydration' | 'head-inline' | 'page' | 'page-ssr'; -export interface InjectedRoute { - pattern: string; - entrypoint: string | URL; - prerender?: boolean; -} - -export interface ResolvedInjectedRoute extends InjectedRoute { - resolvedEntryPoint?: URL; -} +export type InjectedRoute = Omit; export interface InjectedType { filename: string; @@ -253,7 +245,7 @@ export interface AstroIntegration { */ export type IntegrationRouteData = Omit< RouteData, - 'isIndex' | 'fallbackRoutes' | 'redirectRoute' + 'isIndex' | 'fallbackRoutes' | 'redirectRoute' | 'origin' > & { /** * {@link RouteData.redirectRoute} @@ -268,22 +260,26 @@ export interface IntegrationResolvedRoute { * - `src/pages/blog/[...slug].astro` has a pattern of `/blog/[...slug]` * - `src/pages/site/[blog]/[...slug].astro` has a pattern of `/site/[blog]/[...slug]` */ - pattern: string; + pattern: RouteData['route']; + /** * Source component URL */ - entrypoint: string; + entrypoint: RouteData['component']; + /** * Whether the route is prerendered or not */ - prerendered: boolean; + prerendered: RouteData['prerender']; + /** * Dynamic and spread route params * ex. "/pages/[lang]/[...slug].astro" will output the params ['lang', '...slug'] */ - params: Array; + params: RouteData['params']; + /** * Whether the route comes from Astro core, an integration or the user's project */ - origin: 'core' | 'integration' | 'user'; + origin: RouteData['origin']; } diff --git a/packages/astro/src/types/public/internal.ts b/packages/astro/src/types/public/internal.ts index c970ab3d18ac..54688ccee51b 100644 --- a/packages/astro/src/types/public/internal.ts +++ b/packages/astro/src/types/public/internal.ts @@ -136,6 +136,11 @@ export interface RouteData { * - src/pages/blog/index.astro */ isIndex: boolean; + + /** + * Whether the route comes from Astro core, an integration or the user's project + */ + origin: 'core' | 'integration' | 'user'; } /** @@ -284,3 +289,14 @@ export interface SSRMetadata { } export type SSRError = Error & ViteErrorPayload['err']; + +export interface InternalInjectedRoute { + pattern: string; + entrypoint: string | URL; + prerender?: boolean; + origin: RouteData['origin']; +} + +export interface ResolvedInjectedRoute extends InternalInjectedRoute { + resolvedEntryPoint?: URL; +} diff --git a/packages/astro/src/vite-plugin-integrations-container/index.ts b/packages/astro/src/vite-plugin-integrations-container/index.ts index 0af181e39c55..5aa62603c947 100644 --- a/packages/astro/src/vite-plugin-integrations-container/index.ts +++ b/packages/astro/src/vite-plugin-integrations-container/index.ts @@ -5,7 +5,7 @@ import type { AstroSettings } from '../types/astro.js'; import { normalizePath } from 'vite'; import { runHookServerSetup } from '../integrations/hooks.js'; -import type { InjectedRoute, ResolvedInjectedRoute } from '../types/public/integrations.js'; +import type { InternalInjectedRoute, ResolvedInjectedRoute } from '../types/public/index.js'; /** Connect Astro integrations into Vite, as needed. */ export default function astroIntegrationsContainerPlugin({ @@ -33,7 +33,7 @@ export default function astroIntegrationsContainerPlugin({ async function resolveEntryPoint( this: PluginContext, - route: InjectedRoute, + route: InternalInjectedRoute, ): Promise { const resolvedId = await this.resolve(route.entrypoint.toString()) .then((res) => res?.id) From 96f560b995c0256585ee458a958d7dd1f87448ce Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 29 Oct 2024 13:54:53 +0100 Subject: [PATCH 04/24] misc --- packages/astro/src/container/index.ts | 1 - packages/astro/src/vite-plugin-integrations-container/index.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index a3006ddebbaa..c9899a6f676e 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -544,7 +544,6 @@ export class experimental_AstroContainer { type, fallbackRoutes: [], isIndex: false, - // TODO: check what we should use there origin: 'user', }; } diff --git a/packages/astro/src/vite-plugin-integrations-container/index.ts b/packages/astro/src/vite-plugin-integrations-container/index.ts index 5aa62603c947..81b720aef10c 100644 --- a/packages/astro/src/vite-plugin-integrations-container/index.ts +++ b/packages/astro/src/vite-plugin-integrations-container/index.ts @@ -5,7 +5,7 @@ import type { AstroSettings } from '../types/astro.js'; import { normalizePath } from 'vite'; import { runHookServerSetup } from '../integrations/hooks.js'; -import type { InternalInjectedRoute, ResolvedInjectedRoute } from '../types/public/index.js'; +import type { InternalInjectedRoute, ResolvedInjectedRoute } from '../types/public/internal.js'; /** Connect Astro integrations into Vite, as needed. */ export default function astroIntegrationsContainerPlugin({ From 65f5b60aab610c41bb363e41d51ef011b7f0ea3d Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 29 Oct 2024 14:57:01 +0100 Subject: [PATCH 05/24] feat: add test --- .../astro/src/core/routing/manifest/create.ts | 4 +- .../src/vite-plugin-astro-server/plugin.ts | 32 ++-- .../astro/test/units/integrations/api.test.js | 147 +++++++++++++++++- 3 files changed, 163 insertions(+), 20 deletions(-) diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index c06e701b0ff6..fa8fa6d827d2 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -282,7 +282,7 @@ function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): Rou const routes: RouteData[] = []; for (const injectedRoute of settings.injectedRoutes) { - const { pattern: name, entrypoint, prerender: prerenderInjected } = injectedRoute; + const { pattern: name, entrypoint, prerender: prerenderInjected, origin } = injectedRoute; const { resolved, component } = resolveInjectedRoute(entrypoint.toString(), config.root, cwd); const segments = removeLeadingForwardSlash(name) @@ -322,7 +322,7 @@ function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): Rou prerender: prerenderInjected ?? prerender, fallbackRoutes: [], distURL: [], - origin: 'integration', + origin, }); } diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 2a22db6c7729..b7226f1bdc16 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -50,26 +50,24 @@ export default function createVitePluginAstroServer({ const controller = createController({ loader }); const localStorage = new AsyncLocalStorage(); - /** rebuild the route cache + manifest, as needed. */ - async function rebuildManifest(needsManifestRebuild: boolean) { + /** rebuild the route cache + manifest */ + async function rebuildManifest() { pipeline.clearRouteCache(); - if (needsManifestRebuild) { - routeManifest = injectDefaultDevRoutes( - settings, - devSSRManifest, - await createRouteManifest({ settings, fsMod }, logger), // TODO: Handle partial updates to the manifest - ); - warnMissingAdapter(logger, settings); - pipeline.manifest.checkOrigin = - settings.config.security.checkOrigin && settings.buildOutput === 'server'; - pipeline.setManifestData(routeManifest); - } + routeManifest = injectDefaultDevRoutes( + settings, + devSSRManifest, + await createRouteManifest({ settings, fsMod }, logger), // TODO: Handle partial updates to the manifest + ); + warnMissingAdapter(logger, settings); + pipeline.manifest.checkOrigin = + settings.config.security.checkOrigin && settings.buildOutput === 'server'; + pipeline.setManifestData(routeManifest); } - // Rebuild route manifest on file change, if needed. - viteServer.watcher.on('add', rebuildManifest.bind(null, true)); - viteServer.watcher.on('unlink', rebuildManifest.bind(null, true)); - viteServer.watcher.on('change', rebuildManifest.bind(null, false)); + // Rebuild route manifest on file change + viteServer.watcher.on('add', rebuildManifest.bind(null)); + viteServer.watcher.on('unlink', rebuildManifest.bind(null)); + viteServer.watcher.on('change', rebuildManifest.bind(null)); function handleUnhandledRejection(rejection: any) { const error = new AstroError({ diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index f2365c006b39..6f100ef5259c 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -7,7 +7,7 @@ import { runHookBuildSetup, runHookConfigSetup, } from '../../../dist/integrations/hooks.js'; -import { defaultLogger } from '../test-utils.js'; +import { createFixture, defaultLogger, runInContainer } from '../test-utils.js'; const defaultConfig = { root: new URL('./', import.meta.url), @@ -131,6 +131,151 @@ describe('Integration API', () => { assert.equal(updatedSettings.config.site, site); assert.equal(updatedSettings.config.integrations.length, 2); }); + + describe('Routes resolved hooks', () => { + it('should work in dev', async () => { + let routes = []; + const fixture = await createFixture({ + '/src/pages/about.astro': '', + '/src/actions.ts': 'export const server = {}', + '/src/foo.astro': '', + }); + + await runInContainer( + { + inlineConfig: { + root: fixture.path, + integrations: [ + { + name: 'test', + hooks: { + 'astro:config:setup': (params) => { + params.injectRoute({ + entrypoint: './src/foo.astro', + pattern: '/foo', + }); + }, + 'astro:routes:resolved': (params) => { + routes = params.routes; + }, + }, + }, + ], + }, + }, + async (container) => { + assert.deepEqual( + routes.sort(), + [ + { + prerendered: false, + entrypoint: '../../../../dist/actions/runtime/route.js', + pattern: '/_actions/[...path]', + params: ['...path'], + origin: 'core', + }, + { + prerendered: true, + entrypoint: 'src/pages/about.astro', + pattern: '/about', + params: [], + origin: 'user', + }, + { + prerendered: true, + entrypoint: 'src/foo.astro', + pattern: '/foo', + params: [], + origin: 'integration', + }, + ].sort(), + ); + + await fixture.writeFile('/src/pages/bar.astro', ''); + container.viteServer.watcher.emit( + 'add', + fixture.getPath('/src/pages/bar.astro').replace(/\\/g, '/'), + ); + await new Promise((r) => setTimeout(r, 100)); + + assert.deepEqual( + routes.sort(), + [ + { + prerendered: false, + entrypoint: '../../../../dist/actions/runtime/route.js', + pattern: '/_actions/[...path]', + params: ['...path'], + origin: 'core', + }, + { + prerendered: true, + entrypoint: 'src/pages/about.astro', + pattern: '/about', + params: [], + origin: 'user', + }, + { + prerendered: true, + entrypoint: 'src/pages/bar.astro', + pattern: '/bar', + params: [], + origin: 'user', + }, + { + prerendered: true, + entrypoint: 'src/foo.astro', + pattern: '/foo', + params: [], + origin: 'integration', + }, + ].sort(), + ); + + await fixture.writeFile('/src/pages/about.astro', '---\nexport const prerender=false\n'); + container.viteServer.watcher.emit( + 'change', + fixture.getPath('/src/pages/about.astro').replace(/\\/g, '/'), + ); + await new Promise((r) => setTimeout(r, 100)); + + assert.deepEqual( + routes.sort(), + [ + { + prerendered: false, + entrypoint: '../../../../dist/actions/runtime/route.js', + pattern: '/_actions/[...path]', + params: ['...path'], + origin: 'core', + }, + { + prerendered: false, + entrypoint: 'src/pages/about.astro', + pattern: '/about', + params: [], + origin: 'user', + }, + { + prerendered: true, + entrypoint: 'src/pages/bar.astro', + pattern: '/bar', + params: [], + origin: 'user', + }, + { + prerendered: true, + entrypoint: 'src/foo.astro', + pattern: '/foo', + params: [], + origin: 'integration', + }, + ].sort(), + ); + }, + ); + }); + }); }); describe('Astro feature map', function () { From 75a84dce5533ceb9bc9792d462272c453c0890d8 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 29 Oct 2024 15:03:59 +0100 Subject: [PATCH 06/24] feat: add changeset --- .changeset/giant-ravens-look.md | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .changeset/giant-ravens-look.md diff --git a/.changeset/giant-ravens-look.md b/.changeset/giant-ravens-look.md new file mode 100644 index 000000000000..6c5b00fb5c5c --- /dev/null +++ b/.changeset/giant-ravens-look.md @@ -0,0 +1,43 @@ +--- +'astro': minor +--- + +Adds a new `astro:routes:resolved` hook to the Integration API, and deprecates `routes` passed to `astro:build:done` + +When building an integration, you can now get access to routes inside the `astro:routes:resolved` hook: + +```js +const integration = () => { + return { + name: 'my-integration', + hooks: { + 'astro:routes:resolved': ({ routes }) => { + console.log(routes) + } + } + } +} +``` + +This hook runs before `astro:config:done`, and whenever a route changes in development. + +`routes` from `astro:build:done` is now deprecated. We recommend you use the new hook instead: + +```diff +const integration = () => { ++ let routes + return { + name: 'my-integration', + hooks: { ++ 'astro:routes:resolved': (params) => { ++ routes = params.routes ++ }, + 'astro:build:done': ({ +- routes + }) => { + console.log(routes) + } + } + } +} +``` \ No newline at end of file From 3a3b083dcf9f02a6044eefe2a174816a996b75b4 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 1 Nov 2024 14:08:52 +0100 Subject: [PATCH 07/24] Update packages/astro/src/types/public/integrations.ts Co-authored-by: Luiz Ferraz --- packages/astro/src/types/public/integrations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 3f4f9bdb2887..16ba0a9de696 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -226,7 +226,7 @@ export interface BaseIntegrationHooks { logger: AstroIntegrationLogger; }) => void | Promise; 'astro:routes:resolved': (options: { - routes: Array; + routes: IntegrationResolvedRoute[]; logger: AstroIntegrationLogger; }) => void | Promise; } From ec16abfb5e5ab85bc27e03c3b260d8d6c73b3e3b Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 1 Nov 2024 14:11:34 +0100 Subject: [PATCH 08/24] feat: rename property --- packages/astro/src/integrations/hooks.ts | 2 +- packages/astro/src/types/public/integrations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 92f38a2eeca7..ecda3e971567 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -674,7 +674,7 @@ export async function runHookRoutesResolved({ function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute { return { - prerendered: route.prerender, + isPrerendered: route.prerender, entrypoint: route.component, pattern: route.route, params: route.params, diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 16ba0a9de696..a34ef4b5f0b2 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -270,7 +270,7 @@ export interface IntegrationResolvedRoute { /** * Whether the route is prerendered or not */ - prerendered: RouteData['prerender']; + isPrerendered: RouteData['prerender']; /** * Dynamic and spread route params From 7e26fa4ec9b3ae2f8cb19f7fff27f3d96fa214b4 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 1 Nov 2024 14:53:59 +0100 Subject: [PATCH 09/24] feat: handle partial manifest updates in dev --- .../src/vite-plugin-astro-server/plugin.ts | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index b7226f1bdc16..f0ef42d1d929 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -21,6 +21,9 @@ import { recordServerError } from './error.js'; import { DevPipeline } from './pipeline.js'; import { handleRequest } from './request.js'; import { setRouteError } from './server-state.js'; +import { fileURLToPath } from 'node:url'; +import { getRoutePrerenderOption } from '../core/routing/manifest/prerender.js'; +import { runHookRoutesResolved } from '../integrations/hooks.js'; export interface AstroPluginOptions { settings: AstroSettings; @@ -51,13 +54,36 @@ export default function createVitePluginAstroServer({ const localStorage = new AsyncLocalStorage(); /** rebuild the route cache + manifest */ - async function rebuildManifest() { + async function rebuildManifest(path: string | null = null) { pipeline.clearRouteCache(); - routeManifest = injectDefaultDevRoutes( - settings, - devSSRManifest, - await createRouteManifest({ settings, fsMod }, logger), // TODO: Handle partial updates to the manifest - ); + + // If a route changes, we check if it's part of the manifest and check for its prerender value + if (path !== null) { + const route = routeManifest.routes.find( + (r) => path === new URL(r.component, settings.config.root).pathname, + ); + if (!route) { + return; + } + if (route.type !== 'page' && route.type !== 'endpoint') return; + + const routePath = fileURLToPath(new URL(route.component, settings.config.root)); + if (!fsMod.existsSync(routePath)) { + // Route was renamed so it does not exist anymore + return; + } + const content = await fsMod.promises.readFile(routePath, 'utf-8'); + await getRoutePrerenderOption(content, route, settings, logger); + + await runHookRoutesResolved({ routes: routeManifest.routes, settings, logger }); + } else { + routeManifest = injectDefaultDevRoutes( + settings, + devSSRManifest, + await createRouteManifest({ settings, fsMod }, logger), + ); + } + warnMissingAdapter(logger, settings); pipeline.manifest.checkOrigin = settings.config.security.checkOrigin && settings.buildOutput === 'server'; @@ -65,9 +91,9 @@ export default function createVitePluginAstroServer({ } // Rebuild route manifest on file change - viteServer.watcher.on('add', rebuildManifest.bind(null)); - viteServer.watcher.on('unlink', rebuildManifest.bind(null)); - viteServer.watcher.on('change', rebuildManifest.bind(null)); + viteServer.watcher.on('add', () => rebuildManifest()); + viteServer.watcher.on('unlink', () => rebuildManifest()); + viteServer.watcher.on('change', (path) => rebuildManifest(path)); function handleUnhandledRejection(rejection: any) { const error = new AstroError({ From db92a982fed761f9b29a34dca80f287211467821 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 16:45:32 +0100 Subject: [PATCH 10/24] feat: include more properties and rename origin things --- packages/astro/src/actions/integration.ts | 2 +- packages/astro/src/assets/endpoint/config.ts | 2 +- packages/astro/src/container/index.ts | 2 +- .../routing/astro-designed-error-pages.ts | 4 +-- .../astro/src/core/routing/manifest/create.ts | 4 +-- .../astro/src/core/server-islands/endpoint.ts | 2 +- packages/astro/src/integrations/hooks.ts | 11 +++++- .../astro/src/types/public/integrations.ts | 35 +++++++++++-------- packages/astro/src/types/public/internal.ts | 2 +- 9 files changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/astro/src/actions/integration.ts b/packages/astro/src/actions/integration.ts index 60213e415042..13d76e8b6023 100644 --- a/packages/astro/src/actions/integration.ts +++ b/packages/astro/src/actions/integration.ts @@ -22,7 +22,7 @@ export default function astroIntegrationActionsRouteHandler({ pattern: ACTION_RPC_ROUTE_PATTERN, entrypoint: 'astro/actions/runtime/route.js', prerender: false, - origin: 'core', + origin: 'internal', }); params.addMiddleware({ diff --git a/packages/astro/src/assets/endpoint/config.ts b/packages/astro/src/assets/endpoint/config.ts index 4ffade76caea..b9309d446997 100644 --- a/packages/astro/src/assets/endpoint/config.ts +++ b/packages/astro/src/assets/endpoint/config.ts @@ -63,6 +63,6 @@ function getImageEndpointData( pathname: settings.config.image.endpoint.route, prerender: false, fallbackRoutes: [], - origin: 'core', + origin: 'internal', }; } diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index c9899a6f676e..db0e204ed3db 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -544,7 +544,7 @@ export class experimental_AstroContainer { type, fallbackRoutes: [], isIndex: false, - origin: 'user', + origin: 'project', }; } diff --git a/packages/astro/src/core/routing/astro-designed-error-pages.ts b/packages/astro/src/core/routing/astro-designed-error-pages.ts index 42034ff5c7e0..4348e6e974f0 100644 --- a/packages/astro/src/core/routing/astro-designed-error-pages.ts +++ b/packages/astro/src/core/routing/astro-designed-error-pages.ts @@ -15,7 +15,7 @@ export const DEFAULT_404_ROUTE: RouteData = { route: '/404', fallbackRoutes: [], isIndex: false, - origin: 'core', + origin: 'internal', }; export const DEFAULT_500_ROUTE: RouteData = { @@ -30,7 +30,7 @@ export const DEFAULT_500_ROUTE: RouteData = { route: '/500', fallbackRoutes: [], isIndex: false, - origin: 'core', + origin: 'internal', }; export function ensure404Route(manifest: ManifestData) { diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index fa8fa6d827d2..bf7f46acd1a7 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -256,7 +256,7 @@ function createFileBasedRoutes( prerender, fallbackRoutes: [], distURL: [], - origin: 'user', + origin: 'project', }); } } @@ -392,7 +392,7 @@ function createRedirectRoutes( redirectRoute: routeMap.get(destination), fallbackRoutes: [], distURL: [], - origin: 'user', + origin: 'project', }); } diff --git a/packages/astro/src/core/server-islands/endpoint.ts b/packages/astro/src/core/server-islands/endpoint.ts index 89ccaf403869..999826a6f8a7 100644 --- a/packages/astro/src/core/server-islands/endpoint.ts +++ b/packages/astro/src/core/server-islands/endpoint.ts @@ -31,7 +31,7 @@ export function getServerIslandRouteData(config: ConfigFields) { isIndex: false, fallbackRoutes: [], route: SERVER_ISLAND_ROUTE, - origin: 'core', + origin: 'internal', }; return route; } diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index ecda3e971567..3782f2c0237c 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -206,7 +206,7 @@ export async function runHookConfigSetup({ ); injectRoute.entrypoint = injectRoute.entryPoint as string; } - updatedSettings.injectedRoutes.push({ ...injectRoute, origin: 'integration' }); + updatedSettings.injectedRoutes.push({ ...injectRoute, origin: 'external' }); }, addWatchFile: (path) => { updatedSettings.watchFiles.push(path instanceof URL ? fileURLToPath(path) : path); @@ -679,6 +679,15 @@ function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute pattern: route.route, params: route.params, origin: route.origin, + generate: route.generate, + patternRegex: route.pattern, + segments: route.segments, + type: route.type, + pathname: route.pathname, + redirect: route.redirect, + redirectRoute: route.redirectRoute + ? toIntegrationResolvedRoute(route.redirectRoute) + : undefined, }; } diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index a34ef4b5f0b2..595a9950d2d3 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -253,33 +253,40 @@ export type IntegrationRouteData = Omit< redirectRoute?: IntegrationRouteData; }; -export interface IntegrationResolvedRoute { +export interface IntegrationResolvedRoute + extends Omit< + RouteData, + | 'isIndex' + | 'fallbackRoutes' + | 'redirectRoute' + | 'route' + | 'pattern' + | 'component' + | 'prerender' + | 'distURL' + > { /** - * The current **pattern** of the route. For example: - * - `src/pages/index.astro` has a pattern of `/` - * - `src/pages/blog/[...slug].astro` has a pattern of `/blog/[...slug]` - * - `src/pages/site/[blog]/[...slug].astro` has a pattern of `/site/[blog]/[...slug]` + * {@link RouteData.route} */ pattern: RouteData['route']; /** - * Source component URL + * {@link RouteData.pattern} */ - entrypoint: RouteData['component']; + patternRegex: RouteData['pattern']; /** - * Whether the route is prerendered or not + * {@link RouteData.component} */ - isPrerendered: RouteData['prerender']; + entrypoint: RouteData['component']; /** - * Dynamic and spread route params - * ex. "/pages/[lang]/[...slug].astro" will output the params ['lang', '...slug'] + * {@link RouteData.prerender} */ - params: RouteData['params']; + isPrerendered: RouteData['prerender']; /** - * Whether the route comes from Astro core, an integration or the user's project + * {@link RouteData.redirectRoute} */ - origin: RouteData['origin']; + redirectRoute?: IntegrationResolvedRoute; } diff --git a/packages/astro/src/types/public/internal.ts b/packages/astro/src/types/public/internal.ts index 54688ccee51b..297e65f89cb7 100644 --- a/packages/astro/src/types/public/internal.ts +++ b/packages/astro/src/types/public/internal.ts @@ -140,7 +140,7 @@ export interface RouteData { /** * Whether the route comes from Astro core, an integration or the user's project */ - origin: 'core' | 'integration' | 'user'; + origin: 'internal' | 'external' | 'project'; } /** From fc4e42ccee08171949f2b5e5a95a6cd91f0a9333 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 16:46:51 +0100 Subject: [PATCH 11/24] feat: update origin --- packages/astro/src/container/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index db0e204ed3db..2564e28750ac 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -544,7 +544,7 @@ export class experimental_AstroContainer { type, fallbackRoutes: [], isIndex: false, - origin: 'project', + origin: 'internal', }; } From ebb12f945ecff8678dbaf23e7e60347db023db00 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 16:55:38 +0100 Subject: [PATCH 12/24] feat: deprecate properties instead of whole object --- .changeset/giant-ravens-look.md | 14 +++-- .../astro/src/types/public/integrations.ts | 60 ++++++++++++++++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/.changeset/giant-ravens-look.md b/.changeset/giant-ravens-look.md index 6c5b00fb5c5c..177fdcbd7b2e 100644 --- a/.changeset/giant-ravens-look.md +++ b/.changeset/giant-ravens-look.md @@ -2,7 +2,7 @@ 'astro': minor --- -Adds a new `astro:routes:resolved` hook to the Integration API, and deprecates `routes` passed to `astro:build:done` +Adds a new `astro:routes:resolved` hook to the Integration API, and deprecates most `routes` properties passed to `astro:build:done` When building an integration, you can now get access to routes inside the `astro:routes:resolved` hook: @@ -21,7 +21,7 @@ const integration = () => { This hook runs before `astro:config:done`, and whenever a route changes in development. -`routes` from `astro:build:done` is now deprecated. We recommend you use the new hook instead: +Most `routes` properties from `astro:build:done` are now deprecated. We recommend you use the new hook instead: ```diff const integration = () => { @@ -32,9 +32,13 @@ const integration = () => { + 'astro:routes:resolved': (params) => { + routes = params.routes + }, - 'astro:build:done': ({ -- routes - }) => { + 'astro:build:done': (params) => { ++ for (const _route of params.routes) { ++ const route = routes.find(r => r.pattern === _route.route) ++ if (route) { ++ route.distURL = _route.distURL ++ } ++ } console.log(routes) } } diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 595a9950d2d3..5ac3ad097c7f 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -217,7 +217,6 @@ export interface BaseIntegrationHooks { 'astro:build:done': (options: { pages: { pathname: string }[]; dir: URL; - /** @deprecated Use `routes` from `astro:routes:resolved` instead */ routes: IntegrationRouteData[]; logger: AstroIntegrationLogger; }) => void | Promise; @@ -243,12 +242,67 @@ export interface AstroIntegration { /** * A smaller version of the {@link RouteData} that is used in the integrations. */ -export type IntegrationRouteData = Omit< +export type IntegrationRouteData = Pick< RouteData, - 'isIndex' | 'fallbackRoutes' | 'redirectRoute' | 'origin' + 'route' | 'distURL' > & { + /** + * {@link RouteData.component} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + component: RouteData['component']; + + /** + * {@link RouteData.generate} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + generate: RouteData['generate']; + + /** + * {@link RouteData.params} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + params: RouteData['params']; + + /** + * {@link RouteData.pathname} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + pathname?: RouteData['pathname']; + + /** + * {@link RouteData.pattern} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + pattern: RouteData['pattern']; + + /** + * {@link RouteData.segments} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + segments: RouteData['segments']; + + /** + * {@link RouteData.type} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + type: RouteData['type']; + + /** + * {@link RouteData.prerender} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + prerender: RouteData['prerender']; + + /** + * {@link RouteData.redirect} + * @deprecated Use `routes` from the `astro:routes:resolved` hook + */ + redirect?: RouteData['redirect']; + /** * {@link RouteData.redirectRoute} + * @deprecated Use `routes` from the `astro:routes:resolved` hook */ redirectRoute?: IntegrationRouteData; }; From b377e0f42d3c08cb6462ae3b055451a9be015522 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 16:58:12 +0100 Subject: [PATCH 13/24] Update packages/astro/src/types/public/internal.ts --- packages/astro/src/types/public/internal.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/astro/src/types/public/internal.ts b/packages/astro/src/types/public/internal.ts index 297e65f89cb7..a17ee76506a0 100644 --- a/packages/astro/src/types/public/internal.ts +++ b/packages/astro/src/types/public/internal.ts @@ -290,6 +290,8 @@ export interface SSRMetadata { export type SSRError = Error & ViteErrorPayload['err']; +// `origin` is set within the hook, but the user doesn't have access to this property. That's why +// we need an intermediary interface export interface InternalInjectedRoute { pattern: string; entrypoint: string | URL; From 33b1165b26e575a9f15659a4cce5f60db443640b Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 17:10:31 +0100 Subject: [PATCH 14/24] feat: update test --- .../astro/test/units/integrations/api.test.js | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index 6f100ef5259c..efac72347211 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -156,7 +156,14 @@ describe('Integration API', () => { }); }, 'astro:routes:resolved': (params) => { - routes = params.routes; + routes = params.routes.map((r) => ({ + isPrerendered: r.isPrerendered, + entrypoint: r.entrypoint, + pattern: r.pattern, + params: r.params, + origin: r.origin, + })); + routes.sort(); }, }, }, @@ -168,25 +175,25 @@ describe('Integration API', () => { routes.sort(), [ { - prerendered: false, + isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', pattern: '/_actions/[...path]', params: ['...path'], - origin: 'core', + origin: 'internal', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/pages/about.astro', pattern: '/about', params: [], - origin: 'user', + origin: 'project', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/foo.astro', pattern: '/foo', params: [], - origin: 'integration', + origin: 'external', }, ].sort(), ); @@ -202,32 +209,32 @@ describe('Integration API', () => { routes.sort(), [ { - prerendered: false, + isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', pattern: '/_actions/[...path]', params: ['...path'], - origin: 'core', + origin: 'internal', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/pages/about.astro', pattern: '/about', params: [], - origin: 'user', + origin: 'project', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/pages/bar.astro', pattern: '/bar', params: [], - origin: 'user', + origin: 'project', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/foo.astro', pattern: '/foo', params: [], - origin: 'integration', + origin: 'external', }, ].sort(), ); @@ -243,32 +250,32 @@ describe('Integration API', () => { routes.sort(), [ { - prerendered: false, + isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', pattern: '/_actions/[...path]', params: ['...path'], - origin: 'core', + origin: 'internal', }, { - prerendered: false, + isPrerendered: false, entrypoint: 'src/pages/about.astro', pattern: '/about', params: [], - origin: 'user', + origin: 'project', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/pages/bar.astro', pattern: '/bar', params: [], - origin: 'user', + origin: 'project', }, { - prerendered: true, + isPrerendered: true, entrypoint: 'src/foo.astro', pattern: '/foo', params: [], - origin: 'integration', + origin: 'external', }, ].sort(), ); From 5576af9468ac7941ec652b80ea5fe0455bf67a98 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 13 Nov 2024 17:25:13 +0100 Subject: [PATCH 15/24] feat: work on test --- packages/astro/test/units/integrations/api.test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index efac72347211..5e955998c9ed 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -163,7 +163,7 @@ describe('Integration API', () => { params: r.params, origin: r.origin, })); - routes.sort(); + routes.sort((a, b) => a.pattern.localeCompare(b.pattern)); }, }, }, @@ -172,7 +172,7 @@ describe('Integration API', () => { }, async (container) => { assert.deepEqual( - routes.sort(), + routes, [ { isPrerendered: false, @@ -195,7 +195,7 @@ describe('Integration API', () => { params: [], origin: 'external', }, - ].sort(), + ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); await fixture.writeFile('/src/pages/bar.astro', ''); @@ -206,7 +206,7 @@ describe('Integration API', () => { await new Promise((r) => setTimeout(r, 100)); assert.deepEqual( - routes.sort(), + routes, [ { isPrerendered: false, @@ -236,7 +236,7 @@ describe('Integration API', () => { params: [], origin: 'external', }, - ].sort(), + ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); await fixture.writeFile('/src/pages/about.astro', '---\nexport const prerender=false\n'); @@ -247,7 +247,7 @@ describe('Integration API', () => { await new Promise((r) => setTimeout(r, 100)); assert.deepEqual( - routes.sort(), + routes, [ { isPrerendered: false, @@ -277,7 +277,7 @@ describe('Integration API', () => { params: [], origin: 'external', }, - ].sort(), + ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); }, ); From 46be686b5d7258519378136a9ca2ff6119f3ca81 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 14 Nov 2024 15:37:10 +0100 Subject: [PATCH 16/24] feat: new assets --- .changeset/giant-ravens-look.md | 17 ++--- packages/astro/src/integrations/hooks.ts | 3 + .../astro/src/types/public/integrations.ts | 62 ++----------------- 3 files changed, 18 insertions(+), 64 deletions(-) diff --git a/.changeset/giant-ravens-look.md b/.changeset/giant-ravens-look.md index 177fdcbd7b2e..a47e77fa341c 100644 --- a/.changeset/giant-ravens-look.md +++ b/.changeset/giant-ravens-look.md @@ -2,7 +2,7 @@ 'astro': minor --- -Adds a new `astro:routes:resolved` hook to the Integration API, and deprecates most `routes` properties passed to `astro:build:done` +Adds a new `astro:routes:resolved` hook to the Integration API. Makes updates to the `astro:build:done` hook by deprecating `routes` and adding a new `assets` map When building an integration, you can now get access to routes inside the `astro:routes:resolved` hook: @@ -21,7 +21,7 @@ const integration = () => { This hook runs before `astro:config:done`, and whenever a route changes in development. -Most `routes` properties from `astro:build:done` are now deprecated. We recommend you use the new hook instead: +The `routes` array from `astro:build:done` are now deprecated. Any useful property is made available on `astro:routes:resolved`, except for `distURL`. Instead, you can use the newly exposed `assets` map:: ```diff const integration = () => { @@ -32,11 +32,14 @@ const integration = () => { + 'astro:routes:resolved': (params) => { + routes = params.routes + }, - 'astro:build:done': (params) => { -+ for (const _route of params.routes) { -+ const route = routes.find(r => r.pattern === _route.route) -+ if (route) { -+ route.distURL = _route.distURL + 'astro:build:done': ({ +- routes ++ assets + }) => { ++ for (const route of routes) { ++ const distURL = assets.get(route.pattern) ++ if (distURL) { ++ Object.assign(route, { distURL }) + } + } console.log(routes) diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 3782f2c0237c..5a4b723b2000 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -601,6 +601,9 @@ export async function runHookBuildDone({ settings, pages, routes, logging }: Run pages: pages.map((p) => ({ pathname: p })), dir, routes: integrationRoutes, + assets: new Map( + routes.filter((r) => r.distURL !== undefined).map((r) => [r.route, r.distURL!]), + ), logger, }), logger: logging, diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index 5ac3ad097c7f..a19f506a182a 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -217,7 +217,9 @@ export interface BaseIntegrationHooks { 'astro:build:done': (options: { pages: { pathname: string }[]; dir: URL; + /** @deprecated Use the `assets` map and the new `astro:routes:resolved` hook */ routes: IntegrationRouteData[]; + assets: Map; logger: AstroIntegrationLogger; }) => void | Promise; 'astro:route:setup': (options: { @@ -241,68 +243,14 @@ export interface AstroIntegration { /** * A smaller version of the {@link RouteData} that is used in the integrations. + * @deprecated Use {@link IntegrationResolvedRoute} */ -export type IntegrationRouteData = Pick< +export type IntegrationRouteData = Omit< RouteData, - 'route' | 'distURL' + 'isIndex' | 'fallbackRoutes' | 'redirectRoute' | 'origin' > & { - /** - * {@link RouteData.component} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - component: RouteData['component']; - - /** - * {@link RouteData.generate} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - generate: RouteData['generate']; - - /** - * {@link RouteData.params} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - params: RouteData['params']; - - /** - * {@link RouteData.pathname} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - pathname?: RouteData['pathname']; - - /** - * {@link RouteData.pattern} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - pattern: RouteData['pattern']; - - /** - * {@link RouteData.segments} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - segments: RouteData['segments']; - - /** - * {@link RouteData.type} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - type: RouteData['type']; - - /** - * {@link RouteData.prerender} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - prerender: RouteData['prerender']; - - /** - * {@link RouteData.redirect} - * @deprecated Use `routes` from the `astro:routes:resolved` hook - */ - redirect?: RouteData['redirect']; - /** * {@link RouteData.redirectRoute} - * @deprecated Use `routes` from the `astro:routes:resolved` hook */ redirectRoute?: IntegrationRouteData; }; From c9dcd7c5269ee297090ddbfceab55469d21e5000 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 14 Nov 2024 15:56:31 +0100 Subject: [PATCH 17/24] fix: test --- .../astro/test/units/integrations/api.test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index 5e955998c9ed..4af6eb3ed968 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -249,6 +249,13 @@ describe('Integration API', () => { assert.deepEqual( routes, [ + { + isPrerendered: false, + entrypoint: '_server-islands.astro', + pattern: '/_server-islands/[name]', + params: ['name'], + origin: 'internal', + }, { isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', @@ -277,6 +284,20 @@ describe('Integration API', () => { params: [], origin: 'external', }, + { + isPrerendered: false, + entrypoint: '../../../../dist/assets/endpoint/node.js', + pattern: '/_image', + params: [], + origin: 'internal', + }, + { + isPrerendered: false, + entrypoint: 'astro-default-404.astro', + pattern: '/404', + params: [], + origin: 'internal', + }, ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); }, From 24600f09e8de5d30e8d80fe93226ee2f20379a09 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 14 Nov 2024 16:08:39 +0100 Subject: [PATCH 18/24] fix: take dev routes into account --- packages/astro/src/core/dev/container.ts | 4 +- .../astro/src/core/routing/manifest/create.ts | 5 ++- .../src/vite-plugin-astro-server/plugin.ts | 7 ++-- .../astro/test/units/integrations/api.test.js | 42 +++++++++++++++++++ 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/packages/astro/src/core/dev/container.ts b/packages/astro/src/core/dev/container.ts index 3f9090498be2..0ca40cd74b3a 100644 --- a/packages/astro/src/core/dev/container.ts +++ b/packages/astro/src/core/dev/container.ts @@ -7,6 +7,7 @@ import * as vite from 'vite'; import { runHookConfigDone, runHookConfigSetup, + runHookRoutesResolved, runHookServerDone, runHookServerStart, } from '../../integrations/hooks.js'; @@ -83,10 +84,11 @@ export async function createContainer({ .filter(Boolean) as string[]; // Create the route manifest already outside of Vite so that `runHookConfigDone` can use it to inform integrations of the build output - let manifest = await createRouteManifest({ settings, fsMod: fs }, logger); + let manifest = await createRouteManifest({ settings, fsMod: fs }, logger, { dev: true }); const devSSRManifest = createDevelopmentManifest(settings); manifest = injectDefaultDevRoutes(settings, devSSRManifest, manifest); + await runHookRoutesResolved({ settings, logger, routes: manifest.routes }); await runHookConfigDone({ settings, logger, command: 'dev' }); diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index bf7f46acd1a7..621164084e9f 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -484,6 +484,7 @@ function detectRouteCollision(a: RouteData, b: RouteData, _config: AstroConfig, export async function createRouteManifest( params: CreateRouteManifestParams, logger: Logger, + { dev = false }: { dev?: boolean } = {}, ): Promise { const { settings } = params; const { config } = settings; @@ -731,7 +732,9 @@ export async function createRouteManifest( } } - await runHookRoutesResolved({ routes, settings, logger }); + if (!dev) { + await runHookRoutesResolved({ routes, settings, logger }); + } return { routes, diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index f0ef42d1d929..471b0a2c55ed 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -57,7 +57,7 @@ export default function createVitePluginAstroServer({ async function rebuildManifest(path: string | null = null) { pipeline.clearRouteCache(); - // If a route changes, we check if it's part of the manifest and check for its prerender value + // If a route changes, we check if it's part of the manifest and check for its prerender value if (path !== null) { const route = routeManifest.routes.find( (r) => path === new URL(r.component, settings.config.root).pathname, @@ -74,15 +74,14 @@ export default function createVitePluginAstroServer({ } const content = await fsMod.promises.readFile(routePath, 'utf-8'); await getRoutePrerenderOption(content, route, settings, logger); - - await runHookRoutesResolved({ routes: routeManifest.routes, settings, logger }); } else { routeManifest = injectDefaultDevRoutes( settings, devSSRManifest, - await createRouteManifest({ settings, fsMod }, logger), + await createRouteManifest({ settings, fsMod }, logger, { dev: true }), ); } + await runHookRoutesResolved({ routes: routeManifest.routes, settings, logger }); warnMissingAdapter(logger, settings); pipeline.manifest.checkOrigin = diff --git a/packages/astro/test/units/integrations/api.test.js b/packages/astro/test/units/integrations/api.test.js index 4af6eb3ed968..97da20c19332 100644 --- a/packages/astro/test/units/integrations/api.test.js +++ b/packages/astro/test/units/integrations/api.test.js @@ -174,6 +174,13 @@ describe('Integration API', () => { assert.deepEqual( routes, [ + { + isPrerendered: false, + entrypoint: '_server-islands.astro', + pattern: '/_server-islands/[name]', + params: ['name'], + origin: 'internal', + }, { isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', @@ -195,6 +202,20 @@ describe('Integration API', () => { params: [], origin: 'external', }, + { + isPrerendered: false, + entrypoint: '../../../../dist/assets/endpoint/node.js', + pattern: '/_image', + params: [], + origin: 'internal', + }, + { + isPrerendered: false, + entrypoint: 'astro-default-404.astro', + pattern: '/404', + params: [], + origin: 'internal', + }, ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); @@ -208,6 +229,13 @@ describe('Integration API', () => { assert.deepEqual( routes, [ + { + isPrerendered: false, + entrypoint: '_server-islands.astro', + pattern: '/_server-islands/[name]', + params: ['name'], + origin: 'internal', + }, { isPrerendered: false, entrypoint: '../../../../dist/actions/runtime/route.js', @@ -236,6 +264,20 @@ describe('Integration API', () => { params: [], origin: 'external', }, + { + isPrerendered: false, + entrypoint: '../../../../dist/assets/endpoint/node.js', + pattern: '/_image', + params: [], + origin: 'internal', + }, + { + isPrerendered: false, + entrypoint: 'astro-default-404.astro', + pattern: '/404', + params: [], + origin: 'internal', + }, ].sort((a, b) => a.pattern.localeCompare(b.pattern)), ); From 93a69e24147894735bb34238f02a7978c1d84a31 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 15 Nov 2024 15:24:52 +0100 Subject: [PATCH 19/24] Update packages/astro/src/vite-plugin-astro-server/plugin.ts Co-authored-by: Emanuele Stoppa --- packages/astro/src/vite-plugin-astro-server/plugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 471b0a2c55ed..14730c9601ff 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -90,9 +90,9 @@ export default function createVitePluginAstroServer({ } // Rebuild route manifest on file change - viteServer.watcher.on('add', () => rebuildManifest()); - viteServer.watcher.on('unlink', () => rebuildManifest()); - viteServer.watcher.on('change', (path) => rebuildManifest(path)); + viteServer.watcher.on('add', rebuildManifest); + viteServer.watcher.on('unlink', rebuildManifest); + viteServer.watcher.on('change', rebuildManifest); function handleUnhandledRejection(rejection: any) { const error = new AstroError({ From e837affae21b0061722ab511fe5a158125a77afd Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 15 Nov 2024 15:32:31 +0100 Subject: [PATCH 20/24] feat: address review --- packages/astro/src/vite-plugin-astro-server/plugin.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 14730c9601ff..8f40d9edcf9f 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -59,9 +59,7 @@ export default function createVitePluginAstroServer({ // If a route changes, we check if it's part of the manifest and check for its prerender value if (path !== null) { - const route = routeManifest.routes.find( - (r) => path === new URL(r.component, settings.config.root).pathname, - ); + const route = routeManifest.routes.find((r) => path.endsWith(r.component)); if (!route) { return; } @@ -90,8 +88,8 @@ export default function createVitePluginAstroServer({ } // Rebuild route manifest on file change - viteServer.watcher.on('add', rebuildManifest); - viteServer.watcher.on('unlink', rebuildManifest); + viteServer.watcher.on('add', rebuildManifest.bind(null)); + viteServer.watcher.on('unlink', rebuildManifest.bind(null)); viteServer.watcher.on('change', rebuildManifest); function handleUnhandledRejection(rejection: any) { From 12088d0a9ffdde674a46792a360fe11cb76b883b Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 18 Nov 2024 15:37:17 +0100 Subject: [PATCH 21/24] fix: check and calls --- .../astro/src/vite-plugin-astro-server/plugin.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 8f40d9edcf9f..14b900f14975 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -66,12 +66,10 @@ export default function createVitePluginAstroServer({ if (route.type !== 'page' && route.type !== 'endpoint') return; const routePath = fileURLToPath(new URL(route.component, settings.config.root)); - if (!fsMod.existsSync(routePath)) { - // Route was renamed so it does not exist anymore - return; - } - const content = await fsMod.promises.readFile(routePath, 'utf-8'); - await getRoutePrerenderOption(content, route, settings, logger); + try { + const content = await fsMod.promises.readFile(routePath, 'utf-8'); + await getRoutePrerenderOption(content, route, settings, logger); + } catch (_) {} } else { routeManifest = injectDefaultDevRoutes( settings, @@ -88,8 +86,8 @@ export default function createVitePluginAstroServer({ } // Rebuild route manifest on file change - viteServer.watcher.on('add', rebuildManifest.bind(null)); - viteServer.watcher.on('unlink', rebuildManifest.bind(null)); + viteServer.watcher.on('add', rebuildManifest.bind(null, null)); + viteServer.watcher.on('unlink', rebuildManifest.bind(null, null)); viteServer.watcher.on('change', rebuildManifest); function handleUnhandledRejection(rejection: any) { From e1f53d5adc5b10e94e43bbd7e4204a01ce2b674a Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 19 Nov 2024 14:57:09 +0100 Subject: [PATCH 22/24] feat: address reviews --- packages/astro/src/types/public/integrations.ts | 11 ++--------- packages/astro/src/vite-plugin-astro-server/plugin.ts | 4 +++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/astro/src/types/public/integrations.ts b/packages/astro/src/types/public/integrations.ts index a19f506a182a..2d0b13e96300 100644 --- a/packages/astro/src/types/public/integrations.ts +++ b/packages/astro/src/types/public/integrations.ts @@ -256,16 +256,9 @@ export type IntegrationRouteData = Omit< }; export interface IntegrationResolvedRoute - extends Omit< + extends Pick< RouteData, - | 'isIndex' - | 'fallbackRoutes' - | 'redirectRoute' - | 'route' - | 'pattern' - | 'component' - | 'prerender' - | 'distURL' + 'generate' | 'params' | 'pathname' | 'segments' | 'type' | 'redirect' | 'origin' > { /** * {@link RouteData.route} diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 14b900f14975..61eae2cc2ba4 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -59,7 +59,9 @@ export default function createVitePluginAstroServer({ // If a route changes, we check if it's part of the manifest and check for its prerender value if (path !== null) { - const route = routeManifest.routes.find((r) => path.endsWith(r.component)); + const route = routeManifest.routes.find( + (r) => path === new URL(r.component, settings.config.root).pathname, + ); if (!route) { return; } From 539d40f3d28e9d567bc55dc8103fa69cc5ecf986 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 19 Nov 2024 16:11:41 +0100 Subject: [PATCH 23/24] Apply suggestions from code review Co-authored-by: Sarah Rainsberger --- .changeset/giant-ravens-look.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/giant-ravens-look.md b/.changeset/giant-ravens-look.md index a47e77fa341c..dfa5d6d95bee 100644 --- a/.changeset/giant-ravens-look.md +++ b/.changeset/giant-ravens-look.md @@ -2,7 +2,7 @@ 'astro': minor --- -Adds a new `astro:routes:resolved` hook to the Integration API. Makes updates to the `astro:build:done` hook by deprecating `routes` and adding a new `assets` map +Adds a new `astro:routes:resolved` hook to the Integration API. Also update the `astro:build:done` hook by deprecating `routes` and adding a new `assets` map. When building an integration, you can now get access to routes inside the `astro:routes:resolved` hook: @@ -21,7 +21,7 @@ const integration = () => { This hook runs before `astro:config:done`, and whenever a route changes in development. -The `routes` array from `astro:build:done` are now deprecated. Any useful property is made available on `astro:routes:resolved`, except for `distURL`. Instead, you can use the newly exposed `assets` map:: +The `routes` array from `astro:build:done` is now deprecated, and exposed properties are now available on `astro:routes:resolved`, except for `distURL`. For this, you can use the newly exposed `assets` map: ```diff const integration = () => { From 846c3a73407f5f0991d692f87ad9c99345c30c97 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 20 Nov 2024 16:35:13 +0100 Subject: [PATCH 24/24] fix: normalize paths --- packages/astro/src/vite-plugin-astro-server/plugin.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 61eae2cc2ba4..642565161b61 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -2,6 +2,7 @@ import { AsyncLocalStorage } from 'node:async_hooks'; import type fs from 'node:fs'; import { IncomingMessage } from 'node:http'; import type * as vite from 'vite'; +import { normalizePath } from 'vite'; import type { SSRManifest, SSRManifestI18n } from '../core/app/types.js'; import { warnMissingAdapter } from '../core/dev/adapter-validation.js'; import { createKey } from '../core/encryption.js'; @@ -60,7 +61,9 @@ export default function createVitePluginAstroServer({ // If a route changes, we check if it's part of the manifest and check for its prerender value if (path !== null) { const route = routeManifest.routes.find( - (r) => path === new URL(r.component, settings.config.root).pathname, + (r) => + normalizePath(path) === + normalizePath(fileURLToPath(new URL(r.component, settings.config.root))), ); if (!route) { return;