|
1 | 1 | import * as path from "path"
|
| 2 | +import fs from "fs-extra" |
2 | 3 | import Template from "webpack/lib/Template"
|
3 | 4 | import ModuleDependency from "webpack/lib/dependencies/ModuleDependency"
|
4 | 5 | import NullDependency from "webpack/lib/dependencies/NullDependency"
|
5 | 6 | import { createNormalizedModuleKey } from "../utils/create-normalized-module-key"
|
6 | 7 | import webpack, { Module, NormalModule, Dependency, javascript } from "webpack"
|
| 8 | +import type Reporter from "gatsby-cli/lib/reporter" |
7 | 9 |
|
8 | 10 | interface IModuleExport {
|
9 | 11 | id: string
|
@@ -33,14 +35,17 @@ class ClientReferenceDependency extends ModuleDependency {
|
33 | 35 | */
|
34 | 36 | export class PartialHydrationPlugin {
|
35 | 37 | name = `PartialHydrationPlugin`
|
36 |
| - _manifestPath: string |
37 |
| - _rootFilePath: string |
| 38 | + |
| 39 | + _manifestPath: string // Absolute path to where the manifest file should be written |
| 40 | + _reporter: typeof Reporter |
| 41 | + |
38 | 42 | _references: Array<ClientReferenceDependency> = []
|
39 | 43 | _clientModules = new Set<webpack.NormalModule>()
|
| 44 | + _previousManifest = {} |
40 | 45 |
|
41 |
| - constructor(manifestPath: string, rootFilePath: string) { |
| 46 | + constructor(manifestPath: string, reporter: typeof Reporter) { |
42 | 47 | this._manifestPath = manifestPath
|
43 |
| - this._rootFilePath = rootFilePath |
| 48 | + this._reporter = reporter |
44 | 49 | }
|
45 | 50 |
|
46 | 51 | _generateClientReferenceChunk(
|
@@ -188,6 +193,27 @@ export class PartialHydrationPlugin {
|
188 | 193 | }
|
189 | 194 |
|
190 | 195 | apply(compiler: webpack.Compiler): void {
|
| 196 | + // Restore manifest from the previous compilation, otherwise it will be wiped since files aren't visited on cached builds |
| 197 | + compiler.hooks.beforeCompile.tap(this.name, () => { |
| 198 | + try { |
| 199 | + const previousManifest = fs.existsSync(this._manifestPath) |
| 200 | + |
| 201 | + if (!previousManifest) { |
| 202 | + return |
| 203 | + } |
| 204 | + |
| 205 | + this._previousManifest = JSON.parse( |
| 206 | + fs.readFileSync(this._manifestPath, `utf-8`) |
| 207 | + ) |
| 208 | + } catch (error) { |
| 209 | + this._reporter.panic({ |
| 210 | + id: `80001`, |
| 211 | + context: {}, |
| 212 | + error, |
| 213 | + }) |
| 214 | + } |
| 215 | + }) |
| 216 | + |
191 | 217 | compiler.hooks.thisCompilation.tap(
|
192 | 218 | this.name,
|
193 | 219 | (compilation, { normalModuleFactory }) => {
|
@@ -298,10 +324,23 @@ export class PartialHydrationPlugin {
|
298 | 324 | compilation.options.context as string
|
299 | 325 | )
|
300 | 326 |
|
| 327 | + /** |
| 328 | + * `emitAsset` is unclear about what the path should be relative to and absolute paths don't work. This works so we'll go with that. |
| 329 | + * @see {@link https://webpack.js.org/api/compilation-object/#emitasset} |
| 330 | + */ |
| 331 | + const emitManifestPath = `..${this._manifestPath.replace( |
| 332 | + compiler.context, |
| 333 | + `` |
| 334 | + )}` |
| 335 | + |
301 | 336 | compilation.emitAsset(
|
302 |
| - this._manifestPath, |
| 337 | + emitManifestPath, |
303 | 338 | new webpack.sources.RawSource(
|
304 |
| - JSON.stringify(manifest, null, 2), |
| 339 | + JSON.stringify( |
| 340 | + { ...this._previousManifest, ...manifest }, |
| 341 | + null, |
| 342 | + 2 |
| 343 | + ), |
305 | 344 | false
|
306 | 345 | )
|
307 | 346 | )
|
|
0 commit comments