summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/strange-forks-exist.md5
-rw-r--r--packages/astro/src/core/build/generate.ts2
-rw-r--r--packages/astro/src/core/routing/manifest/generator.ts10
-rw-r--r--packages/astro/test/dynamic-route-collision.test.js59
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/package.json8
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[...slug].astro35
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[aOrder].astro27
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[bOrder].astro27
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/[...page].astro28
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/index.astro27
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/[page].astro31
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/about.astro8
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/index.astro8
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/[...page].astro27
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/index.astro8
-rw-r--r--packages/astro/test/fixtures/dynamic-route-collision/src/pages/who.astro8
-rw-r--r--pnpm-lock.yaml6
17 files changed, 322 insertions, 2 deletions
diff --git a/.changeset/strange-forks-exist.md b/.changeset/strange-forks-exist.md
new file mode 100644
index 000000000..4fa5b0277
--- /dev/null
+++ b/.changeset/strange-forks-exist.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+Fix an incorrect conflict resolution between pages generated from static routes and rest parameters
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 6a9f0610c..3a1b2939a 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -326,7 +326,7 @@ async function getPathsForRoute(
let paths: Array<string> = [];
if (route.pathname) {
paths.push(route.pathname);
- builtPaths.add(route.pathname);
+ builtPaths.add(removeTrailingForwardSlash(route.pathname));
} else {
const staticPaths = await callGetStaticPaths({
mod,
diff --git a/packages/astro/src/core/routing/manifest/generator.ts b/packages/astro/src/core/routing/manifest/generator.ts
index 60614f2e5..2a3e18ade 100644
--- a/packages/astro/src/core/routing/manifest/generator.ts
+++ b/packages/astro/src/core/routing/manifest/generator.ts
@@ -37,5 +37,13 @@ export function getRouteGenerator(
trailing = '/';
}
const toPath = compile(template + trailing);
- return toPath;
+ return (params: object): string => {
+ const path = toPath(params);
+
+ // When generating an index from a rest parameter route, `path-to-regexp` will return an
+ // empty string instead "/". This causes an inconsistency with static indexes that may result
+ // in the incorrect routes being rendered.
+ // To fix this, we return "/" when the path is empty.
+ return path || '/';
+ };
}
diff --git a/packages/astro/test/dynamic-route-collision.test.js b/packages/astro/test/dynamic-route-collision.test.js
new file mode 100644
index 000000000..ca78af9b5
--- /dev/null
+++ b/packages/astro/test/dynamic-route-collision.test.js
@@ -0,0 +1,59 @@
+import assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
+import * as cheerio from 'cheerio';
+import { loadFixture } from './test-utils.js';
+
+describe('Dynamic route collision', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/dynamic-route-collision',
+ });
+
+ await fixture.build().catch(console.log);
+ });
+
+ it('Builds a static route when in conflict with a dynamic route', async () => {
+ const html = await fixture.readFile('/about/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Static About');
+ });
+
+ it('Builds a static route when in conflict with a spread route', async () => {
+ const html = await fixture.readFile('/who/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Static Who We Are');
+ });
+
+ it('Builds a static nested index when in conflict with a spread route', async () => {
+ const html = await fixture.readFile('/tags/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Static Tags Index');
+ });
+
+ it('Builds a static root index when in conflict with a spread route', async () => {
+ const html = await fixture.readFile('/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Static Index');
+ });
+
+ it('Builds a static index a nested when in conflict with a dynamic+spread route', async () => {
+ const html = await fixture.readFile('/en/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Dynamic-only Localized Index');
+ });
+
+ it('Builds a dynamic route when in conflict with a spread route', async () => {
+ const html = await fixture.readFile('/blog/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Dynamic Blog');
+ });
+
+ it('Builds the highest priority route out of two conflicting dynamic routes', async () => {
+ const html = await fixture.readFile('/order/index.html');
+ const $ = cheerio.load(html);
+ assert.equal($('h1').text(), 'Order from A');
+ });
+});
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/package.json b/packages/astro/test/fixtures/dynamic-route-collision/package.json
new file mode 100644
index 000000000..35848efb7
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@test/dynamic-route-collision",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[...slug].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[...slug].astro
new file mode 100644
index 000000000..89498c2d9
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[...slug].astro
@@ -0,0 +1,35 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ slug: undefined,
+ title: 'Rest Index',
+ },
+ {
+ slug: 'blog',
+ title: 'Rest Blog',
+ },
+ {
+ slug: 'who',
+ title: 'Rest Who We Are',
+ },
+ ];
+ return pages.map(({ slug, title }) => {
+ return {
+ params: { slug },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+ <head>
+ <title>{title}</title>
+ </head>
+ <body>
+ <h1>{title}</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[aOrder].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[aOrder].astro
new file mode 100644
index 000000000..8957a3dc8
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[aOrder].astro
@@ -0,0 +1,27 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ page: 'order',
+ title: 'Order from A',
+ },
+ ];
+ return pages.map(({ page, title }) => {
+ return {
+ params: { 'aOrder': page },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+<head>
+ <title>{title}</title>
+</head>
+<body>
+<h1>{title}</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[bOrder].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[bOrder].astro
new file mode 100644
index 000000000..1b0eb30d8
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[bOrder].astro
@@ -0,0 +1,27 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ page: 'order',
+ title: 'Order from B',
+ },
+ ];
+ return pages.map(({ page, title }) => {
+ return {
+ params: { 'bOrder': page },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+<head>
+ <title>{title}</title>
+</head>
+<body>
+<h1>{title}</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/[...page].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/[...page].astro
new file mode 100644
index 000000000..1cdd7f766
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/[...page].astro
@@ -0,0 +1,28 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ locale: 'en',
+ page: undefined,
+ title: 'Dynamic+Rest Localized Index',
+ },
+ ];
+ return pages.map(({ page, locale, title }) => {
+ return {
+ params: { page, locale },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+ <head>
+ <title>{title}</title>
+ </head>
+ <body>
+ <h1>{title}</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/index.astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/index.astro
new file mode 100644
index 000000000..425c55f74
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[locale]/index.astro
@@ -0,0 +1,27 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ locale: 'en',
+ title: 'Dynamic-only Localized Index',
+ },
+ ];
+ return pages.map(({ page, locale, title }) => {
+ return {
+ params: { page, locale },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+<head>
+ <title>{title}</title>
+</head>
+<body>
+<h1>{title}</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[page].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[page].astro
new file mode 100644
index 000000000..433198cd7
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/[page].astro
@@ -0,0 +1,31 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ page: 'about',
+ title: 'Dynamic About',
+ },
+ {
+ page: 'blog',
+ title: 'Dynamic Blog',
+ },
+ ];
+ return pages.map(({ page, title }) => {
+ return {
+ params: { page },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+<head>
+ <title>{title}</title>
+</head>
+<body>
+<h1>{title}</h1>
+</body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/about.astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/about.astro
new file mode 100644
index 000000000..16698abc1
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/about.astro
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Static About Page</title>
+ </head>
+ <body>
+ <h1>Static About</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/index.astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/index.astro
new file mode 100644
index 000000000..043c4a5c9
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/index.astro
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Static Index Page</title>
+ </head>
+ <body>
+ <h1>Static Index</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/[...page].astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/[...page].astro
new file mode 100644
index 000000000..fa7f87d3a
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/[...page].astro
@@ -0,0 +1,27 @@
+---
+export async function getStaticPaths() {
+ const pages = [
+ {
+ page: undefined,
+ title: 'Rest Tag Index',
+ },
+ ];
+ return pages.map(({ page, title }) => {
+ return {
+ params: { tag: page },
+ props: { title },
+ };
+ });
+}
+
+const { title } = Astro.props;
+---
+
+<html>
+ <head>
+ <title>{title}</title>
+ </head>
+ <body>
+ <h1>{title}</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/index.astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/index.astro
new file mode 100644
index 000000000..0f86c5313
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/tags/index.astro
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Static Tags Index</title>
+ </head>
+ <body>
+ <h1>Static Tags Index</h1>
+ </body>
+</html>
diff --git a/packages/astro/test/fixtures/dynamic-route-collision/src/pages/who.astro b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/who.astro
new file mode 100644
index 000000000..00d12c59d
--- /dev/null
+++ b/packages/astro/test/fixtures/dynamic-route-collision/src/pages/who.astro
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Static Who We Are</title>
+ </head>
+ <body>
+ <h1>Static Who We Are</h1>
+ </body>
+</html>
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index edc246409..c3b33f704 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2732,6 +2732,12 @@ importers:
specifier: workspace:*
version: link:../../..
+ packages/astro/test/fixtures/dynamic-route-collision:
+ dependencies:
+ astro:
+ specifier: workspace:*
+ version: link:../../..
+
packages/astro/test/fixtures/entry-file-names:
dependencies:
'@astrojs/preact':