Skip to content

Commit c6f8bce

Browse files
authored
Fix Netlify adapter and dynamic routes (#3011)
* Fix Netlify adapter and dynamic routes * Changeset
1 parent 8bd49c9 commit c6f8bce

File tree

10 files changed

+82
-18
lines changed

10 files changed

+82
-18
lines changed

.changeset/nervous-chairs-check.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'astro': patch
3+
'@astrojs/netlify': patch
4+
---
5+
6+
Fixes dynamic routes in the Netlify adapter

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build:ci": "turbo run build:ci --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
1313
"build:examples": "turbo run build --scope=\"@example/*\"",
1414
"dev": "turbo run dev --no-deps --no-cache --parallel --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
15-
"test": "pnpm run test --filter astro --filter @astrojs/webapi --filter @astrojs/deno",
15+
"test": "pnpm run test --filter astro --filter @astrojs/webapi --filter @astrojs/deno --filter @astrojs/netlify",
1616
"test:match": "cd packages/astro && pnpm run test:match",
1717
"test:templates": "pnpm run test --filter create-astro",
1818
"test:smoke": "node scripts/smoke/index.js",

packages/astro/src/@types/astro.ts

+7
Original file line numberDiff line numberDiff line change
@@ -798,12 +798,19 @@ export interface AstroIntegration {
798798

799799
export type RouteType = 'page' | 'endpoint';
800800

801+
export interface RoutePart {
802+
content: string;
803+
dynamic: boolean;
804+
spread: boolean;
805+
}
806+
801807
export interface RouteData {
802808
component: string;
803809
generate: (data?: any) => string;
804810
params: string[];
805811
pathname?: string;
806812
pattern: RegExp;
813+
segments: RoutePart[][];
807814
type: RouteType;
808815
}
809816

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

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AstroConfig, ManifestData, RouteData } from '../../../@types/astro';
1+
import type { AstroConfig, ManifestData, RouteData, RoutePart } from '../../../@types/astro';
22
import type { LogOptions } from '../../logger/core';
33

44
import fs from 'fs';
@@ -9,16 +9,10 @@ import { fileURLToPath } from 'url';
99
import { warn } from '../../logger/core.js';
1010
import { resolvePages } from '../../util.js';
1111

12-
interface Part {
13-
content: string;
14-
dynamic: boolean;
15-
spread: boolean;
16-
}
17-
1812
interface Item {
1913
basename: string;
2014
ext: string;
21-
parts: Part[];
15+
parts: RoutePart[];
2216
file: string;
2317
isDir: boolean;
2418
isIndex: boolean;
@@ -35,7 +29,7 @@ function countOccurrences(needle: string, haystack: string) {
3529
}
3630

3731
function getParts(part: string, file: string) {
38-
const result: Part[] = [];
32+
const result: RoutePart[] = [];
3933
part.split(/\[(.+?\(.+?\)|.+?)\]/).map((str, i) => {
4034
if (!str) return;
4135
const dynamic = i % 2 === 1;
@@ -56,7 +50,7 @@ function getParts(part: string, file: string) {
5650
return result;
5751
}
5852

59-
function getPattern(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) {
53+
function getPattern(segments: RoutePart[][], addTrailingSlash: AstroConfig['trailingSlash']) {
6054
const pathname = segments
6155
.map((segment) => {
6256
return segment[0].spread
@@ -94,7 +88,7 @@ function getTrailingSlashPattern(addTrailingSlash: AstroConfig['trailingSlash'])
9488
return '\\/?$';
9589
}
9690

97-
function getGenerator(segments: Part[][], addTrailingSlash: AstroConfig['trailingSlash']) {
91+
function getGenerator(segments: RoutePart[][], addTrailingSlash: AstroConfig['trailingSlash']) {
9892
const template = segments
9993
.map((segment) => {
10094
return segment[0].spread
@@ -181,7 +175,7 @@ export function createRouteManifest(
181175
const validPageExtensions: Set<string> = new Set(['.astro', '.md']);
182176
const validEndpointExtensions: Set<string> = new Set(['.js', '.ts']);
183177

184-
function walk(dir: string, parentSegments: Part[][], parentParams: string[]) {
178+
function walk(dir: string, parentSegments: RoutePart[][], parentParams: string[]) {
185179
let items: Item[] = [];
186180
fs.readdirSync(dir).forEach((basename) => {
187181
const resolved = path.join(dir, basename);
@@ -285,6 +279,7 @@ export function createRouteManifest(
285279
routes.push({
286280
type: item.isPage ? 'page' : 'endpoint',
287281
pattern,
282+
segments,
288283
params,
289284
component,
290285
generate,

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import type { RouteData, SerializedRouteData } from '../../../@types/astro';
1+
import type { RouteData, SerializedRouteData, RoutePart } from '../../../@types/astro';
22

33
function createRouteData(
44
pattern: RegExp,
55
params: string[],
66
component: string,
77
pathname: string | undefined,
8-
type: 'page' | 'endpoint'
8+
type: 'page' | 'endpoint',
9+
segments: RoutePart[][]
910
): RouteData {
1011
return {
1112
type,
@@ -15,6 +16,7 @@ function createRouteData(
1516
// TODO bring back
1617
generate: () => '',
1718
pathname: pathname || undefined,
19+
segments
1820
};
1921
}
2022

@@ -26,7 +28,7 @@ export function serializeRouteData(routeData: RouteData): SerializedRouteData {
2628
}
2729

2830
export function deserializeRouteData(rawRouteData: SerializedRouteData) {
29-
const { component, params, pathname, type } = rawRouteData;
31+
const { component, params, pathname, type, segments } = rawRouteData;
3032
const pattern = new RegExp(rawRouteData.pattern);
31-
return createRouteData(pattern, params, component, pathname, type);
33+
return createRouteData(pattern, params, component, pathname, type, segments);
3234
}

packages/integrations/netlify/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
},
2222
"scripts": {
2323
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
24-
"dev": "astro-scripts dev \"src/**/*.ts\""
24+
"dev": "astro-scripts dev \"src/**/*.ts\"",
25+
"test": "mocha --exit --timeout 20000"
2526
},
2627
"dependencies": {
2728
"@astrojs/webapi": "^0.11.0"

packages/integrations/netlify/src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegrat
5353
if (route.pathname) {
5454
_redirects += `
5555
${route.pathname} /.netlify/functions/${entryFile} 200`;
56+
} else {
57+
const pattern = '/' + route.segments.map(([part]) => part.dynamic ? '*' : part.content).join('/');
58+
_redirects += `
59+
${pattern} /.netlify/functions/${entryFile} 200`;
5660
}
5761
}
5862

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { expect } from 'chai';
2+
import { load as cheerioLoad } from 'cheerio';
3+
import { loadFixture } from '../../../astro/test/test-utils.js';
4+
import netlifyAdapter from '../dist/index.js';
5+
import { fileURLToPath } from 'url';
6+
7+
// Asset bundling
8+
describe('Dynamic pages', () => {
9+
/** @type {import('../../../astro/test/test-utils').Fixture} */
10+
let fixture;
11+
12+
before(async () => {
13+
fixture = await loadFixture({
14+
root: new URL('./fixtures/dynamic-route/', import.meta.url).toString(),
15+
experimental: {
16+
ssr: true,
17+
},
18+
adapter: netlifyAdapter({
19+
dist: new URL('./fixtures/dynamic-route/dist/', import.meta.url)
20+
}),
21+
site: `http://example.com`,
22+
vite: {
23+
resolve: {
24+
alias: {
25+
'@astrojs/netlify/netlify-functions.js': fileURLToPath(new URL('../dist/netlify-functions.js', import.meta.url))
26+
}
27+
}
28+
}
29+
});
30+
await fixture.build();
31+
});
32+
33+
it('Dynamic pages are included in the redirects file', async () => {
34+
const redir = await fixture.readFile('/_redirects');
35+
expect(redir).to.match(/\/products\/\*/);
36+
});
37+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/netlify
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
3+
---
4+
<html>
5+
<head>
6+
<title>Testing</title>
7+
</head>
8+
<body>
9+
<h1>Testing</h1>
10+
</body>
11+
</html>

0 commit comments

Comments
 (0)