Skip to content

Commit 8309c61

Browse files
florian-lefebvreFryuniematipicosarah11918
authored
feat(next): astro:routes:resolved (#12329)
Co-authored-by: Luiz Ferraz <luiz@lferraz.com> Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
1 parent 3f02d5f commit 8309c61

16 files changed

Lines changed: 434 additions & 35 deletions

File tree

.changeset/giant-ravens-look.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
'astro': minor
3+
---
4+
5+
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.
6+
7+
When building an integration, you can now get access to routes inside the `astro:routes:resolved` hook:
8+
9+
```js
10+
const integration = () => {
11+
return {
12+
name: 'my-integration',
13+
hooks: {
14+
'astro:routes:resolved': ({ routes }) => {
15+
console.log(routes)
16+
}
17+
}
18+
}
19+
}
20+
```
21+
22+
This hook runs before `astro:config:done`, and whenever a route changes in development.
23+
24+
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:
25+
26+
```diff
27+
const integration = () => {
28+
+ let routes
29+
return {
30+
name: 'my-integration',
31+
hooks: {
32+
+ 'astro:routes:resolved': (params) => {
33+
+ routes = params.routes
34+
+ },
35+
'astro:build:done': ({
36+
- routes
37+
+ assets
38+
}) => {
39+
+ for (const route of routes) {
40+
+ const distURL = assets.get(route.pattern)
41+
+ if (distURL) {
42+
+ Object.assign(route, { distURL })
43+
+ }
44+
+ }
45+
console.log(routes)
46+
}
47+
}
48+
}
49+
}
50+
```

packages/astro/src/actions/integration.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ export default function astroIntegrationActionsRouteHandler({
1818
name: VIRTUAL_MODULE_ID,
1919
hooks: {
2020
async 'astro:config:setup'(params) {
21-
params.injectRoute({
21+
settings.injectedRoutes.push({
2222
pattern: ACTION_RPC_ROUTE_PATTERN,
2323
entrypoint: 'astro/actions/runtime/route.js',
2424
prerender: false,
25+
origin: 'internal',
2526
});
2627

2728
params.addMiddleware({

packages/astro/src/assets/endpoint/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ function getImageEndpointData(
6363
pathname: settings.config.image.endpoint.route,
6464
prerender: false,
6565
fallbackRoutes: [],
66+
origin: 'internal',
6667
};
6768
}

packages/astro/src/container/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ export class experimental_AstroContainer {
544544
type,
545545
fallbackRoutes: [],
546546
isIndex: false,
547+
origin: 'internal',
547548
};
548549
}
549550

packages/astro/src/core/dev/container.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vite from 'vite';
77
import {
88
runHookConfigDone,
99
runHookConfigSetup,
10+
runHookRoutesResolved,
1011
runHookServerDone,
1112
runHookServerStart,
1213
} from '../../integrations/hooks.js';
@@ -83,10 +84,11 @@ export async function createContainer({
8384
.filter(Boolean) as string[];
8485

8586
// Create the route manifest already outside of Vite so that `runHookConfigDone` can use it to inform integrations of the build output
86-
let manifest = await createRouteManifest({ settings, fsMod: fs }, logger);
87+
let manifest = await createRouteManifest({ settings, fsMod: fs }, logger, { dev: true });
8788
const devSSRManifest = createDevelopmentManifest(settings);
8889

8990
manifest = injectDefaultDevRoutes(settings, devSSRManifest, manifest);
91+
await runHookRoutesResolved({ settings, logger, routes: manifest.routes });
9092

9193
await runHookConfigDone({ settings, logger, command: 'dev' });
9294

packages/astro/src/core/routing/astro-designed-error-pages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const DEFAULT_404_ROUTE: RouteData = {
1515
route: '/404',
1616
fallbackRoutes: [],
1717
isIndex: false,
18+
origin: 'internal',
1819
};
1920

2021
export const DEFAULT_500_ROUTE: RouteData = {
@@ -29,6 +30,7 @@ export const DEFAULT_500_ROUTE: RouteData = {
2930
route: '/500',
3031
fallbackRoutes: [],
3132
isIndex: false,
33+
origin: 'internal',
3234
};
3335

3436
export function ensure404Route(manifest: ManifestData) {

packages/astro/src/core/routing/manifest/create.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { routeComparator } from '../priority.js';
2020
import { getRouteGenerator } from './generator.js';
2121
import { getPattern } from './pattern.js';
2222
import { getRoutePrerenderOption } from './prerender.js';
23+
import { runHookRoutesResolved } from '../../../integrations/hooks.js';
2324
const require = createRequire(import.meta.url);
2425

2526
interface Item {
@@ -255,6 +256,7 @@ function createFileBasedRoutes(
255256
prerender,
256257
fallbackRoutes: [],
257258
distURL: [],
259+
origin: 'project',
258260
});
259261
}
260262
}
@@ -280,7 +282,7 @@ function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): Rou
280282
const routes: RouteData[] = [];
281283

282284
for (const injectedRoute of settings.injectedRoutes) {
283-
const { pattern: name, entrypoint, prerender: prerenderInjected } = injectedRoute;
285+
const { pattern: name, entrypoint, prerender: prerenderInjected, origin } = injectedRoute;
284286
const { resolved, component } = resolveInjectedRoute(entrypoint.toString(), config.root, cwd);
285287

286288
const segments = removeLeadingForwardSlash(name)
@@ -320,6 +322,7 @@ function createInjectedRoutes({ settings, cwd }: CreateRouteManifestParams): Rou
320322
prerender: prerenderInjected ?? prerender,
321323
fallbackRoutes: [],
322324
distURL: [],
325+
origin,
323326
});
324327
}
325328

@@ -389,6 +392,7 @@ function createRedirectRoutes(
389392
redirectRoute: routeMap.get(destination),
390393
fallbackRoutes: [],
391394
distURL: [],
395+
origin: 'project',
392396
});
393397
}
394398

@@ -480,6 +484,7 @@ function detectRouteCollision(a: RouteData, b: RouteData, _config: AstroConfig,
480484
export async function createRouteManifest(
481485
params: CreateRouteManifestParams,
482486
logger: Logger,
487+
{ dev = false }: { dev?: boolean } = {},
483488
): Promise<ManifestData> {
484489
const { settings } = params;
485490
const { config } = settings;
@@ -727,6 +732,10 @@ export async function createRouteManifest(
727732
}
728733
}
729734

735+
if (!dev) {
736+
await runHookRoutesResolved({ routes, settings, logger });
737+
}
738+
730739
return {
731740
routes,
732741
};

packages/astro/src/core/routing/manifest/serialization.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@ export function deserializeRouteData(rawRouteData: SerializedRouteData): RouteDa
4141
return deserializeRouteData(fallback);
4242
}),
4343
isIndex: rawRouteData.isIndex,
44+
origin: rawRouteData.origin,
4445
};
4546
}

packages/astro/src/core/server-islands/endpoint.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function getServerIslandRouteData(config: ConfigFields) {
3131
isIndex: false,
3232
fallbackRoutes: [],
3333
route: SERVER_ISLAND_ROUTE,
34+
origin: 'internal',
3435
};
3536
return route;
3637
}

packages/astro/src/integrations/hooks.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import type {
2424
import type {
2525
AstroIntegration,
2626
AstroRenderer,
27+
BaseIntegrationHooks,
2728
HookParameters,
29+
IntegrationResolvedRoute,
2830
IntegrationRouteData,
2931
RouteOptions,
3032
} from '../types/public/integrations.js';
@@ -39,7 +41,7 @@ async function withTakingALongTimeMsg<T>({
3941
logger,
4042
}: {
4143
name: string;
42-
hookName: string;
44+
hookName: keyof BaseIntegrationHooks;
4345
hookResult: T | Promise<T>;
4446
timeoutMs?: number;
4547
logger: Logger;
@@ -204,7 +206,7 @@ export async function runHookConfigSetup({
204206
);
205207
injectRoute.entrypoint = injectRoute.entryPoint as string;
206208
}
207-
updatedSettings.injectedRoutes.push(injectRoute);
209+
updatedSettings.injectedRoutes.push({ ...injectRoute, origin: 'external' });
208210
},
209211
addWatchFile: (path) => {
210212
updatedSettings.watchFiles.push(path instanceof URL ? fileURLToPath(path) : path);
@@ -599,6 +601,9 @@ export async function runHookBuildDone({ settings, pages, routes, logging }: Run
599601
pages: pages.map((p) => ({ pathname: p })),
600602
dir,
601603
routes: integrationRoutes,
604+
assets: new Map(
605+
routes.filter((r) => r.distURL !== undefined).map((r) => [r.route, r.distURL!]),
606+
),
602607
logger,
603608
}),
604609
logger: logging,
@@ -648,6 +653,47 @@ export async function runHookRouteSetup({
648653
}
649654
}
650655

656+
export async function runHookRoutesResolved({
657+
routes,
658+
settings,
659+
logger,
660+
}: { routes: Array<RouteData>; settings: AstroSettings; logger: Logger }) {
661+
for (const integration of settings.config.integrations) {
662+
if (integration?.hooks?.['astro:routes:resolved']) {
663+
const integrationLogger = getLogger(integration, logger);
664+
665+
await withTakingALongTimeMsg({
666+
name: integration.name,
667+
hookName: 'astro:routes:resolved',
668+
hookResult: integration.hooks['astro:routes:resolved']({
669+
routes: routes.map((route) => toIntegrationResolvedRoute(route)),
670+
logger: integrationLogger,
671+
}),
672+
logger,
673+
});
674+
}
675+
}
676+
}
677+
678+
function toIntegrationResolvedRoute(route: RouteData): IntegrationResolvedRoute {
679+
return {
680+
isPrerendered: route.prerender,
681+
entrypoint: route.component,
682+
pattern: route.route,
683+
params: route.params,
684+
origin: route.origin,
685+
generate: route.generate,
686+
patternRegex: route.pattern,
687+
segments: route.segments,
688+
type: route.type,
689+
pathname: route.pathname,
690+
redirect: route.redirect,
691+
redirectRoute: route.redirectRoute
692+
? toIntegrationResolvedRoute(route.redirectRoute)
693+
: undefined,
694+
};
695+
}
696+
651697
function toIntegrationRouteData(route: RouteData): IntegrationRouteData {
652698
return {
653699
route: route.route,

0 commit comments

Comments
 (0)