Skip to content

Commit 613f5c7

Browse files
blainekastenwardpeetLekoArtsgatsbybotpieh
authored
feat(gatsby): Add preliminary fast-refresh integration (#26664)
* chore(gatsby): Use fast refresh if the version of react installed supports it * Update detect-hot-loader-to-use.ts * idk * rm * fix ts * try to fix 2 tests.. * things * fixes * another thing * Fix most tests * fix the tests by moving the page query into hook until i can fix the multiple exports problem * Finally got FastRefresh working with page components * fix tests * one versino of react * test something * fix test * revert script changes * reset react version for gatsby-cli * Update packages/gatsby/src/utils/get-react-hot-loader-strategy.ts Co-authored-by: Ward Peeters <[email protected]> * updates * named exports * circleci: create new test with fast-refresh * another position lel * update tests * reset package json * package.json * lock file * wip stuff from blaine * wip stuff from blaine * re-add pieh e2e tests * consolidate into less components and react class * lunch break -- use portal, runtime error works * use components * error boundary * runtime mostly working * lint * get babel-code-frame for runtime working * lint * fix errors from merge * Revert "re-add pieh e2e tests" This reverts commit 66c6400 * only use eval for fast-refresh * more proper TS types * re-add isomporphic-fetch * only conditionally use fast-refresh overlay + safe guards for sourceMap * style * test run for CI * cypress conditionally * comment out the default for 17 thing * fix linting * fix circleci after wrong merge conflict resolution Co-authored-by: Ward Peeters <[email protected]> Co-authored-by: LekoArts <[email protected]> Co-authored-by: gatsbybot <[email protected]> Co-authored-by: Michal Piechowiak <[email protected]>
1 parent 2e3ec89 commit 613f5c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+920
-92
lines changed

.circleci/config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ jobs:
329329
e2e_tests_development_runtime:
330330
<<: *e2e_tests_development_runtime_alias
331331

332+
e2e_tests_development_runtime_fast_refresh:
333+
<<: *e2e_tests_development_runtime_alias
334+
environment:
335+
GATSBY_HOT_LOADER: fast-refresh
336+
CYPRESS_HOT_LOADER: fast-refresh
337+
332338
e2e_tests_development_runtime_with_experimental_react:
333339
<<: *e2e_tests_development_runtime_alias
334340

@@ -611,6 +617,8 @@ workflows:
611617
<<: *e2e-test-workflow
612618
- e2e_tests_development_runtime:
613619
<<: *e2e-test-workflow
620+
- e2e_tests_development_runtime_fast_refresh:
621+
<<: *e2e-test-workflow
614622
- e2e_tests_production_runtime:
615623
<<: *e2e-test-workflow
616624
- themes_e2e_tests_production_runtime:

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ module.exports = {
4545
allowTaggedTemplates: true,
4646
},
4747
],
48+
"no-unused-vars": [
49+
"warn",
50+
{
51+
varsIgnorePattern: "^_"
52+
}
53+
],
4854
"consistent-return": ["error"],
4955
"filenames/match-regex": ["error", "^[a-z-\\d\\.]+$", true],
5056
"no-console": "off",

e2e-tests/development-runtime/cypress/integration/functionality/query-data-caches.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,15 @@ function pageTitleAndDataAssertion(config) {
8787
cy.findByText(`Preview custom 404 page`).click()
8888
}
8989

90-
cy.getTestElement(`${config.prefix || ``}page-path`)
91-
.invoke(`text`)
92-
.should(`equal`, getExpectedCanonicalPath(config))
90+
cy.findByTestId(`${config.prefix || ``}page-path`)
91+
.should(`have.text`, getExpectedCanonicalPath(config))
9392

94-
cy.getTestElement(`${config.prefix || ``}query-data-caches-page-title`)
95-
.invoke(`text`)
96-
.should(`equal`, `This is page ${config.page}`)
93+
cy.findByTestId(`${config.prefix || ``}query-data-caches-page-title`)
94+
.should(`have.text`, `This is page ${config.page}`)
9795

98-
cy.getTestElement(`${config.prefix || ``}${config.queryType}-query-result`)
99-
.invoke(`text`)
96+
cy.findByTestId(`${config.prefix || ``}${config.queryType}-query-result`)
10097
.should(
101-
`equal`,
98+
`have.text`,
10299
`${config.slug} / ${
103100
config.page === config.initialPage ? `initial-page` : `second-page`
104101
}: ${config.data}`
@@ -119,7 +116,7 @@ function runTests(config) {
119116
data: `before-edit`,
120117
})
121118

122-
cy.getTestElement(`page-b-link`).click().waitForRouteChange()
119+
cy.findByTestId(`page-b-link`).click().waitForRouteChange()
123120

124121
// assert we navigated
125122
pageTitleAndDataAssertion({ ...config, page: `B`, data: `before-edit` })
@@ -131,10 +128,10 @@ function runTests(config) {
131128
pageTitleAndDataAssertion({ ...config, page: `B`, data: `after-edit` })
132129

133130
if (config.navigateBack === `link`) {
134-
cy.getTestElement(`page-a-link`).click().waitForRouteChange()
131+
cy.findByTestId(`page-a-link`).click().waitForRouteChange()
135132
} else if (config.navigateBack === `history`) {
136133
// this is just making sure page components don't have link to navigate back (asserting correct setup)
137-
cy.getTestElement(`page-a-link`).should(`not.exist`)
134+
cy.findByTestId(`page-a-link`).should(`not.exist`)
138135
cy.go(`back`).waitForRouteChange()
139136
}
140137

e2e-tests/development-runtime/cypress/integration/gatsby-preview/base-functionality.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ describe(`Gatsby Preview, base functionality`, () => {
99
})
1010

1111
it(`displays correct data/id`, () => {
12-
cy.get(`li`).invoke(`text`).should(`equal`, `Hello World (1)`)
12+
cy.get(`li`).should(`have.text`, `Hello World (1)`)
1313
})
1414
})

e2e-tests/development-runtime/cypress/integration/hot-reloading/arrow-functions.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@ describe(`hot-reloading anonymous arrow functions`, () => {
88
cy.visit(`/arrows`).waitForRouteChange()
99
})
1010
it(`displays placeholders on launch`, () => {
11-
cy.getTestElement(IDS.title).invoke(`text`).should(`contain`, `%TITLE%`)
11+
cy.getTestElement(IDS.title).should(`have.text`, `%TITLE%`)
1212

13-
cy.getTestElement(IDS.subTitle)
14-
.invoke(`text`)
15-
.should(`contain`, `%SUB_TITLE%`)
13+
cy.getTestElement(IDS.subTitle).should(`have.text`, `%SUB_TITLE%`)
1614
})
1715

1816
it(`updates on change`, () => {
@@ -21,6 +19,6 @@ describe(`hot-reloading anonymous arrow functions`, () => {
2119
`npm run update -- --file src/components/title.tsx --replacements "TITLE:${text}"`
2220
)
2321

24-
cy.getTestElement(IDS.title).invoke(`text`).should(`eq`, text)
22+
cy.getTestElement(IDS.title).should(`have.text`, text)
2523
})
2624
})

e2e-tests/development-runtime/cypress/integration/hot-reloading/class-component.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ describe(`reloading class component`, () => {
55
cy.visit(`/`).waitForRouteChange()
66
})
77
it(`displays placeholder on launch`, () => {
8-
cy.getTestElement(TEST_ID)
9-
.invoke(`text`)
10-
.should(`contain`, `%CLASS_COMPONENT%`)
8+
cy.getTestElement(TEST_ID).should(`contain.text`, `%CLASS_COMPONENT%`)
119
})
1210

1311
it(`updates placeholder and hot reloads`, () => {
@@ -16,7 +14,7 @@ describe(`reloading class component`, () => {
1614
`npm run update -- --file src/components/class-component.js --replacements "CLASS_COMPONENT:${text}"`
1715
)
1816

19-
cy.getTestElement(TEST_ID).invoke(`text`).should(`contain`, text)
17+
cy.getTestElement(TEST_ID).should(`contain.text`, text)
2018
})
2119

2220
it(`updates state and hot reloads`, () => {
@@ -25,8 +23,9 @@ describe(`reloading class component`, () => {
2523
`npm run update -- --file src/components/class-component.js --replacements "CUSTOM_STATE:${value}"`
2624
)
2725

28-
cy.getTestElement(`stateful-${TEST_ID}`)
29-
.invoke(`text`)
30-
.should(`eq`, `Custom Message`)
26+
cy.getTestElement(`stateful-${TEST_ID}`).should(
27+
`have.text`,
28+
`Custom Message`
29+
)
3130
})
3231
})

e2e-tests/development-runtime/cypress/integration/hot-reloading/page-component.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ describe(`hot reloading page component`, () => {
55
cy.visit(`/`).waitForRouteChange()
66
})
77
it(`displays placeholder content on launch`, () => {
8-
cy.getTestElement(TEST_ID).invoke(`text`).should(`contain`, `%GATSBY_SITE%`)
8+
cy.getTestElement(TEST_ID).should(`contain.text`, `%GATSBY_SITE%`)
99
})
1010

1111
it(`hot reloads with new content`, () => {
@@ -14,6 +14,6 @@ describe(`hot reloading page component`, () => {
1414
`npm run update -- --file src/pages/index.js --replacements "GATSBY_SITE:${text}"`
1515
)
1616

17-
cy.getTestElement(TEST_ID).invoke(`text`).should(`contain`, text)
17+
cy.getTestElement(TEST_ID).should(`contain.text`, text)
1818
})
1919
})

e2e-tests/development-runtime/cypress/integration/hot-reloading/template-component.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ describe(`hot reloading template component`, () => {
1515
`npm run update -- --file src/templates/blog-post.js --replacements "${TEMPLATE}:${message}"`
1616
)
1717

18-
cy.getTestElement(TEST_ID).invoke(`text`).should(`eq`, `Hello ${message}`)
18+
cy.getTestElement(TEST_ID).should(`have.text`, `Hello ${message}`)
1919
})
2020
})

e2e-tests/development-runtime/cypress/integration/navigation/linking.js

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,23 +143,46 @@ describe(`navigation`, () => {
143143
})
144144
})
145145

146-
describe(`All location changes should trigger an effect`, () => {
147-
beforeEach(() => {
148-
cy.visit(`/navigation-effects`).waitForRouteChange()
149-
})
150-
151-
it(`should trigger an effect after a search param has changed`, () => {
152-
cy.getTestElement(`effect-message`).invoke(`text`).should(`eq`, `Waiting for effect`)
153-
cy.getTestElement(`send-search-message`).click().waitForRouteChange()
154-
cy.getTestElement(`effect-message`).invoke(`text`).should(`eq`, `?message=searchParam`)
155-
})
156-
157-
it(`should trigger an effect after the hash has changed`, () => {
158-
cy.getTestElement(`effect-message`).invoke(`text`).should(`eq`, `Waiting for effect`)
159-
cy.getTestElement(`send-hash-message`).click().waitForRouteChange()
160-
cy.getTestElement(`effect-message`).invoke(`text`).should(`eq`, `#message-hash`)
161-
})
162-
})
146+
if (Cypress.env("HOT_LOADER") !== `fast-refresh`) {
147+
describe(`All location changes should trigger an effect (react-hot-loader)`, () => {
148+
beforeEach(() => {
149+
cy.visit(`/navigation-effects`).waitForRouteChange()
150+
})
151+
152+
it(`should trigger an effect after a search param has changed`, () => {
153+
cy.findByTestId(`effect-message`).should(`have.text`, `Waiting for effect`)
154+
cy.findByTestId(`send-search-message`).click().waitForRouteChange()
155+
cy.findByTestId(`effect-message`).should(`have.text`, `?message=searchParam`)
156+
})
157+
158+
it(`should trigger an effect after the hash has changed`, () => {
159+
cy.findByTestId(`effect-message`).should(`have.text`, `Waiting for effect`)
160+
cy.findByTestId(`send-hash-message`).click().waitForRouteChange()
161+
cy.findByTestId(`effect-message`).should(`have.text`, `#message-hash`)
162+
})
163+
})
164+
}
165+
166+
// TODO: Check if this is the correct behavior
167+
if (Cypress.env("HOT_LOADER") === `fast-refresh`) {
168+
describe(`All location changes should trigger an effect (fast-refresh)`, () => {
169+
beforeEach(() => {
170+
cy.visit(`/navigation-effects`).waitForRouteChange()
171+
})
172+
173+
it(`should trigger an effect after a search param has changed`, () => {
174+
cy.findByTestId(`effect-message`).should(`have.text`, ``)
175+
cy.findByTestId(`send-search-message`).click().waitForRouteChange()
176+
cy.findByTestId(`effect-message`).should(`have.text`, `?message=searchParam`)
177+
})
178+
179+
it(`should trigger an effect after the hash has changed`, () => {
180+
cy.findByTestId(`effect-message`).should(`have.text`, ``)
181+
cy.findByTestId(`send-hash-message`).click().waitForRouteChange()
182+
cy.findByTestId(`effect-message`).should(`have.text`, `#message-hash`)
183+
})
184+
})
185+
}
163186

164187
describe(`Route lifecycle update order`, () => {
165188
it(`calls onPreRouteUpdate, render and onRouteUpdate the correct amount of times on route change`, () => {

e2e-tests/development-runtime/gatsby-config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// isomorphic-fetch sets global.fetch which seems to conflicts with source-map@<0.8.0 where it does a
22
// simple browser check if (global.fetch) which is true when isomorphic-fetch is used. This creates an
33
// exception in react-hot-loader. @see https://github.com/gatsbyjs/gatsby/pull/13713
4+
//
5+
// This is only necessary if we are testing react < 16.9 or if you are forcing GATSBY_HOT_LOADER=react-hot-loader.
6+
// When we are using fast-refresh we do not need this hack.
7+
// TODO: Remove once fast-refresh is the default
8+
//
49
require(`isomorphic-fetch`)
510

611
module.exports = {

e2e-tests/development-runtime/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "1.0.0",
55
"author": "Dustin Schau <[email protected]>",
66
"dependencies": {
7-
"gatsby": "^2.4.4",
7+
"gatsby": "^2.27.1",
88
"gatsby-image": "^2.0.41",
99
"gatsby-plugin-image": "^0.0.2",
1010
"gatsby-plugin-manifest": "^2.0.17",
@@ -18,8 +18,8 @@
1818
"gatsby-transformer-sharp": "^2.1.19",
1919
"isomorphic-fetch": "^2.2.1",
2020
"prop-types": "^15.6.2",
21-
"react": "16.8.6",
22-
"react-dom": "16.8.6",
21+
"react": "16.9.0",
22+
"react-dom": "16.9.0",
2323
"react-helmet": "^5.2.1"
2424
},
2525
"keywords": [
@@ -30,6 +30,7 @@
3030
"scripts": {
3131
"build": "gatsby build",
3232
"develop": "cross-env CYPRESS_SUPPORT=y ENABLE_GATSBY_REFRESH_ENDPOINT=true gatsby develop",
33+
"develop:fast-refresh": "cross-env CYPRESS_SUPPORT=y ENABLE_GATSBY_REFRESH_ENDPOINT=true GATSBY_HOT_LOADER=fast-refresh gatsby develop",
3334
"serve": "gatsby serve",
3435
"start": "npm run develop",
3536
"format": "prettier --write \"src/**/*.js\"",
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import React from "react"
22

3-
export default () => <h2 data-testid="sub-title">{`%SUB_TITLE%`}</h2>
3+
export default function SubTitle() {
4+
return (
5+
<h2 data-testid="sub-title">{`%SUB_TITLE%`}</h2>
6+
)
7+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
import React from "react"
22

3-
export default () => <h1 data-testid="title">{`%TITLE%`}</h1>
3+
export default function Title() {
4+
return (
5+
<h1 data-testid="title">{`%TITLE%`}</h1>
6+
)
7+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from "react"
22
import Layout from "../../components/layout"
33

4-
export default props => (
4+
const ClientDynamicID = props => (
55
<Layout>
66
<h1 data-testid="title">Client Dynamic Route</h1>
77
<h2 data-testid="params">{props.params.id}</h2>
88
</Layout>
99
)
10+
11+
export default ClientDynamicID
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from "react"
22
import Layout from "../../../components/layout"
33

4-
export default props => (
4+
const NamedSplat = props => (
55
<Layout>
66
<h1 data-testid="title">Named SPLAT</h1>
77
<h2 data-testid="splat">{props.params.name}</h2>
88
</Layout>
99
)
10+
11+
export default NamedSplat
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import React from "react"
22
import Layout from "../../../../components/layout"
33

4-
export default props => (
4+
const NestedClientOnlyRoute = props => (
55
<Layout>
66
<h1 data-testid="title">Nested Dynamic Route</h1>
77
<h2 data-testid="params-brand">{props.params.brand}</h2>
88
<h2 data-testid="params-product">{props.params.product}</h2>
99
</Layout>
1010
)
11+
12+
export default NestedClientOnlyRoute
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from "react"
22
import Layout from "../../../components/layout"
33

4-
export default props => (
4+
const SplatRoute = props => (
55
<Layout>
66
<h1 data-testid="title">SPLAT!</h1>
77
<h2 data-testid="splat">{props.params["*"]}</h2>
88
</Layout>
99
)
10+
11+
export default SplatRoute
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import React from "react"
22
import Layout from "../../../components/layout"
33

4-
export default props => (
4+
const FakeDataTitleName = props => (
55
<Layout>
66
<h1 data-testid="title">Named SPLAT Nested with Collection Route!</h1>
77
<h2 data-testid="splat">{props.params.name}</h2>
88
</Layout>
99
)
10+
11+
export default FakeDataTitleName

e2e-tests/development-runtime/src/pages/queries-in-packages.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import SEO from "gatsby-seo"
33

44
import Layout from "../components/layout"
55

6-
export default () => (
6+
const QueriesInPackages = () => (
77
<Layout>
88
<SEO
99
title="Testing queries in packages"
1010
keywords={[`gatsby`, `application`, `react`, `queries in component`]}
1111
/>
1212
</Layout>
1313
)
14+
15+
export default QueriesInPackages

e2e-tests/development-runtime/src/utils/instrument-page.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from "react"
22

3-
export default Page =>
3+
const InstrumentPage = Page =>
44
class extends React.Component {
55
addLogEntry(action) {
66
if (typeof window !== `undefined`) {
@@ -31,3 +31,5 @@ export default Page =>
3131
return <Page {...this.props} />
3232
}
3333
}
34+
35+
export default InstrumentPage

0 commit comments

Comments
 (0)