Skip to content

Commit 89d23c6

Browse files
KyleAMathewspieh
authored andcommitted
feature(gatsby): Pause dev-ssr watching between page loads to avoid slowing down regular develop-js HMR (#28394)
* feature(gatsby): Pause dev-ssr watching between page loads to avoid slowing down regular develop-js HMR * update snapshot * Don't double-resolve + add activity for building the SSR bundle * Add timeout for tests to ensure that dev server has time to bundle SSR + remove activity timers as not helpful * Update packages/gatsby/src/commands/build-html.ts Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> * fix typo * Don't resume if nothing has changed * Update packages/gatsby/src/commands/build-html.ts Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> * Didn't need this Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com> (cherry picked from commit 8ff6245)
1 parent 5a0489d commit 89d23c6

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

integration-tests/ssr/__tests__/ssr.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ describe(`SSR`, () => {
99

1010
expect(html).toMatchSnapshot()
1111
})
12+
1213
test(`dev & build outputs match`, async () => {
1314
const childProcess = await execa(`yarn`, [`test-output`])
1415

1516
expect(childProcess.code).toEqual(0)
16-
})
17+
}, 15000)
18+
1719
test(`it generates an error page correctly`, async () => {
1820
const src = path.join(__dirname, `/fixtures/bad-page.js`)
1921
const dest = path.join(__dirname, `../src/pages/bad-page.js`)

integration-tests/ssr/test-output.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
)
4343
)
4444

45+
// Fetch once to trigger re-compilation.
46+
await fetch(`${devSiteBasePath}/${path}`)
47+
48+
// Then wait for 6 seconds to ensure it's ready to go.
49+
// Otherwise, tests are flaky depending on the speed of the testing machine.
50+
await new Promise(resolve => {
51+
setTimeout(() => resolve(), 6000)
52+
})
53+
4554
let devStatus = 200
4655
const rawDevHtml = await fetch(`${devSiteBasePath}/${path}`).then(res => {
4756
devStatus = res.status

packages/gatsby/src/commands/build-html.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import telemetry from "gatsby-telemetry"
66
import { chunk } from "lodash"
77
import webpack from "webpack"
88

9+
import { emitter } from "../redux"
910
import webpackConfig from "../utils/webpack.config"
1011
import { structureWebpackErrors } from "../utils/webpack-error-utils"
1112

@@ -14,6 +15,30 @@ import { IProgram, Stage } from "./types"
1415
type IActivity = any // TODO
1516
type IWorkerPool = any // TODO
1617

18+
export interface IWebpackWatchingPauseResume extends webpack.Watching {
19+
suspend: () => void
20+
resume: () => void
21+
}
22+
23+
let devssrWebpackCompiler: webpack.Compiler
24+
let devssrWebpackWatcher: IWebpackWatchingPauseResume
25+
let needToRecompileSSRBundle = true
26+
export const getDevSSRWebpack = (): Record<
27+
IWebpackWatchingPauseResume,
28+
webpack.Compiler,
29+
needToRecompileSSRBundle
30+
> => {
31+
if (process.env.gatsby_executing_command !== `develop`) {
32+
throw new Error(`This function can only be called in development`)
33+
}
34+
35+
return {
36+
devssrWebpackWatcher,
37+
devssrWebpackCompiler,
38+
needToRecompileSSRBundle,
39+
}
40+
}
41+
1742
let oldHash = ``
1843
let newHash = ``
1944
const runWebpack = (
@@ -34,11 +59,19 @@ const runWebpack = (
3459
process.env.GATSBY_EXPERIMENTAL_DEV_SSR &&
3560
stage === `develop-html`
3661
) {
37-
webpack(compilerConfig).watch(
62+
devssrWebpackCompiler = webpack(compilerConfig)
63+
devssrWebpackCompiler.hooks.invalid.tap(`ssr file invalidation`, file => {
64+
needToRecompileSSRBundle = true
65+
})
66+
devssrWebpackWatcher = devssrWebpackCompiler.watch(
3867
{
3968
ignored: /node_modules/,
4069
},
4170
(err, stats) => {
71+
needToRecompileSSRBundle = false
72+
emitter.emit(`DEV_SSR_COMPILATION_DONE`)
73+
devssrWebpackWatcher.suspend()
74+
4275
if (err) {
4376
return reject(err)
4477
} else {

packages/gatsby/src/utils/dev-ssr/render-dev-html.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import report from "gatsby-cli/lib/reporter"
66
import { startListener } from "../../bootstrap/requires-writer"
77
import { findPageByPath } from "../find-page-by-path"
88
import { getPageData as getPageDataExperimental } from "../get-page-data"
9+
import { getDevSSRWebpack } from "../../commands/build-html"
10+
import { emitter } from "../../redux"
911

1012
const startWorker = (): any => {
1113
const newWorker = new JestWorker(require.resolve(`./render-dev-html-child`), {
@@ -144,6 +146,41 @@ export const renderDevHTML = ({
144146
return reject(`404 page`)
145147
}
146148

149+
// Resume the webpack watcher and wait for any compilation necessary to happen.
150+
// We timeout after 1.5s as the user might not care per se about SSR.
151+
//
152+
// We pause and resume so there's no excess webpack activity during normal development.
153+
const {
154+
devssrWebpackCompiler,
155+
devssrWebpackWatcher,
156+
needToRecompileSSRBundle,
157+
} = getDevSSRWebpack()
158+
if (
159+
devssrWebpackWatcher &&
160+
devssrWebpackCompiler &&
161+
needToRecompileSSRBundle
162+
) {
163+
let isResolved = false
164+
await new Promise(resolve => {
165+
function finish(stats: Stats): void {
166+
emitter.off(`DEV_SSR_COMPILATION_DONE`, finish)
167+
if (!isResolved) {
168+
resolve(stats)
169+
}
170+
}
171+
emitter.on(`DEV_SSR_COMPILATION_DONE`, finish)
172+
devssrWebpackWatcher.resume()
173+
// Suspending is just a flag, so it's safe to re-suspend right away
174+
devssrWebpackWatcher.suspend()
175+
176+
// Timeout after 1.5s.
177+
setTimeout(() => {
178+
isResolved = true
179+
resolve()
180+
}, 1500)
181+
})
182+
}
183+
147184
// Wait for public/render-page.js to update w/ the page component.
148185
const found = await ensurePathComponentInSSRBundle(pageObj, directory)
149186

0 commit comments

Comments
 (0)