Skip to content

Commit 91b9d66

Browse files
sidharthachatterjeepiehwardpeet
authored
feat(gatsby): ignore case option in create redirect (#29742)
* Add ignoreCase option for createRedirect and support it in client side navigation * Add typings for ignoreCase * Update packages/gatsby/src/redux/actions/public.js Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> * Prepare lowercased redirects at build time * Add tests * Remove only * Switch to O(1) Maps * Update navigate as well * Update packages/gatsby/index.d.ts Co-authored-by: Ward Peeters <ward@coding-tech.com> * Update packages/gatsby/cache-dir/navigation.js Co-authored-by: Ward Peeters <ward@coding-tech.com> * Set ignoreCase to false by default * Update snapshot * toLowerCase not toLowercase fml Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> Co-authored-by: Ward Peeters <ward@coding-tech.com>
1 parent 662fe41 commit 91b9d66

9 files changed

Lines changed: 88 additions & 60 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
describe(`Redirects`, () => {
2+
it(`are case insensitive when ignoreCase is set to true`, () => {
3+
cy.visit(`/Longue-PAGE`, { failOnStatusCode: false }).waitForRouteChange()
4+
5+
cy.get(`h1`).invoke(`text`).should(`contain`, `Hi from the long page`)
6+
})
7+
it(`are case sensitive when ignoreCase is set to false`, () => {
8+
cy.visit(`/PAGINA-larga`, { failOnStatusCode: false }).waitForRouteChange()
9+
10+
cy.get(`h1`).invoke(`text`).should(`contain`, `NOT FOUND`)
11+
})
12+
})

e2e-tests/production-runtime/gatsby-node.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ exports.sourceNodes = ({ actions, createNodeId }) => {
3636
})
3737
}
3838

39-
exports.createPages = ({ actions: { createPage } }) => {
39+
exports.createPages = ({ actions: { createPage, createRedirect } }) => {
4040
createPage({
4141
path: `/안녕`,
4242
component: path.resolve(`src/pages/page-2.js`),
@@ -124,6 +124,22 @@ exports.createPages = ({ actions: { createPage } }) => {
124124
path: `/page-from-cache/`,
125125
component: path.resolve(`./.cache/static-page-from-cache.js`),
126126
})
127+
128+
createRedirect({
129+
fromPath: "/pagina-larga",
130+
toPath: "/long-page",
131+
isPermanent: true,
132+
redirectInBrowser: true,
133+
ignoreCase: false,
134+
})
135+
136+
createRedirect({
137+
fromPath: "/Longue-Page",
138+
toPath: "/long-page",
139+
isPermanent: true,
140+
redirectInBrowser: true,
141+
ignoreCase: true,
142+
})
127143
}
128144

129145
exports.onCreatePage = ({ page, actions }) => {

packages/gatsby/cache-dir/navigation.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,23 @@ import { globalHistory } from "@reach/router/lib/history"
1010
import { parsePath } from "gatsby-link"
1111

1212
// Convert to a map for faster lookup in maybeRedirect()
13-
const redirectMap = redirects.reduce((map, redirect) => {
14-
map[redirect.fromPath] = redirect
15-
return map
16-
}, {})
13+
14+
const redirectMap = new Map()
15+
const redirectIgnoreCaseMap = new Map()
16+
17+
redirects.forEach(redirect => {
18+
if (redirect.ignoreCase) {
19+
redirectIgnoreCaseMap.set(redirect.fromPath, redirect)
20+
} else {
21+
redirectMap.set(redirect.fromPath, redirect)
22+
}
23+
})
1724

1825
function maybeRedirect(pathname) {
19-
const redirect = redirectMap[pathname]
26+
let redirect = redirectMap.get(pathname)
27+
if (!redirect) {
28+
redirect = redirectIgnoreCaseMap.get(pathname.toLowerCase())
29+
}
2030

2131
if (redirect != null) {
2232
if (process.env.NODE_ENV !== `production`) {
@@ -62,7 +72,10 @@ const navigate = (to, options = {}) => {
6272
}
6373

6474
let { pathname } = parsePath(to)
65-
const redirect = redirectMap[pathname]
75+
let redirect = redirectMap.get(pathname)
76+
if (!redirect) {
77+
redirect = redirectIgnoreCaseMap.get(pathname.toLowerCase())
78+
}
6679

6780
// If we're redirecting, just replace the passed in pathname
6881
// to the one we want to redirect to.

packages/gatsby/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,7 @@ export interface Actions {
12561256
redirectInBrowser?: boolean
12571257
force?: boolean
12581258
statusCode?: number
1259+
ignoreCase?: boolean
12591260
[key: string]: unknown
12601261
},
12611262
plugin?: ActionPlugin

packages/gatsby/src/bootstrap/redirects-writer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ export const writeRedirects = async (): Promise<void> => {
1616
const browserRedirects = redirects
1717
.filter(r => r.redirectInBrowser)
1818
// eslint-disable-next-line @typescript-eslint/no-unused-vars
19-
.map(({ redirectInBrowser, isPermanent, ...rest }) => rest)
19+
.map(
20+
({ redirectInBrowser, isPermanent, ignoreCase, fromPath, ...rest }) => {
21+
return {
22+
fromPath: ignoreCase ? fromPath.toLowerCase() : fromPath,
23+
ignoreCase,
24+
...rest,
25+
}
26+
}
27+
)
2028

2129
const newHash = crypto
2230
.createHash(`md5`)

packages/gatsby/src/query/redirects-writer.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

packages/gatsby/src/redux/__tests__/__snapshots__/redirects.ts.snap

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ exports[`Add redirects allows you to add redirects 1`] = `
44
Object {
55
"payload": Object {
66
"fromPath": "/old/hello-world",
7+
"ignoreCase": false,
78
"isPermanent": false,
89
"redirectInBrowser": false,
910
"toPath": "/new/hello-world",
@@ -16,6 +17,7 @@ exports[`Add redirects create redirects as permanent 1`] = `
1617
Object {
1718
"payload": Object {
1819
"fromPath": "/old/hello-world",
20+
"ignoreCase": false,
1921
"isPermanent": true,
2022
"redirectInBrowser": false,
2123
"toPath": "/new/hello-world",
@@ -28,6 +30,7 @@ exports[`Add redirects creates redirects from the URL starts with // 1`] = `
2830
Object {
2931
"payload": Object {
3032
"fromPath": "//example.com",
33+
"ignoreCase": false,
3134
"isPermanent": false,
3235
"redirectInBrowser": false,
3336
"toPath": "/new/hello-world-2",
@@ -40,6 +43,7 @@ exports[`Add redirects creates redirects from the URL starts with ftp 1`] = `
4043
Object {
4144
"payload": Object {
4245
"fromPath": "ftp://example.com",
46+
"ignoreCase": false,
4347
"isPermanent": false,
4448
"redirectInBrowser": false,
4549
"toPath": "/new/hello-world-3",
@@ -52,6 +56,7 @@ exports[`Add redirects creates redirects from the URL starts with http 1`] = `
5256
Object {
5357
"payload": Object {
5458
"fromPath": "http://example.com",
59+
"ignoreCase": false,
5560
"isPermanent": false,
5661
"redirectInBrowser": false,
5762
"toPath": "/new/hello-world-1",
@@ -64,6 +69,7 @@ exports[`Add redirects creates redirects from the URL starts with https 1`] = `
6469
Object {
6570
"payload": Object {
6671
"fromPath": "https://example.com",
72+
"ignoreCase": false,
6773
"isPermanent": false,
6874
"redirectInBrowser": false,
6975
"toPath": "/new/hello-world-0",
@@ -76,6 +82,7 @@ exports[`Add redirects creates redirects from the URL starts with mailto 1`] = `
7682
Object {
7783
"payload": Object {
7884
"fromPath": "mailto:example@email.com",
85+
"ignoreCase": false,
7986
"isPermanent": false,
8087
"redirectInBrowser": false,
8188
"toPath": "/new/hello-world-4",
@@ -88,6 +95,7 @@ exports[`Add redirects creates redirects to the URL starts with // 1`] = `
8895
Object {
8996
"payload": Object {
9097
"fromPath": "/old/hello-world-2",
98+
"ignoreCase": false,
9199
"isPermanent": false,
92100
"redirectInBrowser": false,
93101
"toPath": "//example.com",
@@ -100,6 +108,7 @@ exports[`Add redirects creates redirects to the URL starts with ftp 1`] = `
100108
Object {
101109
"payload": Object {
102110
"fromPath": "/old/hello-world-3",
111+
"ignoreCase": false,
103112
"isPermanent": false,
104113
"redirectInBrowser": false,
105114
"toPath": "ftp://example.com",
@@ -112,6 +121,7 @@ exports[`Add redirects creates redirects to the URL starts with http 1`] = `
112121
Object {
113122
"payload": Object {
114123
"fromPath": "/old/hello-world-1",
124+
"ignoreCase": false,
115125
"isPermanent": false,
116126
"redirectInBrowser": false,
117127
"toPath": "http://example.com",
@@ -124,6 +134,7 @@ exports[`Add redirects creates redirects to the URL starts with https 1`] = `
124134
Object {
125135
"payload": Object {
126136
"fromPath": "/old/hello-world-0",
137+
"ignoreCase": false,
127138
"isPermanent": false,
128139
"redirectInBrowser": false,
129140
"toPath": "https://example.com",
@@ -136,6 +147,7 @@ exports[`Add redirects creates redirects to the URL starts with mailto 1`] = `
136147
Object {
137148
"payload": Object {
138149
"fromPath": "/old/hello-world-4",
150+
"ignoreCase": false,
139151
"isPermanent": false,
140152
"redirectInBrowser": false,
141153
"toPath": "mailto:example@email.com",
@@ -148,6 +160,7 @@ exports[`Add redirects creates redirects with in-browser redirect option 1`] = `
148160
Object {
149161
"payload": Object {
150162
"fromPath": "/old/hello-world",
163+
"ignoreCase": false,
151164
"isPermanent": false,
152165
"redirectInBrowser": true,
153166
"toPath": "/new/hello-world",
@@ -160,6 +173,7 @@ exports[`Add redirects with path prefixs allows you to add redirects 1`] = `
160173
Object {
161174
"payload": Object {
162175
"fromPath": "/blog/old/hello-world",
176+
"ignoreCase": false,
163177
"isPermanent": false,
164178
"redirectInBrowser": false,
165179
"toPath": "/blog/new/hello-world",
@@ -172,6 +186,7 @@ exports[`Add redirects with path prefixs create redirects as permanent 1`] = `
172186
Object {
173187
"payload": Object {
174188
"fromPath": "/blog/old/hello-world",
189+
"ignoreCase": false,
175190
"isPermanent": true,
176191
"redirectInBrowser": false,
177192
"toPath": "/blog/new/hello-world",
@@ -184,6 +199,7 @@ exports[`Add redirects with path prefixs creates redirects from the URL starts w
184199
Object {
185200
"payload": Object {
186201
"fromPath": "//example.com",
202+
"ignoreCase": false,
187203
"isPermanent": false,
188204
"redirectInBrowser": false,
189205
"toPath": "/blog/new/hello-world-2",
@@ -196,6 +212,7 @@ exports[`Add redirects with path prefixs creates redirects from the URL starts w
196212
Object {
197213
"payload": Object {
198214
"fromPath": "ftp://example.com",
215+
"ignoreCase": false,
199216
"isPermanent": false,
200217
"redirectInBrowser": false,
201218
"toPath": "/blog/new/hello-world-3",
@@ -208,6 +225,7 @@ exports[`Add redirects with path prefixs creates redirects from the URL starts w
208225
Object {
209226
"payload": Object {
210227
"fromPath": "http://example.com",
228+
"ignoreCase": false,
211229
"isPermanent": false,
212230
"redirectInBrowser": false,
213231
"toPath": "/blog/new/hello-world-1",
@@ -220,6 +238,7 @@ exports[`Add redirects with path prefixs creates redirects from the URL starts w
220238
Object {
221239
"payload": Object {
222240
"fromPath": "https://example.com",
241+
"ignoreCase": false,
223242
"isPermanent": false,
224243
"redirectInBrowser": false,
225244
"toPath": "/blog/new/hello-world-0",
@@ -232,6 +251,7 @@ exports[`Add redirects with path prefixs creates redirects from the URL starts w
232251
Object {
233252
"payload": Object {
234253
"fromPath": "mailto:example@email.com",
254+
"ignoreCase": false,
235255
"isPermanent": false,
236256
"redirectInBrowser": false,
237257
"toPath": "/blog/new/hello-world-4",
@@ -244,6 +264,7 @@ exports[`Add redirects with path prefixs creates redirects to the URL starts wit
244264
Object {
245265
"payload": Object {
246266
"fromPath": "/blog/old/hello-world-2",
267+
"ignoreCase": false,
247268
"isPermanent": false,
248269
"redirectInBrowser": false,
249270
"toPath": "//example.com",
@@ -256,6 +277,7 @@ exports[`Add redirects with path prefixs creates redirects to the URL starts wit
256277
Object {
257278
"payload": Object {
258279
"fromPath": "/blog/old/hello-world-3",
280+
"ignoreCase": false,
259281
"isPermanent": false,
260282
"redirectInBrowser": false,
261283
"toPath": "ftp://example.com",
@@ -268,6 +290,7 @@ exports[`Add redirects with path prefixs creates redirects to the URL starts wit
268290
Object {
269291
"payload": Object {
270292
"fromPath": "/blog/old/hello-world-1",
293+
"ignoreCase": false,
271294
"isPermanent": false,
272295
"redirectInBrowser": false,
273296
"toPath": "http://example.com",
@@ -280,6 +303,7 @@ exports[`Add redirects with path prefixs creates redirects to the URL starts wit
280303
Object {
281304
"payload": Object {
282305
"fromPath": "/blog/old/hello-world-0",
306+
"ignoreCase": false,
283307
"isPermanent": false,
284308
"redirectInBrowser": false,
285309
"toPath": "https://example.com",
@@ -292,6 +316,7 @@ exports[`Add redirects with path prefixs creates redirects to the URL starts wit
292316
Object {
293317
"payload": Object {
294318
"fromPath": "/blog/old/hello-world-4",
319+
"ignoreCase": false,
295320
"isPermanent": false,
296321
"redirectInBrowser": false,
297322
"toPath": "mailto:example@email.com",
@@ -304,6 +329,7 @@ exports[`Add redirects with path prefixs creates redirects with in-browser redir
304329
Object {
305330
"payload": Object {
306331
"fromPath": "/blog/old/hello-world",
332+
"ignoreCase": false,
307333
"isPermanent": false,
308334
"redirectInBrowser": true,
309335
"toPath": "/blog/new/hello-world",

packages/gatsby/src/redux/actions/public.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,7 @@ const maybeAddPathPrefix = (path, pathPrefix) => {
12991299
* @param {boolean} redirect.redirectInBrowser Redirects are generally for redirecting legacy URLs to their new configuration. If you can't update your UI for some reason, set `redirectInBrowser` to true and Gatsby will handle redirecting in the client as well.
13001300
* @param {boolean} redirect.force (Plugin-specific) Will trigger the redirect even if the `fromPath` matches a piece of content. This is not part of the Gatsby API, but implemented by (some) plugins that configure hosting provider redirects
13011301
* @param {number} redirect.statusCode (Plugin-specific) Manually set the HTTP status code. This allows you to create a rewrite (status code 200) or custom error page (status code 404). Note that this will override the `isPermanent` option which also sets the status code. This is not part of the Gatsby API, but implemented by (some) plugins that configure hosting provider redirects
1302+
* @param {boolean} redirect.ignoreCase (Plugin-specific) Ignore case when looking for redirects
13021303
* @example
13031304
* // Generally you create redirects while creating pages.
13041305
* exports.createPages = ({ graphql, actions }) => {
@@ -1314,6 +1315,7 @@ actions.createRedirect = ({
13141315
isPermanent = false,
13151316
redirectInBrowser = false,
13161317
toPath,
1318+
ignoreCase = false,
13171319
...rest
13181320
}) => {
13191321
let pathPrefix = ``
@@ -1326,6 +1328,7 @@ actions.createRedirect = ({
13261328
payload: {
13271329
fromPath: maybeAddPathPrefix(fromPath, pathPrefix),
13281330
isPermanent,
1331+
ignoreCase,
13291332
redirectInBrowser,
13301333
toPath: maybeAddPathPrefix(toPath, pathPrefix),
13311334
...rest,

0 commit comments

Comments
 (0)