Skip to content

Commit

Permalink
feat: wildcard option support in the build output config (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
james-elicx authored Jun 14, 2023
1 parent d835933 commit 1be5e72
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/itchy-rings-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cloudflare/next-on-pages': minor
---

Support for the `wildcard` option in the Vercel build output config.
2 changes: 1 addition & 1 deletion docs/supported.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ If you're application is using a package which relies on unsupported Node.js API
| routes `locale` ||
| routes `middlewarePath` ||
| images<sup>1</sup> | 🔄 |
| wildcard | 🔄 |
| wildcard | |
| overrides ||
| cache ||
| crons ||
Expand Down
7 changes: 6 additions & 1 deletion templates/_worker.js/handleRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export async function handleRequest(
config: ProcessedVercelConfig,
output: VercelBuildOutput
): Promise<Response> {
const matcher = new RoutesMatcher(config.routes, output, reqCtx);
const matcher = new RoutesMatcher(
config.routes,
output,
reqCtx,
config.wildcard
);
const match = await findMatch(matcher);

return generateResponse(reqCtx, match, output);
Expand Down
35 changes: 24 additions & 11 deletions templates/_worker.js/routes-matcher.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse } from 'cookie';
import type { MatchPCREResult, MatchedSet } from './utils';
import type { MatchPCREResult } from './utils';
import { parseAcceptLanguage } from './utils';
import {
applyHeaders,
Expand All @@ -24,6 +24,8 @@ export class RoutesMatcher {
private url: URL;
/** Cookies from the request to match */
private cookies: Record<string, string>;
/** Wildcard match from the Vercel build output config */
private wildcardMatch: VercelWildCard | undefined;

/** Path for the matched route */
public path: string;
Expand All @@ -49,7 +51,7 @@ export class RoutesMatcher {
* @param routes The processed Vercel build output config routes.
* @param output Vercel build output.
* @param reqCtx Request context object; request object, assets fetcher, and execution context.
* @param prevMatch The previous match from a routing phase to initialize the matcher with.
* @param wildcardConfig Wildcard options from the Vercel build output config.
* @returns The matched set of path, status, headers, and search params.
*/
constructor(
Expand All @@ -59,21 +61,21 @@ export class RoutesMatcher {
private output: VercelBuildOutput,
/** Request Context object for the request to match */
private reqCtx: RequestContext,
prevMatch?: MatchedSet
wildcardConfig?: VercelWildcardConfig
) {
this.url = new URL(reqCtx.request.url);
this.cookies = parse(reqCtx.request.headers.get('cookie') || '');

this.path = prevMatch?.path || this.url.pathname || '/';
this.status = prevMatch?.status;
this.headers = prevMatch?.headers || {
normal: new Headers(),
important: new Headers(),
};
this.searchParams = prevMatch?.searchParams || new URLSearchParams();
this.path = this.url.pathname || '/';
this.headers = { normal: new Headers(), important: new Headers() };
this.searchParams = new URLSearchParams();
applySearchParams(this.searchParams, this.url.searchParams);

this.checkPhaseCounter = 0;

this.wildcardMatch = wildcardConfig?.find(
w => w.domain === this.url.hostname
);
}

/**
Expand Down Expand Up @@ -269,6 +271,8 @@ export class RoutesMatcher {
/**
* Applies the route's destination for the matching the path to the Vercel build output.
*
* Applies any wildcard matches to the destination.
*
* @param route Build output config source route.
* @param srcMatch Matches from the PCRE matcher.
* @param captureGroupKeys Named capture group keys from the PCRE matcher.
Expand All @@ -282,8 +286,17 @@ export class RoutesMatcher {
if (!route.dest) return this.path;

const prevPath = this.path;
let processedDest = route.dest;

// Apply wildcard matches before PCRE matches
if (this.wildcardMatch && /\$wildcard/.test(processedDest)) {
processedDest = processedDest.replace(
/\$wildcard/g,
this.wildcardMatch.value
);
}

this.path = applyPCREMatches(route.dest, srcMatch, captureGroupKeys);
this.path = applyPCREMatches(processedDest, srcMatch, captureGroupKeys);

// NOTE: Special handling for `/index` RSC routes. Sometimes the Vercel build output config
// has a record to rewrite `^/` to `/index.rsc`, however, this will hit requests to pages
Expand Down
14 changes: 14 additions & 0 deletions tests/templates/requestTestData/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const rawVercelConfig: VercelConfig = {
},
{ src: '/.*', dest: '/en/500', status: 500 },
],
wildcard: [{ domain: 'example.es', value: '/es' }],
overrides: {
'en/gsp.html': { path: 'en/gsp', contentType: 'text/html; charset=utf-8' },
'fr/gsp.html': { path: 'fr/gsp', contentType: 'text/html; charset=utf-8' },
Expand Down Expand Up @@ -348,5 +349,18 @@ export const testSet: TestSet = {
},
},
},
{
name: 'Vercel wildcard rewrites work: example.es -> /es',
paths: ['/'],
host: 'example.es',
expected: {
status: 200,
data: '<html>es</html>',
headers: {
'content-type': 'text/html; charset=utf-8',
'x-matched-path': '/es',
},
},
},
],
};

0 comments on commit 1be5e72

Please sign in to comment.