Skip to content

Commit

Permalink
Implement priority overrides for injected routes and redirects (#9439)
Browse files Browse the repository at this point in the history
* Implement priority overrides for injected routes and redirects

* Fix ordering for route specificity

* Don't mix rules on tests

* Detailed collision detection

* Add changeset

* Remove TODO

* Add comments to clarify default values

* Update terminology

* Revert unrelated changes

* WIP

* Refactor

* Fix typo and typing

* chore: default to legacy

* chore: use experimental flag instead of option

* fix: do not throw an error on collisions

* chore: fix regression

* chore: use `continue` instead of `return`

* chore: fix tests but one

* chore: Update test

* chore: Change remaining new error to warning

* chore: Test collision warnings

* docs: Update docs of new config

* docs: Improve changesets

* chore: rename experimental flag

* chore: update changeset and docs

* Sarah editing pass

* nit: Align Markdown table

* defined definitions!

Co-authored-by: Luiz Ferraz <luiz@lferraz.com>

* added logging info to docs for experimental flag

* Yan final boss review

Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com>

* chore: Update flag name in tests

* chore: Update flag name in tests

---------

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Co-authored-by: Yan Thomas <61414485+Yan-Thomas@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 17, 2024
1 parent efadef2 commit fd17f4a
Show file tree
Hide file tree
Showing 6 changed files with 755 additions and 193 deletions.
16 changes: 16 additions & 0 deletions .changeset/short-keys-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"astro": patch
---

Updates [Astro's routing priority rules](https://docs.astro.build/en/core-concepts/routing/#route-priority-order) to prioritize the most specifically-defined routes.

Now, routes with **more defined path segments** will take precedence over less specific routes.

For example, `/blog/posts/[pid].astro` (3 path segments) takes precedence over `/blog/[...slug].astro` (2 path segments). This means that:

- `/pages/blog/posts/[id].astro` will build routes of the form `/blog/posts/1` and `/blog/posts/a`
- `/pages/blog/[...slug].astro` will build routes of a variety of forms, including `blog/1` and `/blog/posts/1/a`, but will not build either of the previous routes.

For a complete list of Astro's routing priority rules, please see the [routing guide](https://docs.astro.build/en/core-concepts/routing/#route-priority-order). This should not be a breaking change, but you may wish to inspect your built routes to ensure that your project is unaffected.


34 changes: 34 additions & 0 deletions .changeset/smooth-cobras-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
'astro': minor
---

Adds an experimental flag `globalRoutePriority` to prioritize redirects and injected routes equally alongside file-based project routes, following the same [route priority order rules](https://docs.astro.build/en/core-concepts/routing/#route-priority-order) for all routes.

```js
// astro.config.mjs
export default defineConfig({
experimental: {
globalRoutePriority: true,
},
})
```

Enabling this feature ensures that all routes in your project follow the same, predictable route priority order rules. In particular, this avoids an issue where redirects or injected routes (e.g. from an integration) would always take precedence over local route definitions, making it impossible to override some routes locally.

The following table shows which route builds certain page URLs when file-based routes, injected routes, and redirects are combined as shown below:

- File-based route: `/blog/post/[pid]`
- File-based route: `/[page]`
- Injected route: `/blog/[...slug]`
- Redirect: `/blog/tags/[tag]` -> `/[tag]`
- Redirect: `/posts` -> `/blog`

URLs are handled by the following routes:

| Page | Current Behavior | Global Routing Priority Behavior |
|--------------------|----------------------------------|-------------------------------------|
| `/blog/tags/astro` | Injected route `/blog/[...slug]` | Redirect to `/tags/[tag]` |
| `/blog/post/0` | Injected route `/blog/[...slug]` | File-based route `/blog/post/[pid]` |
| `/posts` | File-based route `/[page]` | Redirect to `/blog` |

In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
40 changes: 40 additions & 0 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,36 @@ export interface AstroUserConfig {
* See the [Prefetch Guide](https://docs.astro.build/en/guides/prefetch/) for more `prefetch` options and usage.
*/
clientPrerender?: boolean;

/**
* @docs
* @name experimental.globalRoutePriority
* @type {boolean}
* @default `false`
* @version 4.2.0
* @description
*
* Prioritizes redirects and injected routes equally alongside file-based project routes, following the same [route priority order rules](https://docs.astro.build/en/core-concepts/routing/#route-priority-order) for all routes.
*
* The following table shows which route builds certain page URLs when file-based routes, injected routes, and redirects are combined as shown below:
* - File-based route: `/blog/post/[pid]`
* - File-based route: `/[page]`
* - Injected route: `/blog/[...slug]`
* - Redirect: `/blog/tags/[tag]` -> `/[tag]`
* - Redirect: `/posts` -> `/blog`
*
* URLs are handled by the following routes:
*
* | Page | Current Behavior | Global Routing Priority Behavior |
* | ------------------ | -------------------------------- | ----------------------------------- |
* | `/blog/tags/astro` | Injected route `/blog/[...slug]` | Redirect to `/tags/[tag]` |
* | `/blog/post/0` | Injected route `/blog/[...slug]` | File-based route `/blog/post/[pid]` |
* | `/posts` | File-based route `/[page]` | Redirect to `/blog` |
*
*
* In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
*/
globalRoutePriority?: boolean;
};
}

Expand All @@ -1652,6 +1682,15 @@ export interface AstroUserConfig {
*/
export type InjectedScriptStage = 'before-hydration' | 'head-inline' | 'page' | 'page-ssr';

/**
* IDs for different priorities of injected routes and redirects:
* - "normal": Merge with discovered file-based project routes, behaving the same as if the route
* was defined as a file in the project.
* - "legacy": Use the old ordering of routes. Inject routes will override any file-based project route,
* and redirects will be overridden by any project route on conflict.
*/
export type RoutePriorityOverride = 'normal' | 'legacy';

export interface InjectedRoute {
pattern: string;
entrypoint: string;
Expand Down Expand Up @@ -2496,6 +2535,7 @@ type RedirectConfig =
| {
status: ValidRedirectStatus;
destination: string;
priority?: RoutePriorityOverride;
};

export interface RouteData {
Expand Down
5 changes: 5 additions & 0 deletions packages/astro/src/core/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const ASTRO_CONFIG_DEFAULTS = {
optimizeHoistedScript: false,
contentCollectionCache: false,
clientPrerender: false,
globalRoutePriority: false,
},
} satisfies AstroUserConfig & { server: { open: boolean } };

Expand Down Expand Up @@ -421,6 +422,10 @@ export const AstroConfigSchema = z.object({
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
globalRoutePriority: z
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.globalRoutePriority),
})
.strict(
`Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for a list of all current experiments.`
Expand Down
Loading

0 comments on commit fd17f4a

Please sign in to comment.