-
Notifications
You must be signed in to change notification settings - Fork 960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle Next.js rewrites/redirects/headers #5212
Closed
leoortizz
wants to merge
59
commits into
firebase:master
from
monogramdesign:leoortizz_nextjs_rewrites
Closed
Changes from all commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
b089f20
add RE2
leoortizz c5bf204
filter out rewrites not supported by RE2
leoortizz c58f6c7
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 9998dd8
filter out rewrites to third parties
leoortizz 28495f1
check rewrites, redirects and headers w/ same fn
leoortizz 279012e
isThirdPartyUrl > isUrl, .includes > .startsWith
leoortizz 81e636f
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 0352221
remove RE2, detect regex as stated in Next.js docs
leoortizz 00f3fb1
add unit tests for Next.js utils
leoortizz 54611e9
add unit tests for frameworks/utils
leoortizz 0760593
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz cc1d080
`replaceAll` > `replace`
leoortizz 7f9a58e
header/redirects/rewrites checks as reusable utils
leoortizz f76c76a
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz dc5fdcc
replace for loop with regex
leoortizz 33b602e
`.exec` > `.test`
leoortizz 170d04d
`has` should also require backend
leoortizz 72771d0
reduce `pathHasRegex` verbosity
leoortizz cd62b47
fix `isUrl`, more test cases
leoortizz b1bc7da
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 6c079ab
require backend if rewrites afterFiles or fallback
leoortizz 750f2fa
filter prerendered routes that matches custom ...
leoortizz 9bbe63b
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 13462a5
remove TODO
leoortizz 7bc1339
`rewrite.has` > `"has" in rewrite`
leoortizz b07c6c3
move Next.js types to interfaces.ts
leoortizz d1abbbb
filter out redirects with `has`
leoortizz 9c6aac3
filter out headers with `has`
leoortizz 7437cb0
add paths for tests, adjust pathHasRegex tests
leoortizz e31f094
tests for supported rewrites
leoortizz d649f02
tests for supported redirects
leoortizz 2d9fee1
tests for supported headers
leoortizz 1ab51c0
tests for `getNextjsRewritesToUse`
leoortizz 71226bb
temporarily disable `cleanEscapedChars` tests
leoortizz c3915d9
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 7895769
comment out unused import
leoortizz 9923860
replace types with interfaces
leoortizz 9257980
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz f0533e6
changelog
leoortizz 75ba873
remove side effects from custom routes filters
leoortizz 9311974
refactor `getNextjsRewritesToUse`
leoortizz 6984b5f
`=== false` > `!`
leoortizz 49a958b
destructure with defaults, reduce ?, reduce ifs
leoortizz c2560bc
simplify isSupported... utils
leoortizz ba9fec9
simplify custom routes filters
leoortizz 3a91834
instantiate regexes before loop
leoortizz db8c398
replace some with every, check negation
leoortizz 8f482ca
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz 9a230e3
improve Next.js utils documentation
leoortizz a0f4c05
readJSON util with type
leoortizz 425fa5d
replace readFile/JSON.parse with typed readJSON
leoortizz 0369402
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz d49b302
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz f3b4a44
fix cleanEscapedChars, improve function doc
leoortizz c2a9c4a
fix `cleanEscapedChars` test
leoortizz fa809ef
replace as Manifest with typed readJSON
leoortizz 44e0148
typed readJSON defaulting to `any`
leoortizz 4b505c5
Merge branch 'master' into leoortizz_nextjs_rewrites
leoortizz ee7d975
Merge master
jamesdaniels File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately
Redirect
is not extendable because its members are not statically known, so this is not possible:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:(