Skip to content
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

feat(gatsby): trailingSlash config option #34268

Merged
merged 76 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
49f1672
config option
LekoArts Dec 14, 2021
1e7646c
Merge branch 'master' into trailing-slash
LekoArts Dec 14, 2021
db532e4
ssr part
LekoArts Dec 15, 2021
0f8f353
docs, types
LekoArts Dec 15, 2021
55d47aa
move applyTrailingSlash to gatsby-page-utils
LekoArts Dec 15, 2021
248877f
dev-404-page handling
LekoArts Dec 15, 2021
396f986
snapshot update
LekoArts Dec 15, 2021
40aea6f
wip
LekoArts Dec 15, 2021
d590d4f
docs
LekoArts Dec 15, 2021
d4a149c
add todo
LekoArts Dec 15, 2021
dae6ddb
gatsby-link :yey:
LekoArts Dec 16, 2021
5e02152
move func into option if case
LekoArts Dec 16, 2021
8949a3e
put rewriteLinkPath to own file + add unit tests
LekoArts Dec 16, 2021
6648b77
fix order of args
LekoArts Dec 16, 2021
992c6d6
fix number behavior
LekoArts Dec 17, 2021
9b2acc5
e2e test addition
LekoArts Dec 17, 2021
b6fdb4d
circle ci addition
LekoArts Dec 17, 2021
429c75e
silence warning
LekoArts Dec 17, 2021
ba4dbd9
revert create-path
LekoArts Dec 17, 2021
07f9343
use createPath + applyTrailingSlashOption
LekoArts Dec 17, 2021
3909933
begin derive-path work
LekoArts Dec 17, 2021
aeec8fd
Merge branch 'master' into trailing-slash
LekoArts Dec 19, 2021
9a89baa
Merge branch 'master' into trailing-slash
LekoArts Jan 4, 2022
abd7c02
change derivePath function
LekoArts Jan 4, 2022
c539129
add client-only and index page
LekoArts Jan 4, 2022
7213133
remove unused import
LekoArts Jan 4, 2022
be16962
handle route params + make ignore work?
LekoArts Jan 4, 2022
6c8e3bc
splat routes + gatsbyPath
LekoArts Jan 5, 2022
0623374
fix ts error
LekoArts Jan 5, 2022
1074661
use npm-run-all
LekoArts Jan 5, 2022
531d42a
prep tests
LekoArts Jan 6, 2022
b062129
always
LekoArts Jan 6, 2022
3a5c0a4
fix gatsbyPath
LekoArts Jan 6, 2022
8147f56
update tests
LekoArts Jan 6, 2022
97e6a3c
update trailingSlash ts type
LekoArts Jan 6, 2022
5a81041
Merge branch 'master' into trailing-slash
LekoArts Jan 6, 2022
0708e46
Update types.ts
LekoArts Jan 6, 2022
a5c77da
add cypress dashboard entries
LekoArts Jan 6, 2022
d7963af
update cypress script to record
LekoArts Jan 6, 2022
10996bd
Merge branch 'master' into trailing-slash
LekoArts Jan 7, 2022
5cab2e4
update package.json from merge
LekoArts Jan 7, 2022
f8b9d2e
tmp
LekoArts Jan 7, 2022
a370934
Merge branch 'master' into trailing-slash
LekoArts Jan 10, 2022
0a522d4
use regex for local-link and add test
LekoArts Jan 10, 2022
a6244b4
clean between test runs
LekoArts Jan 10, 2022
d2477bb
feat(gatsby): Send config keys over IPC (#34411)
LekoArts Jan 11, 2022
917d2be
Merge branch 'master' into trailing-slash
LekoArts Jan 11, 2022
1b3b47f
get tests to pass?
LekoArts Jan 11, 2022
1887b51
Merge branch 'master' into trailing-slash
LekoArts Jan 12, 2022
ecdfa26
update script
LekoArts Jan 12, 2022
1bd7cca
add legacy tests
LekoArts Jan 13, 2022
94b1e78
wip dev
LekoArts Jan 13, 2022
267f6cd
add express middleware
LekoArts Jan 13, 2022
a583544
tests
LekoArts Jan 13, 2022
84fb2cf
Update legacy.js
LekoArts Jan 13, 2022
3cb65ed
Update legacy.js
LekoArts Jan 13, 2022
bb9b1d8
Update serve.ts
LekoArts Jan 14, 2022
0970fbf
Merge branch 'master' into trailing-slash
LekoArts Jan 14, 2022
43537d8
split up tests into more fine-grained
LekoArts Jan 16, 2022
3cf0dc2
format
LekoArts Jan 16, 2022
0a8dfc0
add clean in between build & develop + darkmode
LekoArts Jan 16, 2022
257febb
fix two smaller todos
LekoArts Jan 17, 2022
8b448ce
fix(gatsby-plugin-gatsby-cloud): Revert removal of _gatsby-config.jso…
marvinjude Jan 19, 2022
60ff0ab
Update packages/gatsby-plugin-gatsby-cloud/src/create-site-config.js
LekoArts Jan 19, 2022
b3f4783
feat(gatsby): Add telemetry tracking for trailing slash option (#34529)
marvinjude Jan 19, 2022
a501683
change local-link
LekoArts Jan 20, 2022
4ee7ff6
Merge branch 'master' into trailing-slash
LekoArts Jan 20, 2022
159969b
feat(gatsby): clear cache when trailing slash option changes (#34547)
marvinjude Jan 24, 2022
dd8cc06
test(gatsby): Trailing slash client only splat (#34538)
tyhopp Jan 24, 2022
9bffe80
Merge branch 'master' into trailing-slash
LekoArts Jan 24, 2022
820bba8
Update package.json
LekoArts Jan 24, 2022
8f034c6
test(gatsby): Assert 301 redirects in E2E Tests (#34554)
marvinjude Jan 26, 2022
8235639
Apply suggestions from code review
LekoArts Jan 27, 2022
50f1ae5
fix lint
LekoArts Jan 27, 2022
ad04771
code review
LekoArts Jan 28, 2022
caafd5c
Merge remote-tracking branch 'upstream/master' into trailing-slash
Jan 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,19 @@ jobs:
- store_test_results:
path: e2e-tests/contentful/cypress/results

e2e_tests_trailing-slash:
<<: *e2e-executor
environment:
<<: *e2e-executor-env
CYPRESS_PROJECT_ID: ofxgw8
CYPRESS_RECORD_KEY: 29c32742-6b85-40e0-9b45-a4c722749d52
steps:
- e2e-test:
test_path: e2e-tests/trailing-slash
test_command: yarn test
- store_test_results:
path: e2e-tests/trailing-slash/cypress/results

starters_validate:
executor: node
steps:
Expand Down Expand Up @@ -669,6 +682,8 @@ workflows:
<<: *e2e-test-workflow
- e2e_tests_contentful:
<<: *e2e-test-workflow
- e2e_tests_trailing-slash:
<<: *e2e-test-workflow
- e2e_tests_development_runtime:
<<: *e2e-test-workflow
- e2e_tests_production_runtime:
Expand Down
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports = {
__ASSET_PREFIX__: true,
_CFLAGS_: true,
__GATSBY: true,
__TRAILING_SLASH__: true,
},
rules: {
"@babel/no-unused-expressions": [
Expand Down
33 changes: 23 additions & 10 deletions docs/docs/reference/config-files/gatsby-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,16 @@ module.exports = {
Options available to set within `gatsby-config.js` include:

1. [siteMetadata](#sitemetadata) (object)
2. [plugins](#plugins) (array)
3. [flags](#flags) (object)
4. [pathPrefix](#pathprefix) (string)
5. [polyfill](#polyfill) (boolean)
6. [mapping](#mapping-node-types) (object)
7. [proxy](#proxy) (object)
8. [developMiddleware](#advanced-proxying-with-developmiddleware) (function)
1. [plugins](#plugins) (array)
1. [flags](#flags) (object)
1. [pathPrefix](#pathprefix) (string)
1. [trailingSlash](#trailingslash) (string)
1. [polyfill](#polyfill) (boolean)
1. [mapping](#mapping-node-types) (object)
1. [proxy](#proxy) (object)
1. [developMiddleware](#advanced-proxying-with-developmiddleware) (function)
1. [jsxRuntime](#jsxruntime) (string)
1. [jsxImportSource](#jsximportsource) (string)

## siteMetadata

Expand All @@ -68,7 +71,7 @@ This way you can store it in one place, and pull it whenever you need it. If you

See a full description and sample usage in [Gatsby.js Tutorial Part Four](/docs/tutorial/part-4/#data-in-gatsby).

## Plugins
## plugins

Plugins are Node.js packages that implement Gatsby APIs. The config file accepts an array of plugins. Some plugins may need only to be listed by name, while others may take options (see the docs for individual plugins).

Expand Down Expand Up @@ -135,7 +138,7 @@ module.exports = {

See more about [Plugins](/docs/plugins/) for more on utilizing plugins, and to see available official and community plugins.

## Flags
## flags

Flags let sites enable experimental or upcoming changes that are still in testing or waiting for the next major release.

Expand All @@ -161,7 +164,17 @@ module.exports = {

See more about [Adding a Path Prefix](/docs/how-to/previews-deploys-hosting/path-prefix/).

## Polyfill
## trailingSlash

Configures the creation of URLs and whether to remove, append, or ignore trailing slashes.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

- `always`: Always add trailing slashes to each URL, e.g. `/x` to `/x/`.
- `never`: Remove all trailing slashes on each URL, e.g. `/x/` to `/x`.
- `ignore`: Don't automatically modify the URL

Until Gatsby v4 it'll be set to `legacy` by default, in Gatsby v5 the default mode will be `always`. Gatsby Cloud automatically handles and supports the `trailingSlash` option, any other hosting provider (or if you're managing this on your own) should follow the "Redirects, and expected behavior from the hosting provider" section on the [initial RFC](https://github.com/gatsbyjs/gatsby/discussions/34205).

## polyfill

Gatsby uses the ES6 Promise API. Because some browsers don't support this, Gatsby includes a Promise polyfill by default.

Expand Down
13 changes: 13 additions & 0 deletions e2e-tests/trailing-slash/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Project dependencies
.cache
node_modules
yarn-error.log

# Build assets
/public
.DS_Store
/assets

# Cypress output
cypress/videos/
cypress/screenshots/
15 changes: 15 additions & 0 deletions e2e-tests/trailing-slash/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# trailing-slash E2E Test

This Cypress suite tests the `trailingSlash` option inside `gatsby-config` and its various different settings it takes. When you want to work on it, start watching packages inside the `packages` and start `gatsby-dev-cli` in this E2E test suite.

Locally you can run for development:

```shell
TRAILING_SLASH=your-option yarn debug:develop
```

And for a build + serve:

```shell
TRAILING_SLASH=your-option yarn build && yarn debug:build
```
4 changes: 4 additions & 0 deletions e2e-tests/trailing-slash/cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"videoUploadOnPasses": false,
"chromeWebSecurity": false
}
5 changes: 5 additions & 0 deletions e2e-tests/trailing-slash/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
144 changes: 144 additions & 0 deletions e2e-tests/trailing-slash/cypress/integration/always.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
describe(`always`, () => {
beforeEach(() => {
cy.visit(`/`).waitForRouteChange()
})
it(`page-creator without slash`, () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly about this, so feel free to ignore it.

We could parameterize a large amount of these tests to clean them up a bit. Something like:

[
  {title: `page-creator without slash`, button: `page-creator-without`, expected: `/page-2/`},
  ...
].forEach({title, button, expected} => it(title, () => {
    cy.getTestElement(button).click()
    cy.waitForRouteChange().assertRoute(expected)
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that could be a good follow-up for some time

cy.getTestElement(`page-creator-without`).click()
cy.waitForRouteChange().assertRoute(`/page-2/`)
})
it(`page-creator with slash`, () => {
cy.getTestElement(`page-creator-with`).click()
cy.waitForRouteChange().assertRoute(`/page-2/`)
})
it(`create-page with slash`, () => {
cy.getTestElement(`create-page-with`).click()
cy.waitForRouteChange().assertRoute(`/create-page/with/`)
})
it(`create-page without slash`, () => {
cy.getTestElement(`create-page-without`).click()
cy.waitForRouteChange().assertRoute(`/create-page/without/`)
})
it(`fs-api with slash`, () => {
cy.getTestElement(`fs-api-with`).click()
cy.waitForRouteChange().assertRoute(`/fs-api/with/`)
})
it(`fs-api without slash`, () => {
cy.getTestElement(`fs-api-without`).click()
cy.waitForRouteChange().assertRoute(`/fs-api/without/`)
})
it(`fs-api-simple with slash`, () => {
cy.getTestElement(`fs-api-simple-with`).click()
cy.waitForRouteChange().assertRoute(`/fs-api-simple/with/`)
})
it(`fs-api-simple without slash`, () => {
cy.getTestElement(`fs-api-simple-without`).click()
cy.waitForRouteChange().assertRoute(`/fs-api-simple/without/`)
})
it(`gatsbyPath works`, () => {
cy.getTestElement(`gatsby-path-1`).should(
"have.attr",
"href",
"/fs-api-simple/with/"
)
cy.getTestElement(`gatsby-path-2`).should(
"have.attr",
"href",
"/fs-api-simple/without/"
)
})
it(`hash`, () => {
cy.getTestElement(`hash`).click()
cy.waitForRouteChange().assertRoute(`/page-2/#anchor`)
})
it(`hash trailing`, () => {
cy.getTestElement(`hash-trailing`).click()
cy.waitForRouteChange().assertRoute(`/page-2/#anchor`)
})
it(`query-param`, () => {
cy.getTestElement(`query-param`).click()
cy.waitForRouteChange().assertRoute(`/page-2/?query_param=hello`)
})
it(`query-param-hash`, () => {
cy.getTestElement(`query-param-hash`).click()
cy.waitForRouteChange().assertRoute(`/page-2/?query_param=hello#anchor`)
})
it(`client-only-simple without slash`, () => {
cy.getTestElement(`client-only-simple-without`).click()
cy.waitForRouteChange().assertRoute(`/client-only/without/`)
cy.getTestElement(`title`).should(`have.text`, `without`)
})
it(`client-only-simple with slash`, () => {
cy.getTestElement(`client-only-simple-with`).click()
cy.waitForRouteChange().assertRoute(`/client-only/with/`)
cy.getTestElement(`title`).should(`have.text`, `with`)
})
it(`client-only without slash`, () => {
cy.getTestElement(`client-only-without`).click()
cy.waitForRouteChange().assertRoute(`/fs-api/without/without/`)
cy.getTestElement(`title`).should(`have.text`, `without`)
})
it(`client-only with slash`, () => {
cy.getTestElement(`client-only-with`).click()
cy.waitForRouteChange().assertRoute(`/fs-api/with/with/`)
cy.getTestElement(`title`).should(`have.text`, `with`)
})
})

describe(`always (direct visits)`, () => {
beforeEach(() => {
cy.visit(`/`).waitForRouteChange()
})
it(`page-creator`, () => {
cy.visit(`/page-2`).waitForRouteChange().assertRoute(`/page-2/`)
})
it(`create-page with`, () => {
cy.visit(`/create-page/with/`)
.waitForRouteChange()
.assertRoute(`/create-page/with/`)
})
it(`create-page without`, () => {
cy.visit(`/create-page/without`)
.waitForRouteChange()
.assertRoute(`/create-page/without/`)
})
it(`fs-api-simple with`, () => {
cy.visit(`/fs-api-simple/with/`)
.waitForRouteChange()
.assertRoute(`/fs-api-simple/with/`)
})
it(`fs-api-simple without`, () => {
cy.visit(`/fs-api-simple/without`)
.waitForRouteChange()
.assertRoute(`/fs-api-simple/without/`)
})
it(`client-only-simple with`, () => {
cy.visit(`/client-only/with/`)
.waitForRouteChange()
.assertRoute(`/client-only/with/`)
})
it(`client-only-simple without`, () => {
cy.visit(`/client-only/without`)
.waitForRouteChange()
.assertRoute(`/client-only/without/`)
})
it(`client-only with`, () => {
cy.visit(`/fs-api/with/with/`)
.waitForRouteChange()
.assertRoute(`/fs-api/with/with/`)
})
it(`client-only without`, () => {
cy.visit(`/fs-api/without/without`)
.waitForRouteChange()
.assertRoute(`/fs-api/without/without/`)
})
it(`query-param-hash with`, () => {
cy.visit(`/page-2/?query_param=hello#anchor`)
.waitForRouteChange()
.assertRoute(`/page-2/?query_param=hello#anchor`)
})
it(`query-param-hash without`, () => {
cy.visit(`/page-2?query_param=hello#anchor`)
.waitForRouteChange()
.assertRoute(`/page-2/?query_param=hello#anchor`)
})
})
Loading