mirror of https://github.com/webpack/webpack.git
fix: HMR failure in defer module (#19759)
This commit is contained in:
parent
e8e9f15b82
commit
07a9d20a4c
|
@ -18,6 +18,8 @@ const NullDependency = require("./NullDependency");
|
|||
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
|
||||
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
|
||||
/** @typedef {import("./HarmonyAcceptImportDependency")} HarmonyAcceptImportDependency */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../Module").ModuleId} ModuleId */
|
||||
|
||||
class HarmonyAcceptDependency extends NullDependency {
|
||||
/**
|
||||
|
@ -84,7 +86,57 @@ HarmonyAcceptDependency.Template = class HarmonyAcceptDependencyTemplate extends
|
|||
chunkGraph
|
||||
} = templateContext;
|
||||
|
||||
/** @type {HarmonyAcceptImportDependency[]} */
|
||||
/**
|
||||
* @param {Dependency} dependency the dependency to get module id for
|
||||
* @returns {ModuleId | null} the module id or null if not found
|
||||
*/
|
||||
const getDependencyModuleId = (dependency) =>
|
||||
chunkGraph.getModuleId(
|
||||
/** @type {Module} */ (moduleGraph.getModule(dependency))
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {Dependency} a the first dependency
|
||||
* @param {Dependency} b the second dependency
|
||||
* @returns {boolean} true if the dependencies are related
|
||||
*/
|
||||
const isRelatedHarmonyImportDependency = (a, b) =>
|
||||
a !== b &&
|
||||
b instanceof HarmonyImportDependency &&
|
||||
getDependencyModuleId(a) === getDependencyModuleId(b);
|
||||
|
||||
/**
|
||||
* HarmonyAcceptImportDependency lacks a lot of information, such as the defer property.
|
||||
* One HarmonyAcceptImportDependency may need to generate multiple ImportStatements.
|
||||
* Therefore, we find its original HarmonyImportDependency for code generation.
|
||||
* @param {HarmonyAcceptImportDependency} dependency the dependency to get harmony import dependencies for
|
||||
* @returns {HarmonyImportDependency[]} array of related harmony import dependencies
|
||||
*/
|
||||
const getHarmonyImportDependencies = (dependency) => {
|
||||
const result = [];
|
||||
let deferDependency = null;
|
||||
let noDeferredDependency = null;
|
||||
|
||||
for (const d of module.dependencies) {
|
||||
if (deferDependency && noDeferredDependency) break;
|
||||
if (isRelatedHarmonyImportDependency(dependency, d)) {
|
||||
if (d.defer) {
|
||||
deferDependency = /** @type {HarmonyImportDependency} */ (d);
|
||||
} else {
|
||||
noDeferredDependency = /** @type {HarmonyImportDependency} */ (d);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deferDependency) result.push(deferDependency);
|
||||
if (noDeferredDependency) result.push(noDeferredDependency);
|
||||
if (result.length === 0) {
|
||||
// fallback to the original dependency
|
||||
result.push(dependency);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/** @type {HarmonyImportDependency[]} */
|
||||
const syncDeps = [];
|
||||
|
||||
/** @type {HarmonyAcceptImportDependency[]} */
|
||||
|
@ -96,7 +148,7 @@ HarmonyAcceptDependency.Template = class HarmonyAcceptDependencyTemplate extends
|
|||
if (connection && moduleGraph.isAsync(connection.module)) {
|
||||
asyncDeps.push(dependency);
|
||||
} else {
|
||||
syncDeps.push(dependency);
|
||||
syncDeps.push(...getHarmonyImportDependencies(dependency));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const a = "1";
|
||||
---
|
||||
export const a = "2";
|
|
@ -0,0 +1,14 @@
|
|||
import * as a /* webpackDefer: true */ from "./a.js";
|
||||
import * as a2 from "./a.js";
|
||||
|
||||
it("should handle defer import", (done) => {
|
||||
expect(a.a).toBe("1");
|
||||
expect(a2.a).toBe("1");
|
||||
|
||||
module.hot.accept("./a", function() {
|
||||
expect(a.a).toBe("2");
|
||||
expect(a2.a).toBe("2");
|
||||
done();
|
||||
});
|
||||
NEXT(require("../../update.js")(done));
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: [`async-node${process.versions.node.split(".").map(Number)[0]}`],
|
||||
entry: "./index.js",
|
||||
experiments: {
|
||||
deferImport: true
|
||||
},
|
||||
optimization: {
|
||||
concatenateModules: false
|
||||
}
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
export const a = "1";
|
||||
---
|
||||
export const a = "2";
|
|
@ -0,0 +1,11 @@
|
|||
import * as a /* webpackDefer: true */ from "./a.js";
|
||||
|
||||
it("should handle defer import", (done) => {
|
||||
expect(a.a).toBe("1");
|
||||
|
||||
module.hot.accept("./a", function() {
|
||||
expect(a.a).toBe("2");
|
||||
done();
|
||||
});
|
||||
NEXT(require("../../update")(done));
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
target: [`async-node${process.versions.node.split(".").map(Number)[0]}`],
|
||||
entry: "./index.js",
|
||||
experiments: {
|
||||
deferImport: true
|
||||
},
|
||||
optimization: {
|
||||
concatenateModules: false
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue