Skip to content

Commit

Permalink
feature(gatsby): Pause dev-ssr watching between page loads to avoid s…
Browse files Browse the repository at this point in the history
…lowing 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 <[email protected]>

* fix typo

* Don't resume if nothing has changed

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

Co-authored-by: Michal Piechowiak <[email protected]>

* Didn't need this

Co-authored-by: Michal Piechowiak <[email protected]>
  • Loading branch information
KyleAMathews and pieh authored Dec 21, 2020
1 parent 76a3b57 commit 8ff6245
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
4 changes: 3 additions & 1 deletion integration-tests/ssr/__tests__/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ describe(`SSR`, () => {

expect(html).toMatchSnapshot()
})

test(`dev & build outputs match`, async () => {
const childProcess = await execa(`yarn`, [`test-output`])

expect(childProcess.code).toEqual(0)
})
}, 15000)

test(`it generates an error page correctly`, async () => {
const src = path.join(__dirname, `/fixtures/bad-page.js`)
const dest = path.join(__dirname, `../src/pages/bad-page.js`)
Expand Down
9 changes: 9 additions & 0 deletions integration-tests/ssr/test-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
)
)

// Fetch once to trigger re-compilation.
await fetch(`${devSiteBasePath}/${path}`)

// Then wait for 6 seconds to ensure it's ready to go.
// Otherwise, tests are flaky depending on the speed of the testing machine.
await new Promise(resolve => {
setTimeout(() => resolve(), 6000)
})

let devStatus = 200
const rawDevHtml = await fetch(`${devSiteBasePath}/${path}`).then(res => {
devStatus = res.status
Expand Down
35 changes: 34 additions & 1 deletion packages/gatsby/src/commands/build-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import telemetry from "gatsby-telemetry"
import { chunk } from "lodash"
import webpack from "webpack"

import { emitter } from "../redux"
import webpackConfig from "../utils/webpack.config"
import { structureWebpackErrors } from "../utils/webpack-error-utils"

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

export interface IWebpackWatchingPauseResume extends webpack.Watching {
suspend: () => void
resume: () => void
}

let devssrWebpackCompiler: webpack.Compiler
let devssrWebpackWatcher: IWebpackWatchingPauseResume
let needToRecompileSSRBundle = true
export const getDevSSRWebpack = (): Record<
IWebpackWatchingPauseResume,
webpack.Compiler,
needToRecompileSSRBundle
> => {
if (process.env.gatsby_executing_command !== `develop`) {
throw new Error(`This function can only be called in development`)
}

return {
devssrWebpackWatcher,
devssrWebpackCompiler,
needToRecompileSSRBundle,
}
}

let oldHash = ``
let newHash = ``
const runWebpack = (
Expand All @@ -34,11 +59,19 @@ const runWebpack = (
process.env.GATSBY_EXPERIMENTAL_DEV_SSR &&
stage === `develop-html`
) {
webpack(compilerConfig).watch(
devssrWebpackCompiler = webpack(compilerConfig)
devssrWebpackCompiler.hooks.invalid.tap(`ssr file invalidation`, file => {
needToRecompileSSRBundle = true
})
devssrWebpackWatcher = devssrWebpackCompiler.watch(
{
ignored: /node_modules/,
},
(err, stats) => {
needToRecompileSSRBundle = false
emitter.emit(`DEV_SSR_COMPILATION_DONE`)
devssrWebpackWatcher.suspend()

if (err) {
return reject(err)
} else {
Expand Down
37 changes: 37 additions & 0 deletions packages/gatsby/src/utils/dev-ssr/render-dev-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import report from "gatsby-cli/lib/reporter"
import { startListener } from "../../bootstrap/requires-writer"
import { findPageByPath } from "../find-page-by-path"
import { getPageData as getPageDataExperimental } from "../get-page-data"
import { getDevSSRWebpack } from "../../commands/build-html"
import { emitter } from "../../redux"

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

// Resume the webpack watcher and wait for any compilation necessary to happen.
// We timeout after 1.5s as the user might not care per se about SSR.
//
// We pause and resume so there's no excess webpack activity during normal development.
const {
devssrWebpackCompiler,
devssrWebpackWatcher,
needToRecompileSSRBundle,
} = getDevSSRWebpack()
if (
devssrWebpackWatcher &&
devssrWebpackCompiler &&
needToRecompileSSRBundle
) {
let isResolved = false
await new Promise(resolve => {
function finish(stats: Stats): void {
emitter.off(`DEV_SSR_COMPILATION_DONE`, finish)
if (!isResolved) {
resolve(stats)
}
}
emitter.on(`DEV_SSR_COMPILATION_DONE`, finish)
devssrWebpackWatcher.resume()
// Suspending is just a flag, so it's safe to re-suspend right away
devssrWebpackWatcher.suspend()

// Timeout after 1.5s.
setTimeout(() => {
isResolved = true
resolve()
}, 1500)
})
}

// Wait for public/render-page.js to update w/ the page component.
const found = await ensurePathComponentInSSRBundle(pageObj, directory)

Expand Down

0 comments on commit 8ff6245

Please sign in to comment.