Skip to content

Commit

Permalink
Handle webpack in state machine
Browse files Browse the repository at this point in the history
  • Loading branch information
ascorbic committed Jul 17, 2020
1 parent 3f758f5 commit e967dbe
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 13 deletions.
4 changes: 1 addition & 3 deletions packages/gatsby/src/commands/develop-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ const openDebuggerPort = (debugInfo: IDebugInfo): void => {
}

module.exports = async (program: IDevelopArgs): Promise<void> => {
if (program.verbose) {
reporter.setVerbose(true)
}
reporter.setVerbose(program.verbose)

if (program.debugInfo) {
openDebuggerPort(program.debugInfo)
Expand Down
3 changes: 3 additions & 0 deletions packages/gatsby/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { runPageQueries } from "./run-page-queries"

import { waitUntilAllJobsComplete } from "../utils/wait-until-jobs-complete"
import { runMutationBatch } from "./run-mutation-batch"
import { recompile } from "./recompile"

export * from "./types"

Expand All @@ -40,6 +41,7 @@ export {
startWebpackServer,
rebuildSchemaWithSitePage,
runMutationBatch,
recompile,
}

export const buildServices: Record<string, ServiceConfig<IBuildContext>> = {
Expand All @@ -59,4 +61,5 @@ export const buildServices: Record<string, ServiceConfig<IBuildContext>> = {
writeOutRedirects,
startWebpackServer,
rebuildSchemaWithSitePage,
recompile,
}
6 changes: 0 additions & 6 deletions packages/gatsby/src/services/listen-for-mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ export const listenForMutations: InvokeCallback = (callback: Sender<any>) => {
callback({ type: `ADD_NODE_MUTATION`, payload: event })
}

const emitFileChange = (event: unknown): void => {
callback({ type: `SOURCE_FILE_CHANGED`, payload: event })
}

const emitQueryChange = (event: unknown): void => {
callback({ type: `QUERY_FILE_CHANGED`, payload: event })
}
Expand All @@ -20,12 +16,10 @@ export const listenForMutations: InvokeCallback = (callback: Sender<any>) => {

emitter.on(`ENQUEUE_NODE_MUTATION`, emitMutation)
emitter.on(`WEBHOOK_RECEIVED`, emitWebhook)
emitter.on(`SOURCE_FILE_CHANGED`, emitFileChange)
emitter.on(`QUERY_FILE_CHANGED`, emitQueryChange)

return function unsubscribeFromMutationListening(): void {
emitter.off(`ENQUEUE_NODE_MUTATION`, emitMutation)
emitter.off(`SOURCE_FILE_CHANGED`, emitFileChange)
emitter.off(`WEBHOOK_RECEIVED`, emitWebhook)
emitter.off(`QUERY_FILE_CHANGED`, emitQueryChange)
}
Expand Down
12 changes: 12 additions & 0 deletions packages/gatsby/src/services/listen-to-webpack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Compiler } from "webpack"
import { InvokeCallback } from "xstate"
import reporter from "gatsby-cli/lib/reporter"

export const createWebpackWatcher = (compiler: Compiler): InvokeCallback => (
callback
): void => {
compiler.hooks.invalid.tap(`file invalidation`, file => {
reporter.verbose(`Webpack file changed: ${file}`)
callback({ type: `SOURCE_FILE_CHANGED`, file })
})
}
28 changes: 28 additions & 0 deletions packages/gatsby/src/services/recompile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable no-unused-expressions */
import { IBuildContext } from "./types"
import { Stats } from "webpack"
import reporter from "gatsby-cli/lib/reporter"
import { emitter } from "../redux"

export async function recompile({
webpackWatching,
}: IBuildContext): Promise<Stats> {
if (!webpackWatching) {
reporter.panic(`Missing compiler`)
}
// Promisify the event-based API. We do this using emitter
// because you can't "untap" a webpack watcher, and we just want
// one compilation.

return new Promise(resolve => {
function finish(stats: Stats): void {
emitter.off(`COMPILATION_DONE`, finish)
resolve(stats)
}
emitter.on(`COMPILATION_DONE`, finish)
webpackWatching.resume()
// We can imemdiately suspend, because it doesn't affect
// compilations in-progress
webpackWatching.suspend()
})
}
3 changes: 3 additions & 0 deletions packages/gatsby/src/services/start-webpack-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from "../utils/webpack-status"
import { enqueueFlush } from "../utils/page-data"
import mapTemplatesToStaticQueryHashes from "../utils/map-templates-to-static-query-hashes"
import { emitter } from "../redux"

export async function startWebpackServer({
program,
Expand Down Expand Up @@ -160,6 +161,8 @@ export async function startWebpackServer({

markWebpackStatusAsDone()
done()
webpackWatching.suspend()
emitter.emit(`COMPILATION_DONE`, stats)
resolve({ compiler, websocketManager, webpackWatching })
})
})
Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby/src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@ export interface IBuildContext {
compiler?: Compiler
websocketManager?: WebsocketManager
webpackWatching?: IWebpackWatchingPauseResume
webpackListener?: Actor<unknown, AnyEventObject>
queryFilesDirty?: boolean
sourceFilesDirty?: boolean
}
21 changes: 21 additions & 0 deletions packages/gatsby/src/state-machines/develop/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { assertStore } from "../../utils/assert-store"
import { saveState } from "../../db"
import reporter from "gatsby-cli/lib/reporter"
import { ProgramStatus } from "../../redux/types"
import { createWebpackWatcher } from "../../services/listen-to-webpack"

/**
* These are the deferred redux actions sent from api-runner-node
Expand Down Expand Up @@ -79,6 +80,14 @@ export const markQueryFilesDirty = assign<IBuildContext>({
queryFilesDirty: true,
})

export const markSourceFilesDirty = assign<IBuildContext>({
sourceFilesDirty: true,
})

export const markSourceFilesClean = assign<IBuildContext>({
sourceFilesDirty: false,
})

export const assignServiceResult = assign<IBuildContext, DoneEventObject>(
(_context, { data }): DataLayerResult => data
)
Expand All @@ -98,6 +107,15 @@ export const assignServers = assign<IBuildContext, AnyEventObject>(
}
)

export const spawnWebpackListener = assign<IBuildContext, AnyEventObject>({
webpackListener: ({ compiler }) => {
if (!compiler) {
return undefined
}
return spawn(createWebpackWatcher(compiler))
},
})

export const assignWebhookBody = assign<IBuildContext, AnyEventObject>({
webhookBody: (_context, { payload }) => payload?.webhookBody,
})
Expand Down Expand Up @@ -135,6 +153,9 @@ export const buildActions: ActionFunctionMap<IBuildContext, AnyEventObject> = {
assignWebhookBody,
clearWebhookBody,
finishParentSpan,
spawnWebpackListener,
markSourceFilesDirty,
markSourceFilesClean,
saveDbState,
setQueryRunningFinished,
}
27 changes: 25 additions & 2 deletions packages/gatsby/src/state-machines/develop/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const developConfig: MachineConfig<IBuildContext, any, AnyEventObject> = {
QUERY_FILE_CHANGED: {
actions: `markQueryFilesDirty`,
},
// Sent when webpack sees a changed file
SOURCE_FILE_CHANGED: {
actions: `markSourceFilesDirty`,
},
// These are calls to the refresh endpoint. Also used by Gatsby Preview.
// Saves the webhook body from the event into context, then reloads data
WEBHOOK_RECEIVED: {
Expand Down Expand Up @@ -118,26 +122,45 @@ const developConfig: MachineConfig<IBuildContext, any, AnyEventObject> = {
actions: `setQueryRunningFinished`,
cond: ({ compiler }: IBuildContext): boolean => !compiler,
},
{
// If source files have changed, then recompile the JS bundle
target: `recompiling`,
cond: ({ sourceFilesDirty }: IBuildContext): boolean =>
!!sourceFilesDirty,
},
{
// ...otherwise just wait.
target: `waiting`,
},
],
},
},
// Recompile the JS bundle
recompiling: {
invoke: {
src: `recompile`,
onDone: {
actions: `markSourceFilesClean`,
target: `waiting`,
},
},
},
// Spin up webpack and socket.io
startingDevServers: {
invoke: {
src: `startWebpackServer`,
onDone: {
target: `waiting`,
actions: `assignServers`,
actions: [
`assignServers`,
`spawnWebpackListener`,
`markSourceFilesClean`,
],
},
},
},
// Idle, waiting for events that make us rebuild
waiting: {
// We may want to save this is more places, but this should do for now
entry: `saveDbState`,
on: {
// Forward these events to the child machine, so it can handle batching
Expand Down
10 changes: 8 additions & 2 deletions packages/gatsby/src/state-machines/develop/services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { IBuildContext, startWebpackServer, initialize } from "../../services"
import {
IBuildContext,
startWebpackServer,
initialize,
recompile,
} from "../../services"
import {
initializeDataMachine,
reloadDataMachine,
Expand All @@ -15,5 +20,6 @@ export const developServices: Record<string, ServiceConfig<IBuildContext>> = {
initialize: initialize,
runQueries: queryRunningMachine,
waitForMutations: waitingMachine,
startWebpackServer: startWebpackServer,
startWebpackServer,
recompile,
}

0 comments on commit e967dbe

Please sign in to comment.