mirror of https://github.com/webpack/webpack.git
fix egde case where a HMR chunk is incorrectly downloaded when loading a unchanged chunk during HMR downloading
This commit is contained in:
parent
86a8bd9618
commit
e1179bf9bb
|
@ -28,7 +28,8 @@ module.exports = function () {
|
||||||
var currentStatus = "idle";
|
var currentStatus = "idle";
|
||||||
|
|
||||||
// while downloading
|
// while downloading
|
||||||
var blockingPromises;
|
var blockingPromises = 0;
|
||||||
|
var blockingPromisesWaiting = [];
|
||||||
|
|
||||||
// The update info
|
// The update info
|
||||||
var currentUpdateApplyHandlers;
|
var currentUpdateApplyHandlers;
|
||||||
|
@ -218,17 +219,28 @@ module.exports = function () {
|
||||||
return Promise.all(results);
|
return Promise.all(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function unblock() {
|
||||||
|
if (--blockingPromises === 0) {
|
||||||
|
setStatus("ready").then(function () {
|
||||||
|
if (blockingPromises === 0) {
|
||||||
|
var list = blockingPromisesWaiting;
|
||||||
|
blockingPromisesWaiting = [];
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
list[i]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function trackBlockingPromise(promise) {
|
function trackBlockingPromise(promise) {
|
||||||
switch (currentStatus) {
|
switch (currentStatus) {
|
||||||
case "ready":
|
case "ready":
|
||||||
setStatus("prepare");
|
setStatus("prepare");
|
||||||
blockingPromises.push(promise);
|
/* fallthrough */
|
||||||
waitForBlockingPromises(function () {
|
|
||||||
return setStatus("ready");
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
case "prepare":
|
case "prepare":
|
||||||
blockingPromises.push(promise);
|
blockingPromises++;
|
||||||
|
promise.then(unblock, unblock);
|
||||||
return promise;
|
return promise;
|
||||||
default:
|
default:
|
||||||
return promise;
|
return promise;
|
||||||
|
@ -236,11 +248,11 @@ module.exports = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForBlockingPromises(fn) {
|
function waitForBlockingPromises(fn) {
|
||||||
if (blockingPromises.length === 0) return fn();
|
if (blockingPromises === 0) return fn();
|
||||||
var blocker = blockingPromises;
|
return new Promise(function (resolve) {
|
||||||
blockingPromises = [];
|
blockingPromisesWaiting.push(function () {
|
||||||
return Promise.all(blocker).then(function () {
|
resolve(fn());
|
||||||
return waitForBlockingPromises(fn);
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +273,6 @@ module.exports = function () {
|
||||||
|
|
||||||
return setStatus("prepare").then(function () {
|
return setStatus("prepare").then(function () {
|
||||||
var updatedModules = [];
|
var updatedModules = [];
|
||||||
blockingPromises = [];
|
|
||||||
currentUpdateApplyHandlers = [];
|
currentUpdateApplyHandlers = [];
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
|
@ -298,7 +309,11 @@ module.exports = function () {
|
||||||
function hotApply(options) {
|
function hotApply(options) {
|
||||||
if (currentStatus !== "ready") {
|
if (currentStatus !== "ready") {
|
||||||
return Promise.resolve().then(function () {
|
return Promise.resolve().then(function () {
|
||||||
throw new Error("apply() is only allowed in ready status");
|
throw new Error(
|
||||||
|
"apply() is only allowed in ready status (state: " +
|
||||||
|
currentStatus +
|
||||||
|
")"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return internalApply(options);
|
return internalApply(options);
|
||||||
|
|
|
@ -443,15 +443,16 @@ module.exports = function () {
|
||||||
) {
|
) {
|
||||||
promises.push($loadUpdateChunk$(chunkId, updatedModulesList));
|
promises.push($loadUpdateChunk$(chunkId, updatedModulesList));
|
||||||
currentUpdateChunks[chunkId] = true;
|
currentUpdateChunks[chunkId] = true;
|
||||||
|
} else {
|
||||||
|
currentUpdateChunks[chunkId] = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if ($ensureChunkHandlers$) {
|
if ($ensureChunkHandlers$) {
|
||||||
$ensureChunkHandlers$.$key$Hmr = function (chunkId, promises) {
|
$ensureChunkHandlers$.$key$Hmr = function (chunkId, promises) {
|
||||||
if (
|
if (
|
||||||
currentUpdateChunks &&
|
currentUpdateChunks &&
|
||||||
!$hasOwnProperty$(currentUpdateChunks, chunkId) &&
|
$hasOwnProperty$(currentUpdateChunks, chunkId) &&
|
||||||
$hasOwnProperty$($installedChunks$, chunkId) &&
|
!currentUpdateChunks[chunkId]
|
||||||
$installedChunks$[chunkId] !== undefined
|
|
||||||
) {
|
) {
|
||||||
promises.push($loadUpdateChunk$(chunkId));
|
promises.push($loadUpdateChunk$(chunkId));
|
||||||
currentUpdateChunks[chunkId] = true;
|
currentUpdateChunks[chunkId] = true;
|
||||||
|
|
|
@ -286,8 +286,9 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
||||||
? Template.asString([
|
? Template.asString([
|
||||||
"var currentUpdatedModulesList;",
|
"var currentUpdatedModulesList;",
|
||||||
"var waitingUpdateResolves = {};",
|
"var waitingUpdateResolves = {};",
|
||||||
"function loadUpdateChunk(chunkId) {",
|
"function loadUpdateChunk(chunkId, updatedModulesList) {",
|
||||||
Template.indent([
|
Template.indent([
|
||||||
|
"currentUpdatedModulesList = updatedModulesList;",
|
||||||
`return new Promise(${runtimeTemplate.basicFunction(
|
`return new Promise(${runtimeTemplate.basicFunction(
|
||||||
"resolve, reject",
|
"resolve, reject",
|
||||||
[
|
[
|
||||||
|
|
|
@ -5,22 +5,27 @@ module.hot.accept("./file");
|
||||||
const asyncNext = () => {
|
const asyncNext = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
NEXT((err, stats) => {
|
NEXT((err, stats) => {
|
||||||
if(err) return reject(err);
|
if (err) return reject(err);
|
||||||
resolve(stats);
|
resolve(stats);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
it("should download the missing update chunk on import", () => {
|
it("should download the missing update chunk on import", () => {
|
||||||
expect(value).toBe(1);
|
expect(value).toBe(1);
|
||||||
return asyncNext().then(() => {
|
return asyncNext().then(() => {
|
||||||
return module.hot.check().then(() => {
|
return module.hot.check().then(() => {
|
||||||
return import("./chunk").then(chunk => {
|
return Promise.all([
|
||||||
|
import("./chunk"),
|
||||||
|
import("./unaffected-chunk")
|
||||||
|
]).then(([chunk, unaffectedChunk]) => {
|
||||||
expect(value).toBe(1);
|
expect(value).toBe(1);
|
||||||
expect(chunk.default).toBe(10);
|
expect(chunk.default).toBe(10);
|
||||||
|
expect(unaffectedChunk.default).toBe(10);
|
||||||
return module.hot.apply().then(() => {
|
return module.hot.apply().then(() => {
|
||||||
expect(value).toBe(2);
|
expect(value).toBe(2);
|
||||||
expect(chunk.default).toBe(20);
|
expect(chunk.default).toBe(20);
|
||||||
|
expect(unaffectedChunk.default).toBe(10);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import value from "./unaffected-inner";
|
||||||
|
|
||||||
|
module.hot.accept("./unaffected-inner");
|
||||||
|
|
||||||
|
export { value as default };
|
|
@ -0,0 +1 @@
|
||||||
|
export default 10;
|
Loading…
Reference in New Issue