Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document new routing priority behavior #6386

Merged
merged 7 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions src/content/docs/en/core-concepts/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -293,32 +293,45 @@ if (!isLoggedIn(cookie)) {

## Route Priority Order

It's possible for multiple routes to match the same URL path. For example each of these routes would match `/posts/create`:
It's possible for multiple routes to match the same URL path. For example all of these routes could match `/posts/create`:
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved

<FileTree>
- src/pages/
- [...slug].astro
- posts/
- create.astro
- [pid].astro
- [page].astro
- [pid].ts
- [...slug].astro
</FileTree>

Astro needs to know which route should be used to build the page. To do so, it sorts them according to the following rules:
Astro needs to know which route should be used to build the page. To do so, it sorts them according to the following rules in order:

- Static routes without path parameters will take precedence over all other routes
- Dynamic routes using named parameters take precedence over rest parameters
- Pre-rendered dynamic routes take precedence over server dynamic routes
- Rest parameters have the lowest priority
- Endpoints always take precedence over pages
- Ties are resolved alphabetically
- More specific rotues (with more path segments) will take precedence over less specific routes. In the example above all routes under `/posts/` take precedence over `/[...slug].astro` at the root.
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved
- Static routes without path parameters will take precedence over dynamic routes. `/posts/create.astro` takes precedence over all the other routes in the example.
- Dynamic routes using named parameters take precedence over rest parameters. `/posts/[page].astro` takes precedence over `/posts/[...slug].astro`.
- Pre-rendered dynamic routes take precedence over server dynamic routes.
- Endpoints take precedence over pages.
- If all the above doesn't decide the order, routes are sorted alphabetically based on the default locale of your Node instalation.
sarah11918 marked this conversation as resolved.
Show resolved Hide resolved

Given the example above, here are a few examples of how the rules will match a requested URL to the route used to build the HTML:

- `pages/posts/create.astro` - Will build `/posts/create`
- `pages/posts/[pid].astro` - Will build `/posts/1`, `/posts/abc`, etc. But not `/posts/create`
- `pages/posts/[...slug].astro` - Will build `/posts/1/2`, `/posts/a/b/c`, etc. But not `/posts/create`, `/posts/1`, `/posts/abc`
- `pages/posts/create.astro` - Will build only `/posts/create`
- `pages/posts/[pid].ts` - Will build `/posts/abc`, `/posts/xyz`, etc. But not `/posts/create`
- `pages/posts/[page].astro` - Will build `/posts/1`, `/posts/2`, etc. But not `/posts/create`, `/posts/abc` nor `/posts/xyz`
- `pages/posts/[...slug].astro` - Will build `/posts/1/2`, `/posts/a/b/c`, etc. But not `/posts/create`, `/posts/1`, `/posts/abc`, etc.
- `pages/[...slug].astro` - Will build `/abc`, `/xyz`, `/abc/xyz`, etc. But not `/posts/create`, `/posts/1`, `/posts/abc`, , etc.

Redirects also follow the same rules, but are prioritized *last*; if there is a file-based route and a redirect with the same route priority level, the file-based route is chosen.
Redirects also follow the same rules and are sorted along with all routes from project files.

Collisions that would make one route completely unused will result in an error while building. For example:
- Declaring a static redirect for route `/home` while having a file `pages/home.astro`;
- Declaring a static page and a static endpoint with the same name, like `pages/data.astro` and `pages/data.ts`;
- Declaring two dynamic pages in SSR mode that equal each other, like `pages/[postId].astro` and `pages/[pageNum].astro`.

:::note
[Integrations](/en/guides/integrations-guide/) may inject routes into your project. Those routes are mixed with your project's file routes and redirects before they are prioritized and collisions are detected.
:::

## Pagination

Expand Down
14 changes: 14 additions & 0 deletions src/content/docs/en/reference/configuration-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,20 @@ You can customize the [redirection status code](https://developer.mozilla.org/en
}
```

Redirects are prioritized following [the same rules](/en/core-concepts/routing/#route-priority-order) as project file-based routes. Previously, redirects always had a lower priority than any project route. This legacy behavior can be enabled by passing `priority: 'legacy'` in the object:

```js ins={6}
{
redirects: {
'/other': {
status: 302,
destination: '/place',
priority: 'legacy',
},
}
}
```

### site

<p>
Expand Down
16 changes: 14 additions & 2 deletions src/content/docs/en/reference/integrations-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ interface AstroIntegration {
addMiddleware: (middleware: AstroIntegrationMiddleware) => void;
addDevToolbarApp: (pluginEntrypoint: string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entrypoint: string }) => void;
injectRoute: ({ pattern: string, entrypoint: string, priority?: 'normal' | 'legacy' }) => void;
logger: AstroIntegrationLogger;
}) => void;
'astro:config:done'?: (options: { config: AstroConfig; setAdapter: (adapter: AstroAdapter) => void; logger: AstroIntegrationLogger; }) => void | Promise<void>;
Expand Down Expand Up @@ -80,7 +80,7 @@ interface AstroIntegration {
addDevToolbarApp: (pluginEntrypoint: string) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: ({ pattern: string, entrypoint: string }) => void;
injectRoute: ({ pattern: string, entrypoint: string, priority?: 'normal' | 'legacy' }) => void;
logger: AstroIntegrationLogger;
}) => void;
```
Expand Down Expand Up @@ -318,6 +318,8 @@ A callback function to inject routes into an Astro project. Injected routes can
- `pattern` - where the route should be output in the browser, for example `/foo/bar`. A `pattern` can use Astro's filepath syntax for denoting dynamic routes, for example `/foo/[bar]` or `/foo/[...bar]`. Note that a file extension is **not** needed in the `pattern`.
- `entrypoint` - a bare module specifier pointing towards the `.astro` page or `.js`/`.ts` route handler that handles the route denoted in the `pattern`.

Injected routes are prioritized following [the same rules](/en/core-concepts/routing/#route-priority-order) as project file-based routes. Previously, injected routes always had a higher priority than any project route. This legacy behavior can be enabled by passing `priority: 'legacy'` in the object:

##### Example usage

```js
Expand All @@ -339,6 +341,16 @@ injectRoute({
});
```

For an integration that relies on the legacy behavior:

```js
injectRoute({
pattern: '/fancy-dashboard',
entrypoint: '@fancy/dashboard/dashboard.astro'
priority: 'legacy',
});
```

#### `injectScript` option

**Type:** `(stage: InjectedScriptStage, content: string) => void;`
Expand Down
Loading