Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 55778eb

Browse files
authored
fix(hmr): accept hot updates for modules above page templates (#29752)
* fix(hmr): accept hot updates for modules above page templates * actually use fast-refresh for gatsby-browser and shadowed theme-ui config * exclude actually need to be instance of RegExp * tmp * more tmp * init navigation after loader is set * cleanup tmp code * init navigation after resources for current page are loaded * remove commented out code * revert devtool change
1 parent 7f9bcf1 commit 55778eb

File tree

7 files changed

+74
-29
lines changed

7 files changed

+74
-29
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const TEST_ID = `gatsby-browser-hmr`
2+
3+
describe(`hot reloading above page template (gatsby-browser)`, () => {
4+
beforeEach(() => {
5+
cy.visit(`/`).waitForRouteChange()
6+
})
7+
it(`displays placeholder content on launch`, () => {
8+
cy.getTestElement(TEST_ID).should(
9+
`contain.text`,
10+
`%TEST_HMR_IN_GATSBY_BROWSER%`
11+
)
12+
})
13+
14+
it(`hot reloads with new content`, () => {
15+
const text = `HMR_IN_GATSBY_BROWSER_WORKS`
16+
cy.exec(
17+
`npm run update -- --file src/wrap-root-element.js --replacements "TEST_HMR_IN_GATSBY_BROWSER:${text}"`
18+
)
19+
20+
cy.waitForHmr()
21+
22+
cy.getTestElement(TEST_ID).should(`contain.text`, text)
23+
})
24+
})
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const Wrapper = require(`./src/wrap-root-element`).default
1+
import WrapRootElement from "./src/wrap-root-element"
2+
import * as React from "react"
23

34
if (typeof window !== `undefined`) {
45
window.___PageComponentLifecycleCallsLog = []
@@ -11,16 +12,17 @@ const addLogEntry = (action, location) => {
1112
})
1213
}
1314

14-
exports.onPreRouteUpdate = ({ location }) => {
15+
export const onPreRouteUpdate = ({ location }) => {
1516
addLogEntry(`onPreRouteUpdate`, location)
1617
}
1718

18-
exports.onRouteUpdate = ({ location }) => {
19+
export const onRouteUpdate = ({ location }) => {
1920
addLogEntry(`onRouteUpdate`, location)
2021
}
21-
22-
exports.onPrefetchPathname = ({ pathname }) => {
22+
export const onPrefetchPathname = ({ pathname }) => {
2323
addLogEntry(`onPrefetchPathname`, pathname)
2424
}
2525

26-
exports.wrapRootElement = Wrapper
26+
export const wrapRootElement = ({ element }) => (
27+
<WrapRootElement element={element} />
28+
)

e2e-tests/development-runtime/src/wrap-root-element.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ const WrapRootElement = ({ element }) => (
2222
<div>
2323
StaticQuery in wrapRootElement test (should show site title):
2424
<span data-testid="wrap-root-element-result">{title}</span>
25+
<div data-testid="gatsby-browser-hmr">
26+
%TEST_HMR_IN_GATSBY_BROWSER%
27+
</div>
2528
</div>
2629
</>
2730
)}

packages/gatsby/cache-dir/app.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ import asyncRequires from "$virtual/async-requires"
1313
// Generated during bootstrap
1414
import matchPaths from "$virtual/match-paths.json"
1515
import { LoadingIndicatorEventHandler } from "./loading-indicator"
16-
16+
import Root from "./root"
17+
import { init as navigationInit } from "./navigation"
1718
// ensure in develop we have at least some .css (even if it's empty).
1819
// this is so there is no warning about not matching content-type when site doesn't include any regular css (for example when css-in-js is used)
1920
// this also make sure that if all css is removed in develop we are not left with stale commons.css that have stale content
2021
import "./blank.css"
2122

22-
// Enable fast-refresh for virtual sync-requires
23-
module.hot.accept(`$virtual/async-requires`, () => {
24-
// Manually reload
25-
})
23+
// Enable fast-refresh for virtual sync-requires and gatsby-browser
24+
module.hot.accept([`$virtual/async-requires`, `./api-runner-browser`])
2625

2726
window.___emitter = emitter
2827

@@ -160,8 +159,8 @@ apiRunnerAsync(`onClientEntry`).then(() => {
160159
loader.loadPage(`/404.html`),
161160
loader.loadPage(window.location.pathname),
162161
]).then(() => {
163-
const preferDefault = m => (m && m.default) || m
164-
const Root = preferDefault(require(`./root`))
162+
navigationInit()
163+
165164
domReady(() => {
166165
if (dismissLoadingIndicator) {
167166
dismissLoadingIndicator()

packages/gatsby/cache-dir/root.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@ import React from "react"
22
import { Router, Location, BaseContext } from "@reach/router"
33
import { ScrollContext } from "gatsby-react-router-scroll"
44

5-
import {
6-
shouldUpdateScroll,
7-
init as navigationInit,
8-
RouteUpdates,
9-
} from "./navigation"
5+
import { shouldUpdateScroll, RouteUpdates } from "./navigation"
106
import { apiRunner } from "./api-runner-browser"
117
import loader from "./loader"
128
import { PageQueryStore, StaticQueryStore } from "./query-result-store"
139
import EnsureResources from "./ensure-resources"
1410
import FastRefreshOverlay from "./fast-refresh-overlay"
1511

16-
navigationInit()
17-
1812
// In gatsby v2 if Router is used in page using matchPaths
1913
// paths need to contain full path.
2014
// For example:
@@ -103,7 +97,7 @@ const Root = () => (
10397
)
10498

10599
// Let site, plugins wrap the site e.g. for Redux.
106-
const WrappedRoot = apiRunner(
100+
const rootWrappedWithWrapRootElement = apiRunner(
107101
`wrapRootElement`,
108102
{ element: <Root /> },
109103
<Root />,
@@ -112,8 +106,12 @@ const WrappedRoot = apiRunner(
112106
}
113107
).pop()
114108

115-
export default () => (
116-
<FastRefreshOverlay>
117-
<StaticQueryStore>{WrappedRoot}</StaticQueryStore>
118-
</FastRefreshOverlay>
119-
)
109+
function RootWrappedWithOverlayAndProvider() {
110+
return (
111+
<FastRefreshOverlay>
112+
<StaticQueryStore>{rootWrappedWithWrapRootElement}</StaticQueryStore>
113+
</FastRefreshOverlay>
114+
)
115+
}
116+
117+
export default RootWrappedWithOverlayAndProvider

packages/gatsby/src/utils/webpack-utils.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,13 +731,32 @@ export const createWebpackUtils = (
731731
}
732732
): CssMinimizerPlugin => new CssMinimizerPlugin(options)
733733

734-
plugins.fastRefresh = (): Plugin =>
735-
new ReactRefreshWebpackPlugin({
734+
plugins.fastRefresh = ({ modulesThatUseGatsby }): Plugin => {
735+
const regExpToHack = /node_modules/
736+
regExpToHack.test = (modulePath: string): boolean => {
737+
// when it's not coming from node_modules we treat it as a source file.
738+
if (!vendorRegex.test(modulePath)) {
739+
return false
740+
}
741+
742+
// If the module uses Gatsby as a dependency
743+
// we want to treat it as src because of shadowing
744+
return !modulesThatUseGatsby.some(module =>
745+
modulePath.includes(module.path)
746+
)
747+
}
748+
749+
return new ReactRefreshWebpackPlugin({
736750
overlay: {
737751
sockIntegration: `whm`,
738752
module: path.join(__dirname, `fast-refresh-module`),
739753
},
754+
// this is a bit hacky - exclude expect string or regexp or array of those
755+
// so this is tricking ReactRefreshWebpackPlugin with providing regexp with
756+
// overwritten .test method
757+
exclude: regExpToHack,
740758
})
759+
}
741760

742761
plugins.extractText = (options: any): Plugin =>
743762
new MiniCssExtractPlugin({

packages/gatsby/src/utils/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ module.exports = async (
216216
case `develop`: {
217217
configPlugins = configPlugins
218218
.concat([
219-
plugins.fastRefresh(),
219+
plugins.fastRefresh({ modulesThatUseGatsby }),
220220
plugins.hotModuleReplacement(),
221221
plugins.noEmitOnErrors(),
222222
plugins.eslintGraphqlSchemaReload(),

0 commit comments

Comments
 (0)