-
Notifications
You must be signed in to change notification settings - Fork 958
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle Next.js rewrites/redirects/headers (#5212)
* Handle Next.js rewrites/redirects/headers incompatible with `firebase.json` in Cloud Functions * Filter out Next.js prerendered routes that matches rewrites/redirects/headers rules from SSG content directory
- Loading branch information
1 parent
d7f0186
commit cbe5790
Showing
12 changed files
with
1,020 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
- Add support for Firestore TTL (#5267) | ||
- Fix bug where secrets were not loaded when emulating functions with `--inpsect-functions`. (#4605) | ||
- Handle Next.js rewrites/redirects/headers incompatible with `firebase.json` in Cloud Functions (#5212) | ||
- Filter out Next.js prerendered routes that matches rewrites/redirects/headers rules from SSG content directory (#5212) | ||
- Warn if a web framework's package.json contains anything other than the framework default build command. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import type { Header, Rewrite, Redirect } from "next/dist/lib/load-custom-routes"; | ||
|
||
export interface RoutesManifestRewrite extends Rewrite { | ||
regex: string; | ||
} | ||
|
||
export interface RoutesManifestRewriteObject { | ||
beforeFiles?: RoutesManifestRewrite[]; | ||
afterFiles?: RoutesManifestRewrite[]; | ||
fallback?: RoutesManifestRewrite[]; | ||
} | ||
|
||
export interface RoutesManifestHeader extends Header { | ||
regex: string; | ||
} | ||
|
||
// Next.js's exposed interface is incomplete here | ||
// TODO see if there's a better way to grab this | ||
// TODO: rename to RoutesManifest as Next.js has other types of manifests | ||
export interface Manifest { | ||
distDir?: string; | ||
basePath?: string; | ||
headers?: RoutesManifestHeader[]; | ||
redirects?: Array< | ||
Redirect & { | ||
regex: string; | ||
internal?: boolean; | ||
} | ||
>; | ||
rewrites?: RoutesManifestRewrite[] | RoutesManifestRewriteObject; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import type { Header, Redirect, Rewrite } from "next/dist/lib/load-custom-routes"; | ||
import type { Manifest, RoutesManifestRewrite } from "./interfaces"; | ||
import { isUrl } from "../utils"; | ||
|
||
/** | ||
* Whether the given path has a regex or not. | ||
* According to the Next.js documentation: | ||
* ```md | ||
* To match a regex path you can wrap the regex in parentheses | ||
* after a parameter, for example /post/:slug(\\d{1,}) will match /post/123 | ||
* but not /post/abc. | ||
* ``` | ||
* See: https://nextjs.org/docs/api-reference/next.config.js/redirects#regex-path-matching | ||
*/ | ||
export function pathHasRegex(path: string): boolean { | ||
// finds parentheses that are not preceded by double backslashes | ||
return /(?<!\\)\(/.test(path); | ||
} | ||
|
||
/** | ||
* Remove escaping from characters used for Regex patch matching that Next.js | ||
* requires. As Firebase Hosting does not require escaping for those charachters, | ||
* we remove them. | ||
* | ||
* According to the Next.js documentation: | ||
* ```md | ||
* The following characters (, ), {, }, :, *, +, ? are used for regex path | ||
* matching, so when used in the source as non-special values they must be | ||
* escaped by adding \\ before them. | ||
* ``` | ||
* | ||
* See: https://nextjs.org/docs/api-reference/next.config.js/rewrites#regex-path-matching | ||
*/ | ||
export function cleanEscapedChars(path: string): string { | ||
return path.replace(/\\([(){}:+?*])/g, (a, b: string) => b); | ||
} | ||
|
||
/** | ||
* Whether a Next.js rewrite is supported by `firebase.json`. | ||
* | ||
* See: https://firebase.google.com/docs/hosting/full-config#rewrites | ||
* | ||
* Next.js unsupported rewrites includes: | ||
* - Rewrites with the `has` property that is used by Next.js for Header, | ||
* Cookie, and Query Matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/rewrites#header-cookie-and-query-matching | ||
* | ||
* - Rewrites using regex for path matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/rewrites#regex-path-matching | ||
* | ||
* - Rewrites to external URLs | ||
*/ | ||
export function isRewriteSupportedByFirebase(rewrite: Rewrite): boolean { | ||
return !("has" in rewrite || pathHasRegex(rewrite.source) || isUrl(rewrite.destination)); | ||
} | ||
|
||
/** | ||
* Whether a Next.js redirect is supported by `firebase.json`. | ||
* | ||
* See: https://firebase.google.com/docs/hosting/full-config#redirects | ||
* | ||
* Next.js unsupported redirects includes: | ||
* - Redirects with the `has` property that is used by Next.js for Header, | ||
* Cookie, and Query Matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/redirects#header-cookie-and-query-matching | ||
* | ||
* - Redirects using regex for path matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/redirects#regex-path-matching | ||
* | ||
* - Next.js internal redirects | ||
*/ | ||
export function isRedirectSupportedByFirebase(redirect: Redirect): boolean { | ||
return !("has" in redirect || pathHasRegex(redirect.source) || "internal" in redirect); | ||
} | ||
|
||
/** | ||
* Whether a Next.js custom header is supported by `firebase.json`. | ||
* | ||
* See: https://firebase.google.com/docs/hosting/full-config#headers | ||
* | ||
* Next.js unsupported headers includes: | ||
* - Custom header with the `has` property that is used by Next.js for Header, | ||
* Cookie, and Query Matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/headers#header-cookie-and-query-matching | ||
* | ||
* - Custom header using regex for path matching. | ||
* - https://nextjs.org/docs/api-reference/next.config.js/headers#regex-path-matching | ||
*/ | ||
export function isHeaderSupportedByFirebase(header: Header): boolean { | ||
return !("has" in header || pathHasRegex(header.source)); | ||
} | ||
|
||
/** | ||
* Get which Next.js rewrites will be used before checking supported items individually. | ||
* | ||
* Next.js rewrites can be arrays or objects: | ||
* - For arrays, all supported items can be used. | ||
* - For objects only `beforeFiles` can be used. | ||
* | ||
* See: https://nextjs.org/docs/api-reference/next.config.js/rewrites | ||
*/ | ||
export function getNextjsRewritesToUse( | ||
nextJsRewrites: Manifest["rewrites"] | ||
): RoutesManifestRewrite[] { | ||
if (Array.isArray(nextJsRewrites)) { | ||
return nextJsRewrites; | ||
} | ||
|
||
if (nextJsRewrites?.beforeFiles) { | ||
return nextJsRewrites.beforeFiles; | ||
} | ||
|
||
return []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.