Refactor HMR for runtime modules
fixed a few HMR bugs allow other module types for HMR made HMR more flexible
This commit is contained in:
parent
fa0ec849bd
commit
9d91861592
|
@ -234,20 +234,19 @@ interface RuleSetConditionsAbsoluteRecursive
|
|||
* @todo Once this issue is resolved, remove these globals and add JSDoc onsite instead
|
||||
* https://github.com/Microsoft/TypeScript/issues/15626
|
||||
*/
|
||||
declare const $hash$;
|
||||
declare const $requestTimeout$;
|
||||
declare const $createFakeNamespaceObject$;
|
||||
declare const $moduleCache$;
|
||||
declare let $getFullHash$;
|
||||
declare const $interceptModuleExecution$;
|
||||
declare const $hmrDownloadManifest$;
|
||||
declare let $hmrDownloadUpdateHandlers$;
|
||||
declare let $hmrModuleData$;
|
||||
declare const $options$;
|
||||
declare const $updateModuleFactories$;
|
||||
declare const $updateRuntimeModules$;
|
||||
declare const $moduleFactories$;
|
||||
declare const $onError$;
|
||||
declare const $publicPath$;
|
||||
declare const installedModules;
|
||||
declare const __webpack_require__;
|
||||
declare const hotDownloadManifest;
|
||||
declare const hotDownloadUpdateChunk;
|
||||
declare const hotDisposeChunk;
|
||||
declare const modules;
|
||||
declare const installedChunks;
|
||||
declare const hotAddUpdateChunk;
|
||||
declare const parentHotUpdateCallback;
|
||||
declare const $hotChunkFilename$;
|
||||
declare const $hotMainFilename$;
|
||||
declare const WebAssembly;
|
||||
|
|
|
@ -1385,6 +1385,10 @@ export interface StatsOptions {
|
|||
* add information about the reasons why modules are included
|
||||
*/
|
||||
reasons?: boolean;
|
||||
/**
|
||||
* add information about runtime modules
|
||||
*/
|
||||
runtime?: boolean;
|
||||
/**
|
||||
* add the source code of modules
|
||||
*/
|
||||
|
|
|
@ -10,7 +10,10 @@ const SortableSet = require("./util/SortableSet");
|
|||
const {
|
||||
compareModulesById,
|
||||
compareIterables,
|
||||
compareModulesByIdentifier
|
||||
compareModulesByIdentifier,
|
||||
concatComparators,
|
||||
compareSelect,
|
||||
compareIds
|
||||
} = require("./util/comparators");
|
||||
|
||||
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
|
||||
|
@ -219,6 +222,18 @@ class ChunkGraph {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {Iterable<RuntimeModule>} modules the runtime modules
|
||||
* @returns {void}
|
||||
*/
|
||||
attachRuntimeModules(chunk, modules) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
for (const module of modules) {
|
||||
cgc.runtimeModules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} oldModule the replaced module
|
||||
* @param {Module} newModule the replacing module
|
||||
|
@ -760,6 +775,22 @@ class ChunkGraph {
|
|||
return cgc.runtimeModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {RuntimeModule[]} array of modules in order of execution
|
||||
*/
|
||||
getChunkRuntimeModulesInOrder(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
const array = Array.from(cgc.runtimeModules);
|
||||
array.sort(
|
||||
concatComparators(
|
||||
compareSelect(r => r.stage, compareIds),
|
||||
compareSelect(r => this.getModuleId(r), compareIds)
|
||||
)
|
||||
);
|
||||
return array;
|
||||
}
|
||||
|
||||
/** @typedef {[Module, ChunkGroup | undefined]} EntryModuleWithChunkGroup */
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,6 @@ const {
|
|||
connectChunkGroupAndChunk,
|
||||
connectChunkGroupParentAndChild
|
||||
} = require("./GraphHelpers");
|
||||
const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
|
||||
const MainTemplate = require("./MainTemplate");
|
||||
const ModuleDependencyError = require("./ModuleDependencyError");
|
||||
const ModuleDependencyWarning = require("./ModuleDependencyWarning");
|
||||
|
@ -435,9 +434,6 @@ class Compilation {
|
|||
|
||||
this.mainTemplate = new MainTemplate(this.outputOptions);
|
||||
this.chunkTemplate = new ChunkTemplate(this.outputOptions);
|
||||
this.hotUpdateChunkTemplate = new HotUpdateChunkTemplate(
|
||||
this.outputOptions
|
||||
);
|
||||
this.runtimeTemplate = new RuntimeTemplate(
|
||||
this.outputOptions,
|
||||
this.requestShortener
|
||||
|
@ -1157,8 +1153,9 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
}
|
||||
const entryChunkGroups = /** @type {Entrypoint[]} */ (this.chunkGroups.slice());
|
||||
this.processDependenciesBlocksForChunkGroups(entryChunkGroups);
|
||||
this.processDependenciesBlocksForChunkGroups(
|
||||
/** @type {Entrypoint[]} */ (this.chunkGroups.slice())
|
||||
);
|
||||
this.hooks.afterChunks.call(this.chunks);
|
||||
|
||||
this.hooks.optimize.call();
|
||||
|
@ -1211,7 +1208,7 @@ class Compilation {
|
|||
this.hooks.afterModuleHash.call();
|
||||
|
||||
this.hooks.beforeRuntimeRequirements.call();
|
||||
this.processRuntimeRequirements(entryChunkGroups);
|
||||
this.processRuntimeRequirements(this.entrypoints.values());
|
||||
this.hooks.afterRuntimeRequirements.call();
|
||||
|
||||
this.hooks.beforeHash.call();
|
||||
|
@ -1308,7 +1305,7 @@ class Compilation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Entrypoint[]} entrypoints the entrypoints
|
||||
* @param {Iterable<Entrypoint>} entrypoints the entrypoints
|
||||
* @returns {void}
|
||||
*/
|
||||
processRuntimeRequirements(entrypoints) {
|
||||
|
@ -2462,6 +2459,7 @@ class Compilation {
|
|||
const usedIds = new Set();
|
||||
|
||||
for (const module of this.modules) {
|
||||
if (module.type === "runtime") continue;
|
||||
const moduleId = chunkGraph.getModuleId(module);
|
||||
if (moduleId === null) continue;
|
||||
if (usedIds.has(moduleId)) {
|
||||
|
|
|
@ -1,651 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*global $hash$ $requestTimeout$ installedModules __webpack_require__ hotDownloadManifest hotDownloadUpdateChunk hotDisposeChunk modules $createFakeNamespaceObject$ */
|
||||
|
||||
module.exports = function() {
|
||||
var hotApplyOnUpdate = true;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
var hotCurrentHash = $hash$;
|
||||
var hotRequestTimeout = $requestTimeout$;
|
||||
var hotCurrentModuleData = {};
|
||||
var hotCurrentChildModule;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
var hotCurrentParents = [];
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
var hotCurrentParentsTemp = [];
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotCreateRequire(moduleId) {
|
||||
var me = installedModules[moduleId];
|
||||
if (!me) return __webpack_require__;
|
||||
var fn = function(request) {
|
||||
if (me.hot.active) {
|
||||
if (installedModules[request]) {
|
||||
if (installedModules[request].parents.indexOf(moduleId) === -1) {
|
||||
installedModules[request].parents.push(moduleId);
|
||||
}
|
||||
} else {
|
||||
hotCurrentParents = [moduleId];
|
||||
hotCurrentChildModule = request;
|
||||
}
|
||||
if (me.children.indexOf(request) === -1) {
|
||||
me.children.push(request);
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
"[HMR] unexpected require(" +
|
||||
request +
|
||||
") from disposed module " +
|
||||
moduleId
|
||||
);
|
||||
hotCurrentParents = [];
|
||||
}
|
||||
return __webpack_require__(request);
|
||||
};
|
||||
var ObjectFactory = function ObjectFactory(name) {
|
||||
return {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return __webpack_require__[name];
|
||||
},
|
||||
set: function(value) {
|
||||
__webpack_require__[name] = value;
|
||||
}
|
||||
};
|
||||
};
|
||||
for (var name in __webpack_require__) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(__webpack_require__, name) &&
|
||||
name !== "e" &&
|
||||
name !== "t"
|
||||
) {
|
||||
Object.defineProperty(fn, name, ObjectFactory(name));
|
||||
}
|
||||
}
|
||||
fn.e = function(chunkId) {
|
||||
if (hotStatus === "ready") hotSetStatus("prepare");
|
||||
hotChunksLoading++;
|
||||
return __webpack_require__
|
||||
.e(chunkId)
|
||||
.then(finishChunkLoading, function(err) {
|
||||
finishChunkLoading();
|
||||
throw err;
|
||||
});
|
||||
|
||||
function finishChunkLoading() {
|
||||
hotChunksLoading--;
|
||||
if (hotStatus === "prepare") {
|
||||
if (!hotWaitingFilesMap[chunkId]) {
|
||||
hotEnsureUpdateChunk(chunkId);
|
||||
}
|
||||
if (hotChunksLoading === 0 && hotWaitingFiles === 0) {
|
||||
hotUpdateDownloaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
fn.t = function(value, mode) {
|
||||
if (mode & 1) value = fn(value);
|
||||
return $createFakeNamespaceObject$(value, mode & ~1);
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotCreateModule(moduleId) {
|
||||
var hot = {
|
||||
// private stuff
|
||||
_acceptedDependencies: {},
|
||||
_declinedDependencies: {},
|
||||
_selfAccepted: false,
|
||||
_selfDeclined: false,
|
||||
_disposeHandlers: [],
|
||||
_main: hotCurrentChildModule !== moduleId,
|
||||
|
||||
// Module API
|
||||
active: true,
|
||||
accept: function(dep, callback) {
|
||||
if (dep === undefined) hot._selfAccepted = true;
|
||||
else if (typeof dep === "function") hot._selfAccepted = dep;
|
||||
else if (typeof dep === "object" && dep !== null)
|
||||
for (var i = 0; i < dep.length; i++)
|
||||
hot._acceptedDependencies[dep[i]] = callback || function() {};
|
||||
else hot._acceptedDependencies[dep] = callback || function() {};
|
||||
},
|
||||
decline: function(dep) {
|
||||
if (dep === undefined) hot._selfDeclined = true;
|
||||
else if (typeof dep === "object" && dep !== null)
|
||||
for (var i = 0; i < dep.length; i++)
|
||||
hot._declinedDependencies[dep[i]] = true;
|
||||
else hot._declinedDependencies[dep] = true;
|
||||
},
|
||||
dispose: function(callback) {
|
||||
hot._disposeHandlers.push(callback);
|
||||
},
|
||||
addDisposeHandler: function(callback) {
|
||||
hot._disposeHandlers.push(callback);
|
||||
},
|
||||
removeDisposeHandler: function(callback) {
|
||||
var idx = hot._disposeHandlers.indexOf(callback);
|
||||
if (idx >= 0) hot._disposeHandlers.splice(idx, 1);
|
||||
},
|
||||
|
||||
// Management API
|
||||
check: hotCheck,
|
||||
apply: hotApply,
|
||||
status: function(l) {
|
||||
if (!l) return hotStatus;
|
||||
hotStatusHandlers.push(l);
|
||||
},
|
||||
addStatusHandler: function(l) {
|
||||
hotStatusHandlers.push(l);
|
||||
},
|
||||
removeStatusHandler: function(l) {
|
||||
var idx = hotStatusHandlers.indexOf(l);
|
||||
if (idx >= 0) hotStatusHandlers.splice(idx, 1);
|
||||
},
|
||||
|
||||
//inherit from previous dispose call
|
||||
data: hotCurrentModuleData[moduleId]
|
||||
};
|
||||
hotCurrentChildModule = undefined;
|
||||
return hot;
|
||||
}
|
||||
|
||||
var hotStatusHandlers = [];
|
||||
var hotStatus = "idle";
|
||||
|
||||
function hotSetStatus(newStatus) {
|
||||
hotStatus = newStatus;
|
||||
for (var i = 0; i < hotStatusHandlers.length; i++)
|
||||
hotStatusHandlers[i].call(null, newStatus);
|
||||
}
|
||||
|
||||
// while downloading
|
||||
var hotWaitingFiles = 0;
|
||||
var hotChunksLoading = 0;
|
||||
var hotWaitingFilesMap = {};
|
||||
var hotRequestedFilesMap = {};
|
||||
var hotAvailableFilesMap = {};
|
||||
var hotDeferred;
|
||||
|
||||
// The update info
|
||||
var hotUpdate, hotUpdateNewHash;
|
||||
|
||||
function toModuleId(id) {
|
||||
var isNumber = +id + "" === id;
|
||||
return isNumber ? +id : id;
|
||||
}
|
||||
|
||||
function hotCheck(apply) {
|
||||
if (hotStatus !== "idle") {
|
||||
throw new Error("check() is only allowed in idle status");
|
||||
}
|
||||
hotApplyOnUpdate = apply;
|
||||
hotSetStatus("check");
|
||||
return hotDownloadManifest(hotRequestTimeout).then(function(update) {
|
||||
if (!update) {
|
||||
hotSetStatus("idle");
|
||||
return null;
|
||||
}
|
||||
hotRequestedFilesMap = {};
|
||||
hotWaitingFilesMap = {};
|
||||
hotAvailableFilesMap = update.c;
|
||||
hotUpdateNewHash = update.h;
|
||||
|
||||
hotSetStatus("prepare");
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
hotDeferred = {
|
||||
resolve: resolve,
|
||||
reject: reject
|
||||
};
|
||||
});
|
||||
hotUpdate = {};
|
||||
/*foreachInstalledChunks*/
|
||||
// eslint-disable-next-line no-lone-blocks
|
||||
{
|
||||
/*globals chunkId */
|
||||
hotEnsureUpdateChunk(chunkId);
|
||||
}
|
||||
if (
|
||||
hotStatus === "prepare" &&
|
||||
hotChunksLoading === 0 &&
|
||||
hotWaitingFiles === 0
|
||||
) {
|
||||
hotUpdateDownloaded();
|
||||
}
|
||||
return promise;
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotAddUpdateChunk(chunkId, moreModules) {
|
||||
if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
|
||||
return;
|
||||
hotRequestedFilesMap[chunkId] = false;
|
||||
for (var moduleId in moreModules) {
|
||||
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
|
||||
hotUpdate[moduleId] = moreModules[moduleId];
|
||||
}
|
||||
}
|
||||
if (--hotWaitingFiles === 0 && hotChunksLoading === 0) {
|
||||
hotUpdateDownloaded();
|
||||
}
|
||||
}
|
||||
|
||||
function hotEnsureUpdateChunk(chunkId) {
|
||||
if (!hotAvailableFilesMap[chunkId]) {
|
||||
hotWaitingFilesMap[chunkId] = true;
|
||||
} else {
|
||||
hotRequestedFilesMap[chunkId] = true;
|
||||
hotWaitingFiles++;
|
||||
hotDownloadUpdateChunk(chunkId);
|
||||
}
|
||||
}
|
||||
|
||||
function hotUpdateDownloaded() {
|
||||
hotSetStatus("ready");
|
||||
var deferred = hotDeferred;
|
||||
hotDeferred = null;
|
||||
if (!deferred) return;
|
||||
if (hotApplyOnUpdate) {
|
||||
// Wrap deferred object in Promise to mark it as a well-handled Promise to
|
||||
// avoid triggering uncaught exception warning in Chrome.
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=465666
|
||||
Promise.resolve()
|
||||
.then(function() {
|
||||
return hotApply(hotApplyOnUpdate);
|
||||
})
|
||||
.then(
|
||||
function(result) {
|
||||
deferred.resolve(result);
|
||||
},
|
||||
function(err) {
|
||||
deferred.reject(err);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
var outdatedModules = [];
|
||||
for (var id in hotUpdate) {
|
||||
if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
|
||||
outdatedModules.push(toModuleId(id));
|
||||
}
|
||||
}
|
||||
deferred.resolve(outdatedModules);
|
||||
}
|
||||
}
|
||||
|
||||
function hotApply(options) {
|
||||
if (hotStatus !== "ready")
|
||||
throw new Error("apply() is only allowed in ready status");
|
||||
options = options || {};
|
||||
|
||||
var cb;
|
||||
var i;
|
||||
var j;
|
||||
var module;
|
||||
var moduleId;
|
||||
|
||||
function getAffectedStuff(updateModuleId) {
|
||||
var outdatedModules = [updateModuleId];
|
||||
var outdatedDependencies = {};
|
||||
|
||||
var queue = outdatedModules.slice().map(function(id) {
|
||||
return {
|
||||
chain: [id],
|
||||
id: id
|
||||
};
|
||||
});
|
||||
while (queue.length > 0) {
|
||||
var queueItem = queue.pop();
|
||||
var moduleId = queueItem.id;
|
||||
var chain = queueItem.chain;
|
||||
module = installedModules[moduleId];
|
||||
if (!module || module.hot._selfAccepted) continue;
|
||||
if (module.hot._selfDeclined) {
|
||||
return {
|
||||
type: "self-declined",
|
||||
chain: chain,
|
||||
moduleId: moduleId
|
||||
};
|
||||
}
|
||||
if (module.hot._main) {
|
||||
return {
|
||||
type: "unaccepted",
|
||||
chain: chain,
|
||||
moduleId: moduleId
|
||||
};
|
||||
}
|
||||
for (var i = 0; i < module.parents.length; i++) {
|
||||
var parentId = module.parents[i];
|
||||
var parent = installedModules[parentId];
|
||||
if (!parent) continue;
|
||||
if (parent.hot._declinedDependencies[moduleId]) {
|
||||
return {
|
||||
type: "declined",
|
||||
chain: chain.concat([parentId]),
|
||||
moduleId: moduleId,
|
||||
parentId: parentId
|
||||
};
|
||||
}
|
||||
if (outdatedModules.indexOf(parentId) !== -1) continue;
|
||||
if (parent.hot._acceptedDependencies[moduleId]) {
|
||||
if (!outdatedDependencies[parentId])
|
||||
outdatedDependencies[parentId] = [];
|
||||
addAllToSet(outdatedDependencies[parentId], [moduleId]);
|
||||
continue;
|
||||
}
|
||||
delete outdatedDependencies[parentId];
|
||||
outdatedModules.push(parentId);
|
||||
queue.push({
|
||||
chain: chain.concat([parentId]),
|
||||
id: parentId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: "accepted",
|
||||
moduleId: updateModuleId,
|
||||
outdatedModules: outdatedModules,
|
||||
outdatedDependencies: outdatedDependencies
|
||||
};
|
||||
}
|
||||
|
||||
function addAllToSet(a, b) {
|
||||
for (var i = 0; i < b.length; i++) {
|
||||
var item = b[i];
|
||||
if (a.indexOf(item) === -1) a.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// at begin all updates modules are outdated
|
||||
// the "outdated" status can propagate to parents if they don't accept the children
|
||||
var outdatedDependencies = {};
|
||||
var outdatedModules = [];
|
||||
var appliedUpdate = {};
|
||||
|
||||
var warnUnexpectedRequire = function warnUnexpectedRequire() {
|
||||
console.warn(
|
||||
"[HMR] unexpected require(" + result.moduleId + ") to disposed module"
|
||||
);
|
||||
};
|
||||
|
||||
for (var id in hotUpdate) {
|
||||
if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
|
||||
moduleId = toModuleId(id);
|
||||
/** @type {TODO} */
|
||||
var result;
|
||||
if (hotUpdate[id]) {
|
||||
result = getAffectedStuff(moduleId);
|
||||
} else {
|
||||
result = {
|
||||
type: "disposed",
|
||||
moduleId: id
|
||||
};
|
||||
}
|
||||
/** @type {Error|false} */
|
||||
var abortError = false;
|
||||
var doApply = false;
|
||||
var doDispose = false;
|
||||
var chainInfo = "";
|
||||
if (result.chain) {
|
||||
chainInfo = "\nUpdate propagation: " + result.chain.join(" -> ");
|
||||
}
|
||||
switch (result.type) {
|
||||
case "self-declined":
|
||||
if (options.onDeclined) options.onDeclined(result);
|
||||
if (!options.ignoreDeclined)
|
||||
abortError = new Error(
|
||||
"Aborted because of self decline: " +
|
||||
result.moduleId +
|
||||
chainInfo
|
||||
);
|
||||
break;
|
||||
case "declined":
|
||||
if (options.onDeclined) options.onDeclined(result);
|
||||
if (!options.ignoreDeclined)
|
||||
abortError = new Error(
|
||||
"Aborted because of declined dependency: " +
|
||||
result.moduleId +
|
||||
" in " +
|
||||
result.parentId +
|
||||
chainInfo
|
||||
);
|
||||
break;
|
||||
case "unaccepted":
|
||||
if (options.onUnaccepted) options.onUnaccepted(result);
|
||||
if (!options.ignoreUnaccepted)
|
||||
abortError = new Error(
|
||||
"Aborted because " + moduleId + " is not accepted" + chainInfo
|
||||
);
|
||||
break;
|
||||
case "accepted":
|
||||
if (options.onAccepted) options.onAccepted(result);
|
||||
doApply = true;
|
||||
break;
|
||||
case "disposed":
|
||||
if (options.onDisposed) options.onDisposed(result);
|
||||
doDispose = true;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexception type " + result.type);
|
||||
}
|
||||
if (abortError) {
|
||||
hotSetStatus("abort");
|
||||
return Promise.reject(abortError);
|
||||
}
|
||||
if (doApply) {
|
||||
appliedUpdate[moduleId] = hotUpdate[moduleId];
|
||||
addAllToSet(outdatedModules, result.outdatedModules);
|
||||
for (moduleId in result.outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
result.outdatedDependencies,
|
||||
moduleId
|
||||
)
|
||||
) {
|
||||
if (!outdatedDependencies[moduleId])
|
||||
outdatedDependencies[moduleId] = [];
|
||||
addAllToSet(
|
||||
outdatedDependencies[moduleId],
|
||||
result.outdatedDependencies[moduleId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doDispose) {
|
||||
addAllToSet(outdatedModules, [result.moduleId]);
|
||||
appliedUpdate[moduleId] = warnUnexpectedRequire;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store self accepted outdated modules to require them later by the module system
|
||||
var outdatedSelfAcceptedModules = [];
|
||||
for (i = 0; i < outdatedModules.length; i++) {
|
||||
moduleId = outdatedModules[i];
|
||||
if (
|
||||
installedModules[moduleId] &&
|
||||
installedModules[moduleId].hot._selfAccepted
|
||||
)
|
||||
outdatedSelfAcceptedModules.push({
|
||||
module: moduleId,
|
||||
errorHandler: installedModules[moduleId].hot._selfAccepted
|
||||
});
|
||||
}
|
||||
|
||||
// Now in "dispose" phase
|
||||
hotSetStatus("dispose");
|
||||
Object.keys(hotAvailableFilesMap).forEach(function(chunkId) {
|
||||
if (hotAvailableFilesMap[chunkId] === false) {
|
||||
hotDisposeChunk(chunkId);
|
||||
}
|
||||
});
|
||||
|
||||
var idx;
|
||||
var queue = outdatedModules.slice();
|
||||
while (queue.length > 0) {
|
||||
moduleId = queue.pop();
|
||||
module = installedModules[moduleId];
|
||||
if (!module) continue;
|
||||
|
||||
var data = {};
|
||||
|
||||
// Call dispose handlers
|
||||
var disposeHandlers = module.hot._disposeHandlers;
|
||||
for (j = 0; j < disposeHandlers.length; j++) {
|
||||
cb = disposeHandlers[j];
|
||||
cb(data);
|
||||
}
|
||||
hotCurrentModuleData[moduleId] = data;
|
||||
|
||||
// disable module (this disables requires from this module)
|
||||
module.hot.active = false;
|
||||
|
||||
// remove module from cache
|
||||
delete installedModules[moduleId];
|
||||
|
||||
// when disposing there is no need to call dispose handler
|
||||
delete outdatedDependencies[moduleId];
|
||||
|
||||
// remove "parents" references from all children
|
||||
for (j = 0; j < module.children.length; j++) {
|
||||
var child = installedModules[module.children[j]];
|
||||
if (!child) continue;
|
||||
idx = child.parents.indexOf(moduleId);
|
||||
if (idx >= 0) {
|
||||
child.parents.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove outdated dependency from module children
|
||||
var dependency;
|
||||
var moduleOutdatedDependencies;
|
||||
for (moduleId in outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
|
||||
) {
|
||||
module = installedModules[moduleId];
|
||||
if (module) {
|
||||
moduleOutdatedDependencies = outdatedDependencies[moduleId];
|
||||
for (j = 0; j < moduleOutdatedDependencies.length; j++) {
|
||||
dependency = moduleOutdatedDependencies[j];
|
||||
idx = module.children.indexOf(dependency);
|
||||
if (idx >= 0) module.children.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not in "apply" phase
|
||||
hotSetStatus("apply");
|
||||
|
||||
hotCurrentHash = hotUpdateNewHash;
|
||||
|
||||
// insert new code
|
||||
for (moduleId in appliedUpdate) {
|
||||
if (Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
|
||||
modules[moduleId] = appliedUpdate[moduleId];
|
||||
}
|
||||
}
|
||||
|
||||
// call accept handlers
|
||||
var error = null;
|
||||
for (moduleId in outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
|
||||
) {
|
||||
module = installedModules[moduleId];
|
||||
if (module) {
|
||||
moduleOutdatedDependencies = outdatedDependencies[moduleId];
|
||||
var callbacks = [];
|
||||
for (i = 0; i < moduleOutdatedDependencies.length; i++) {
|
||||
dependency = moduleOutdatedDependencies[i];
|
||||
cb = module.hot._acceptedDependencies[dependency];
|
||||
if (cb) {
|
||||
if (callbacks.indexOf(cb) !== -1) continue;
|
||||
callbacks.push(cb);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < callbacks.length; i++) {
|
||||
cb = callbacks[i];
|
||||
try {
|
||||
cb(moduleOutdatedDependencies);
|
||||
} catch (err) {
|
||||
if (options.onErrored) {
|
||||
options.onErrored({
|
||||
type: "accept-errored",
|
||||
moduleId: moduleId,
|
||||
dependencyId: moduleOutdatedDependencies[i],
|
||||
error: err
|
||||
});
|
||||
}
|
||||
if (!options.ignoreErrored) {
|
||||
if (!error) error = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load self accepted modules
|
||||
for (i = 0; i < outdatedSelfAcceptedModules.length; i++) {
|
||||
var item = outdatedSelfAcceptedModules[i];
|
||||
moduleId = item.module;
|
||||
hotCurrentParents = [moduleId];
|
||||
try {
|
||||
__webpack_require__(moduleId);
|
||||
} catch (err) {
|
||||
if (typeof item.errorHandler === "function") {
|
||||
try {
|
||||
item.errorHandler(err);
|
||||
} catch (err2) {
|
||||
if (options.onErrored) {
|
||||
options.onErrored({
|
||||
type: "self-accept-error-handler-errored",
|
||||
moduleId: moduleId,
|
||||
error: err2,
|
||||
originalError: err
|
||||
});
|
||||
}
|
||||
if (!options.ignoreErrored) {
|
||||
if (!error) error = err2;
|
||||
}
|
||||
if (!error) error = err;
|
||||
}
|
||||
} else {
|
||||
if (options.onErrored) {
|
||||
options.onErrored({
|
||||
type: "self-accept-errored",
|
||||
moduleId: moduleId,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
if (!options.ignoreErrored) {
|
||||
if (!error) error = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle errors in accept handlers and self accepted module load
|
||||
if (error) {
|
||||
hotSetStatus("fail");
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
hotSetStatus("idle");
|
||||
return new Promise(function(resolve) {
|
||||
resolve(outdatedModules);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -18,10 +18,10 @@ const MainTemplate = require("./MainTemplate");
|
|||
const NormalModule = require("./NormalModule");
|
||||
const NullFactory = require("./NullFactory");
|
||||
const RuntimeGlobals = require("./RuntimeGlobals");
|
||||
const Template = require("./Template");
|
||||
const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency");
|
||||
const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency");
|
||||
const ModuleHotDependency = require("./dependencies/ModuleHotDependency");
|
||||
const HotModuleReplacementRuntimeModule = require("./hmr/HotModuleReplacementRuntimeModule");
|
||||
const { find } = require("./util/SetHelpers");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
|
||||
|
@ -40,10 +40,6 @@ const { compareModulesById } = require("./util/comparators");
|
|||
* @property {SyncBailHook<TODO, string[]>} hotAcceptWithoutCallback
|
||||
*/
|
||||
|
||||
const hotInitCode = Template.getFunctionContent(
|
||||
require("./HotModuleReplacement.runtime")
|
||||
);
|
||||
|
||||
/** @type {WeakMap<MainTemplate, HMRMainTemplateHooks>} */
|
||||
const mainTemplateHooksMap = new WeakMap();
|
||||
|
||||
|
@ -96,7 +92,6 @@ class HotModuleReplacementPlugin {
|
|||
this.options = options || {};
|
||||
this.multiStep = this.options.multiStep;
|
||||
this.fullBuildTimeout = this.options.fullBuildTimeout || 200;
|
||||
this.requestTimeout = this.options.requestTimeout || 10000;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,9 +101,6 @@ class HotModuleReplacementPlugin {
|
|||
apply(compiler) {
|
||||
const multiStep = this.multiStep;
|
||||
const fullBuildTimeout = this.fullBuildTimeout;
|
||||
const requestTimeout = this.requestTimeout;
|
||||
const hotUpdateChunkFilename =
|
||||
compiler.options.output.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename;
|
||||
compiler.hooks.additionalPass.tapAsync(
|
||||
"HotModuleReplacementPlugin",
|
||||
|
@ -141,18 +133,12 @@ class HotModuleReplacementPlugin {
|
|||
before: "NodeStuffPlugin"
|
||||
},
|
||||
expr => {
|
||||
return evaluateToIdentifier(
|
||||
"module.hot",
|
||||
!!parser.state.compilation.hotUpdateChunkTemplate
|
||||
)(expr);
|
||||
return evaluateToIdentifier("module.hot", true)(expr);
|
||||
}
|
||||
);
|
||||
parser.hooks.call
|
||||
.for("module.hot.accept")
|
||||
.tap("HotModuleReplacementPlugin", expr => {
|
||||
if (!parser.state.compilation.hotUpdateChunkTemplate) {
|
||||
return false;
|
||||
}
|
||||
const dep = new ModuleHotDependency(expr.callee.range, "accept");
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
|
@ -190,9 +176,6 @@ class HotModuleReplacementPlugin {
|
|||
parser.hooks.call
|
||||
.for("module.hot.decline")
|
||||
.tap("HotModuleReplacementPlugin", expr => {
|
||||
if (!parser.state.compilation.hotUpdateChunkTemplate) {
|
||||
return false;
|
||||
}
|
||||
const dep = new ModuleHotDependency(expr.callee.range, "decline");
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addDependency(dep);
|
||||
|
@ -230,10 +213,6 @@ class HotModuleReplacementPlugin {
|
|||
compiler.hooks.compilation.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
(compilation, { normalModuleFactory }) => {
|
||||
const moduleGraph = compilation.moduleGraph;
|
||||
const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate;
|
||||
if (!hotUpdateChunkTemplate) return;
|
||||
|
||||
compilation.dependencyFactories.set(
|
||||
ModuleHotAcceptDependency,
|
||||
normalModuleFactory
|
||||
|
@ -326,6 +305,7 @@ class HotModuleReplacementPlugin {
|
|||
"HotModuleReplacementPlugin",
|
||||
() => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const chunkTemplate = compilation.chunkTemplate;
|
||||
const records = compilation.records;
|
||||
if (records.hash === compilation.hash) return;
|
||||
if (
|
||||
|
@ -345,8 +325,11 @@ class HotModuleReplacementPlugin {
|
|||
}
|
||||
const hotUpdateMainContent = {
|
||||
h: compilation.hash,
|
||||
c: {}
|
||||
c: [],
|
||||
r: [],
|
||||
m: undefined
|
||||
};
|
||||
const allRemovedModules = new Set();
|
||||
for (const key of Object.keys(records.chunkHashs)) {
|
||||
const chunkId = key;
|
||||
const currentChunk = find(
|
||||
|
@ -357,6 +340,9 @@ class HotModuleReplacementPlugin {
|
|||
const newModules = chunkGraph
|
||||
.getChunkModules(currentChunk)
|
||||
.filter(module => updatedModules.has(module));
|
||||
const newRuntimeModules = Array.from(
|
||||
chunkGraph.getChunkRuntimeModulesIterable(currentChunk)
|
||||
).filter(module => updatedModules.has(module));
|
||||
/** @type {Set<number|string>} */
|
||||
const allModules = new Set();
|
||||
for (const module of chunkGraph.getChunkModulesIterable(
|
||||
|
@ -371,32 +357,42 @@ class HotModuleReplacementPlugin {
|
|||
const hotUpdateChunk = new HotUpdateChunk();
|
||||
hotUpdateChunk.id = chunkId;
|
||||
chunkGraph.attachModules(hotUpdateChunk, newModules);
|
||||
hotUpdateChunk.removedModules = removedModules;
|
||||
const source = hotUpdateChunkTemplate.render(
|
||||
{
|
||||
chunk: hotUpdateChunk,
|
||||
dependencyTemplates: compilation.dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
},
|
||||
compilation.moduleTemplates.javascript,
|
||||
compilation.hash
|
||||
chunkGraph.attachRuntimeModules(
|
||||
hotUpdateChunk,
|
||||
newRuntimeModules
|
||||
);
|
||||
const filename = compilation.getPath(hotUpdateChunkFilename, {
|
||||
hotUpdateChunk.removedModules = removedModules;
|
||||
const renderManifest = chunkTemplate.getRenderManifest({
|
||||
chunk: hotUpdateChunk,
|
||||
hash: records.hash,
|
||||
chunk: currentChunk
|
||||
fullHash: records.hash,
|
||||
outputOptions: chunkTemplate.outputOptions,
|
||||
moduleTemplates: compilation.moduleTemplates,
|
||||
dependencyTemplates: compilation.dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph
|
||||
});
|
||||
compilation.additionalChunkAssets.push(filename);
|
||||
compilation.assets[filename] = source;
|
||||
hotUpdateMainContent.c[chunkId] = true;
|
||||
currentChunk.files.push(filename);
|
||||
compilation.hooks.chunkAsset.call(currentChunk, filename);
|
||||
for (const entry of renderManifest) {
|
||||
const filename = compilation.getPath(
|
||||
entry.filenameTemplate,
|
||||
entry.pathOptions
|
||||
);
|
||||
const source = entry.render();
|
||||
compilation.additionalChunkAssets.push(filename);
|
||||
compilation.assets[filename] = source;
|
||||
currentChunk.files.push(filename);
|
||||
compilation.hooks.chunkAsset.call(currentChunk, filename);
|
||||
}
|
||||
hotUpdateMainContent.c.push(chunkId);
|
||||
}
|
||||
} else {
|
||||
hotUpdateMainContent.c[chunkId] = false;
|
||||
hotUpdateMainContent.r.push(chunkId);
|
||||
for (const id of records.chunkModuleIds[chunkId])
|
||||
allRemovedModules.add(id);
|
||||
}
|
||||
}
|
||||
hotUpdateMainContent.m = Array.from(allRemovedModules);
|
||||
const source = new RawSource(JSON.stringify(hotUpdateMainContent));
|
||||
const filename = compilation.getPath(hotUpdateMainFilename, {
|
||||
hash: records.hash
|
||||
|
@ -405,78 +401,18 @@ class HotModuleReplacementPlugin {
|
|||
}
|
||||
);
|
||||
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
const {
|
||||
hotBootstrap
|
||||
} = HotModuleReplacementPlugin.getMainTemplateHooks(mainTemplate);
|
||||
|
||||
mainTemplate.hooks.hash.tap("HotModuleReplacementPlugin", hash => {
|
||||
hash.update("HotMainTemplateDecorator");
|
||||
});
|
||||
|
||||
mainTemplate.hooks.moduleRequire.tap(
|
||||
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
(_, chunk, hash, varModuleId) => {
|
||||
return `hotCreateRequire(${varModuleId})`;
|
||||
}
|
||||
);
|
||||
|
||||
mainTemplate.hooks.requireExtensions.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
source => {
|
||||
const buf = [source];
|
||||
buf.push("");
|
||||
buf.push("// __webpack_hash__");
|
||||
buf.push(
|
||||
`${
|
||||
RuntimeGlobals.getFullHash
|
||||
} = function() { return hotCurrentHash; };`
|
||||
(chunk, runtimeRequirements) => {
|
||||
runtimeRequirements.add(RuntimeGlobals.hmrDownloadManifest);
|
||||
runtimeRequirements.add(RuntimeGlobals.hmrDownloadUpdateHandlers);
|
||||
runtimeRequirements.add(RuntimeGlobals.getFullHash);
|
||||
runtimeRequirements.add(RuntimeGlobals.interceptModuleExecution);
|
||||
runtimeRequirements.add(RuntimeGlobals.moduleCache);
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new HotModuleReplacementRuntimeModule()
|
||||
);
|
||||
return Template.asString(buf);
|
||||
}
|
||||
);
|
||||
|
||||
const needChunkLoadingCode = chunk => {
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
if (chunkGroup.chunks.length > 1) return true;
|
||||
if (chunkGroup.getNumberOfChildren() > 0) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
mainTemplate.hooks.bootstrap.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
(source, { chunk, hash }) => {
|
||||
const hotSource = hotBootstrap.call(source, chunk, hash);
|
||||
return Template.asString([
|
||||
hotSource,
|
||||
"",
|
||||
hotInitCode
|
||||
.replace(/\$hash\$/g, JSON.stringify(hash))
|
||||
.replace(/\$requestTimeout\$/g, requestTimeout)
|
||||
.replace(
|
||||
/\$createFakeNamespaceObject\$/g,
|
||||
RuntimeGlobals.createFakeNamespaceObject
|
||||
)
|
||||
.replace(
|
||||
/\/\*foreachInstalledChunks\*\//g,
|
||||
needChunkLoadingCode(chunk)
|
||||
? "for(var chunkId in installedChunks)"
|
||||
: `var chunkId = ${JSON.stringify(chunk.id)};`
|
||||
)
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
mainTemplate.hooks.moduleObj.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
(source, varModuleId) => {
|
||||
return Template.asString([
|
||||
`${source},`,
|
||||
`hot: hotCreateModule(${varModuleId}),`,
|
||||
"parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),",
|
||||
"children: []"
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
const Chunk = require("./Chunk");
|
||||
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class HotUpdateChunk extends Chunk {
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -14,6 +17,11 @@ class HotUpdateChunk extends Chunk {
|
|||
this.removedModules = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash hash (will be modified)
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash, chunkGraph) {
|
||||
super.updateHash(hash, chunkGraph);
|
||||
hash.update(JSON.stringify(this.removedModules));
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const { SyncBailHook } = require("tapable");
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
const Compilation = require("./Compilation");
|
||||
const HotUpdateChunk = require("./HotUpdateChunk");
|
||||
const JavascriptGenerator = require("./JavascriptGenerator");
|
||||
const JavascriptParser = require("./JavascriptParser");
|
||||
const Template = require("./Template");
|
||||
|
@ -147,12 +148,16 @@ class JavascriptModulesPlugin {
|
|||
"JavascriptModulesPlugin",
|
||||
(result, options) => {
|
||||
const chunk = options.chunk;
|
||||
const hotUpdateChunk =
|
||||
chunk instanceof HotUpdateChunk ? chunk : null;
|
||||
const outputOptions = options.outputOptions;
|
||||
const moduleTemplates = options.moduleTemplates;
|
||||
const dependencyTemplates = options.dependencyTemplates;
|
||||
|
||||
let filenameTemplate;
|
||||
if (chunk.filenameTemplate) {
|
||||
if (hotUpdateChunk) {
|
||||
filenameTemplate = outputOptions.hotUpdateChunkFilename;
|
||||
} else if (chunk.filenameTemplate) {
|
||||
filenameTemplate = chunk.filenameTemplate;
|
||||
} else if (chunk.isOnlyInitial()) {
|
||||
filenameTemplate = outputOptions.filename;
|
||||
|
@ -176,6 +181,7 @@ class JavascriptModulesPlugin {
|
|||
),
|
||||
filenameTemplate,
|
||||
pathOptions: {
|
||||
hash: options.hash,
|
||||
chunk,
|
||||
contentHashType: "javascript"
|
||||
},
|
||||
|
@ -198,6 +204,7 @@ class JavascriptModulesPlugin {
|
|||
hashFunction
|
||||
}
|
||||
} = compilation;
|
||||
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
||||
const hash = createHash(hashFunction);
|
||||
if (hashSalt) hash.update(hashSalt);
|
||||
const template = chunk.hasRuntime()
|
||||
|
@ -218,6 +225,9 @@ class JavascriptModulesPlugin {
|
|||
hash.update(chunkGraph.getModuleHash(m));
|
||||
}
|
||||
}
|
||||
if (hotUpdateChunk) {
|
||||
hash.update(JSON.stringify(hotUpdateChunk.removedModules));
|
||||
}
|
||||
chunk.contentHash.javascript = hash
|
||||
.digest(hashDigest)
|
||||
.substr(0, hashDigestLength);
|
||||
|
|
|
@ -72,12 +72,6 @@ module.exports = class MainTemplate {
|
|||
"moduleTemplate",
|
||||
"renderContext"
|
||||
]),
|
||||
/** @type {SyncWaterfallHook<string, string, RenderBootstrapContext>} */
|
||||
moduleObj: new SyncWaterfallHook([
|
||||
"source",
|
||||
"moduleIdExpression",
|
||||
"renderContext"
|
||||
]),
|
||||
/** @type {SyncWaterfallHook<string, RenderBootstrapContext>} */
|
||||
bootstrap: new SyncWaterfallHook(["source", "renderContext"]),
|
||||
/** @type {SyncWaterfallHook<string, Chunk, string>} */
|
||||
|
@ -107,12 +101,6 @@ module.exports = class MainTemplate {
|
|||
"hash",
|
||||
"moduleIdExpression"
|
||||
]),
|
||||
/** @type {SyncWaterfallHook<string, {moduleId: string, module: string}, RenderBootstrapContext>} */
|
||||
addModule: new SyncWaterfallHook([
|
||||
"source",
|
||||
"expressions",
|
||||
"renderContext"
|
||||
]),
|
||||
/** @type {SyncWaterfallHook<string, object>} */
|
||||
assetPath: new SyncWaterfallHook(["path", "options"]),
|
||||
/** @type {SyncHook<Hash>} */
|
||||
|
@ -123,11 +111,10 @@ module.exports = class MainTemplate {
|
|||
this.hooks.startup.tap(
|
||||
"MainTemplate",
|
||||
(source, { chunk, hash, chunkGraph }) => {
|
||||
if (
|
||||
chunkGraph
|
||||
.getTreeRuntimeRequirements(chunk)
|
||||
.has(RuntimeGlobals.startup)
|
||||
) {
|
||||
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(
|
||||
chunk
|
||||
);
|
||||
if (runtimeRequirements.has(RuntimeGlobals.startup)) {
|
||||
return Template.asString([
|
||||
"// run modules when ready",
|
||||
`return ${RuntimeGlobals.startup}();`
|
||||
|
@ -152,13 +139,7 @@ module.exports = class MainTemplate {
|
|||
RuntimeGlobals.entryModuleId
|
||||
} = ${moduleIdExpr}`;
|
||||
}
|
||||
buf.push(
|
||||
`${mayReturn}${this.renderRequireFunctionForModule(
|
||||
hash,
|
||||
chunk,
|
||||
JSON.stringify(moduleId)
|
||||
)}(${moduleIdExpr});`
|
||||
);
|
||||
buf.push(`${mayReturn}__webpack_require__(${moduleIdExpr});`);
|
||||
}
|
||||
return Template.asString(buf);
|
||||
}
|
||||
|
@ -195,7 +176,22 @@ module.exports = class MainTemplate {
|
|||
]);
|
||||
});
|
||||
this.hooks.require.tap("MainTemplate", (source, renderContext) => {
|
||||
const { chunk, hash } = renderContext;
|
||||
const { chunk, chunkGraph } = renderContext;
|
||||
const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
|
||||
const moduleExecution = runtimeRequirements.has(
|
||||
RuntimeGlobals.interceptModuleExecution
|
||||
)
|
||||
? Template.asString([
|
||||
"const execOptions = { id: moduleId, module: module, factory: modules[moduleId], require: __webpack_require__ };",
|
||||
`${
|
||||
RuntimeGlobals.interceptModuleExecution
|
||||
}.forEach(function(handler) { handler(execOptions); });`,
|
||||
"module = execOptions.module;",
|
||||
"execOptions.factory.call(module.exports, module, module.exports, execOptions.require);"
|
||||
])
|
||||
: Template.asString([
|
||||
"modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);"
|
||||
]);
|
||||
return Template.asString([
|
||||
source,
|
||||
"// Check if module is in cache",
|
||||
|
@ -204,40 +200,23 @@ module.exports = class MainTemplate {
|
|||
"}",
|
||||
"// Create a new module (and put it into the cache)",
|
||||
"var module = installedModules[moduleId] = {",
|
||||
Template.indent(
|
||||
this.hooks.moduleObj.call("", "moduleId", renderContext)
|
||||
),
|
||||
Template.indent(["i: moduleId,", "l: false,", "exports: {}"]),
|
||||
"};",
|
||||
"",
|
||||
Template.asString(
|
||||
outputOptions.strictModuleExceptionHandling
|
||||
? [
|
||||
"// Execute the module function",
|
||||
"var threw = true;",
|
||||
"try {",
|
||||
Template.indent([
|
||||
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(
|
||||
hash,
|
||||
chunk,
|
||||
"moduleId"
|
||||
)});`,
|
||||
"threw = false;"
|
||||
]),
|
||||
"} finally {",
|
||||
Template.indent([
|
||||
"if(threw) delete installedModules[moduleId];"
|
||||
]),
|
||||
"}"
|
||||
]
|
||||
: [
|
||||
"// Execute the module function",
|
||||
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(
|
||||
hash,
|
||||
chunk,
|
||||
"moduleId"
|
||||
)});`
|
||||
]
|
||||
),
|
||||
outputOptions.strictModuleExceptionHandling
|
||||
? Template.asString([
|
||||
"// Execute the module function",
|
||||
"var threw = true;",
|
||||
"try {",
|
||||
Template.indent([moduleExecution, "threw = false;"]),
|
||||
"} finally {",
|
||||
Template.indent(["if(threw) delete installedModules[moduleId];"]),
|
||||
"}"
|
||||
])
|
||||
: Template.asString([
|
||||
"// Execute the module function",
|
||||
moduleExecution
|
||||
]),
|
||||
"",
|
||||
"// Flag the module as loaded",
|
||||
"module.l = true;",
|
||||
|
@ -246,9 +225,6 @@ module.exports = class MainTemplate {
|
|||
"return module.exports;"
|
||||
]);
|
||||
});
|
||||
this.hooks.moduleObj.tap("MainTemplate", () => {
|
||||
return Template.asString(["i: moduleId,", "l: false,", "exports: {}"]);
|
||||
});
|
||||
this.hooks.requireExtensions.tap(
|
||||
"MainTemplate",
|
||||
(source, renderContext) => {
|
||||
|
@ -271,6 +247,12 @@ module.exports = class MainTemplate {
|
|||
buf.push(`${RuntimeGlobals.moduleCache} = installedModules;`);
|
||||
}
|
||||
|
||||
if (runtimeRequirements.has(RuntimeGlobals.interceptModuleExecution)) {
|
||||
buf.push("");
|
||||
buf.push("// expose the module execution interceptor");
|
||||
buf.push(`${RuntimeGlobals.interceptModuleExecution} = [];`);
|
||||
}
|
||||
|
||||
return Template.asString(buf);
|
||||
}
|
||||
);
|
||||
|
@ -346,40 +328,6 @@ module.exports = class MainTemplate {
|
|||
return new ConcatSource(source, ";");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} hash hash for render fn
|
||||
* @param {Chunk} chunk Chunk instance for require
|
||||
* @param {(number|string)=} varModuleId module id
|
||||
* @returns {TODO} the moduleRequire hook call return signature
|
||||
*/
|
||||
renderRequireFunctionForModule(hash, chunk, varModuleId) {
|
||||
return this.hooks.moduleRequire.call(
|
||||
"__webpack_require__",
|
||||
chunk,
|
||||
hash,
|
||||
varModuleId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} varModuleId module id
|
||||
* @param {string} varModule Module instance
|
||||
* @param {RenderBootstrapContext} renderContext the render context
|
||||
* @returns {TODO} renderAddModule call
|
||||
*/
|
||||
renderAddModule(varModuleId, varModule, renderContext) {
|
||||
return this.hooks.addModule.call(
|
||||
`modules[${varModuleId}] = ${varModule};`,
|
||||
{
|
||||
moduleId: varModuleId,
|
||||
module: varModule
|
||||
},
|
||||
renderContext
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} options get public path options
|
||||
|
|
|
@ -100,7 +100,37 @@ exports.chunkName = "__webpack_require__.cn";
|
|||
*/
|
||||
exports.getChunkScriptFilename = "__webpack_require__.u";
|
||||
|
||||
/**
|
||||
* the filename of the script part of the hot update chunk
|
||||
*/
|
||||
exports.getChunkUpdateScriptFilename = "__webpack_require__.hu";
|
||||
|
||||
/**
|
||||
* startup signal from runtime
|
||||
*/
|
||||
exports.startup = "__webpack_require__.x";
|
||||
|
||||
/**
|
||||
* startup signal from runtime
|
||||
*/
|
||||
exports.interceptModuleExecution = "__webpack_require__.i";
|
||||
|
||||
/**
|
||||
* the filename of the HMR manifest
|
||||
*/
|
||||
exports.getUpdateManifestFilename = "__webpack_require__.hmrF";
|
||||
|
||||
/**
|
||||
* function downloading the update manifest
|
||||
*/
|
||||
exports.hmrDownloadManifest = "__webpack_require__.hmrM";
|
||||
|
||||
/**
|
||||
* array with handler functions to download chunk updates
|
||||
*/
|
||||
exports.hmrDownloadUpdateHandlers = "__webpack_require__.hmrC";
|
||||
|
||||
/**
|
||||
* object with all hmr module data for all modules
|
||||
*/
|
||||
exports.hmrModuleData = "__webpack_require__.hmrD";
|
||||
|
|
|
@ -12,13 +12,9 @@ const CreateFakeNamespaceObjectRuntimeModule = require("./runtime/CreateFakeName
|
|||
const DefinePropertyGetterRuntimeModule = require("./runtime/DefinePropertyGetterRuntimeModule");
|
||||
const EnsureChunkRuntimeModule = require("./runtime/EnsureChunkRuntimeModule");
|
||||
const GetChunkFilenameRuntimeModule = require("./runtime/GetChunkFilenameRuntimeModule");
|
||||
const GetMainFilenameRuntimeModule = require("./runtime/GetMainFilenameRuntimeModule");
|
||||
const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
|
||||
const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
|
||||
const {
|
||||
concatComparators,
|
||||
compareSelect,
|
||||
compareIds
|
||||
} = require("./util/comparators");
|
||||
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
|
@ -119,12 +115,56 @@ class RuntimePlugin {
|
|||
compilation,
|
||||
chunk,
|
||||
"javascript",
|
||||
"javascript",
|
||||
RuntimeGlobals.getChunkScriptFilename,
|
||||
compilation.outputOptions.chunkFilename
|
||||
)
|
||||
);
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.getChunkUpdateScriptFilename)
|
||||
.tap("RuntimePlugin", (chunk, set) => {
|
||||
if (
|
||||
/\[hash(:\d+)?\]/.test(
|
||||
compilation.outputOptions.hotUpdateChunkFilename
|
||||
)
|
||||
)
|
||||
set.add(RuntimeGlobals.getFullHash);
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new GetChunkFilenameRuntimeModule(
|
||||
compilation,
|
||||
chunk,
|
||||
"javascript",
|
||||
"javascript update",
|
||||
RuntimeGlobals.getChunkUpdateScriptFilename,
|
||||
compilation.outputOptions.hotUpdateChunkFilename
|
||||
)
|
||||
);
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.getUpdateManifestFilename)
|
||||
.tap("RuntimePlugin", (chunk, set) => {
|
||||
if (
|
||||
/\[hash(:\d+)?\]/.test(
|
||||
compilation.outputOptions.hotUpdateMainFilename
|
||||
)
|
||||
)
|
||||
set.add(RuntimeGlobals.getFullHash);
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new GetMainFilenameRuntimeModule(
|
||||
compilation,
|
||||
chunk,
|
||||
"update manifest",
|
||||
RuntimeGlobals.getUpdateManifestFilename,
|
||||
compilation.outputOptions.hotUpdateMainFilename
|
||||
)
|
||||
);
|
||||
return true;
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunk)
|
||||
.tap("RuntimePlugin", (chunk, set) => {
|
||||
|
@ -142,17 +182,11 @@ class RuntimePlugin {
|
|||
"RuntimePlugin",
|
||||
(source, { chunk, chunkGraph }) => {
|
||||
const buf = [];
|
||||
const runtimeModules = Array.from(
|
||||
chunkGraph.getChunkRuntimeModulesIterable(chunk)
|
||||
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(
|
||||
chunk
|
||||
);
|
||||
if (runtimeModules.length > 0) {
|
||||
buf.push("// Bootstrap all runtime modules");
|
||||
runtimeModules.sort(
|
||||
concatComparators(
|
||||
compareSelect(r => r.stage, compareIds),
|
||||
compareSelect(r => chunkGraph.getModuleId(r), compareIds)
|
||||
)
|
||||
);
|
||||
for (const module of runtimeModules) {
|
||||
buf.push(
|
||||
`// ${module.name}\nmodules[${JSON.stringify(
|
||||
|
|
|
@ -396,7 +396,7 @@ class RuntimeTemplate {
|
|||
} else {
|
||||
getModuleFunction = `${
|
||||
RuntimeGlobals.createFakeNamespaceObject
|
||||
}.bind(null, ${comment}${idExpr}, 3)`;
|
||||
}.bind(__webpack_require__, ${comment}${idExpr}, 3)`;
|
||||
}
|
||||
} else if (strict) {
|
||||
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
|
||||
|
@ -407,7 +407,7 @@ class RuntimeTemplate {
|
|||
} else {
|
||||
getModuleFunction = `${
|
||||
RuntimeGlobals.createFakeNamespaceObject
|
||||
}.bind(null, ${comment}${idExpr}, 1)`;
|
||||
}.bind(__webpack_require__, ${comment}${idExpr}, 1)`;
|
||||
}
|
||||
} else {
|
||||
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
|
||||
|
@ -418,7 +418,7 @@ class RuntimeTemplate {
|
|||
} else {
|
||||
getModuleFunction = `${
|
||||
RuntimeGlobals.createFakeNamespaceObject
|
||||
}.bind(null, ${comment}${idExpr}, 7)`;
|
||||
}.bind(__webpack_require__, ${comment}${idExpr}, 7)`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,10 @@ class Stats {
|
|||
);
|
||||
const showDepth = optionOrLocalFallback(options.depth, !forToString);
|
||||
const showCachedModules = optionOrLocalFallback(options.cached, true);
|
||||
const showRuntimeModules = optionOrLocalFallback(
|
||||
options.runtime,
|
||||
!forToString
|
||||
);
|
||||
const showCachedAssets = optionOrLocalFallback(options.cachedAssets, true);
|
||||
const showReasons = optionOrLocalFallback(options.reasons, !forToString);
|
||||
const showUsedExports = optionOrLocalFallback(
|
||||
|
@ -250,6 +254,10 @@ class Stats {
|
|||
);
|
||||
}
|
||||
|
||||
if (!showRuntimeModules) {
|
||||
excludeModules.push((ident, module) => module.type === "runtime");
|
||||
}
|
||||
|
||||
const createModuleFilter = type => {
|
||||
let i = 0;
|
||||
return module => {
|
||||
|
|
|
@ -266,12 +266,7 @@ class ProfilingPlugin {
|
|||
}
|
||||
|
||||
const interceptTemplateInstancesFrom = (compilation, tracer) => {
|
||||
const {
|
||||
mainTemplate,
|
||||
chunkTemplate,
|
||||
hotUpdateChunkTemplate,
|
||||
moduleTemplates
|
||||
} = compilation;
|
||||
const { mainTemplate, chunkTemplate, moduleTemplates } = compilation;
|
||||
|
||||
const { javascript, webassembly } = moduleTemplates;
|
||||
|
||||
|
@ -284,10 +279,6 @@ const interceptTemplateInstancesFrom = (compilation, tracer) => {
|
|||
instance: chunkTemplate,
|
||||
name: "ChunkTemplate"
|
||||
},
|
||||
{
|
||||
instance: hotUpdateChunkTemplate,
|
||||
name: "HotUpdateChunkTemplate"
|
||||
},
|
||||
{
|
||||
instance: javascript,
|
||||
name: "JavaScriptModuleTemplate"
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
/*global $getFullHash$:true, $interceptModuleExecution$, $moduleCache$, $hmrModuleData$:true, $hmrDownloadManifest$, $hmrDownloadUpdateHandlers$:true, __webpack_require__ */
|
||||
|
||||
module.exports = function() {
|
||||
var currentHash = $getFullHash$();
|
||||
var currentModuleData = {};
|
||||
var installedModules = $moduleCache$;
|
||||
|
||||
// module and require creation
|
||||
var currentChildModule;
|
||||
var currentParents = [];
|
||||
|
||||
// status
|
||||
var registeredStatusHandlers = [];
|
||||
var currentStatus = "idle";
|
||||
|
||||
// while downloading
|
||||
var blockingPromises;
|
||||
|
||||
// The update info
|
||||
var currentUpdateApplyHandlers;
|
||||
var currentUpdateNewHash;
|
||||
|
||||
$hmrModuleData$ = currentModuleData;
|
||||
|
||||
$getFullHash$ = function() {
|
||||
return currentHash;
|
||||
};
|
||||
|
||||
$interceptModuleExecution$.push(function(options) {
|
||||
var module = options.module;
|
||||
var require = createRequire(options.require, options.id);
|
||||
module.hot = createModuleHotObject(options.id, module);
|
||||
module.parents = currentParents;
|
||||
module.children = [];
|
||||
currentParents = [];
|
||||
options.require = require;
|
||||
});
|
||||
|
||||
$hmrDownloadUpdateHandlers$ = {};
|
||||
|
||||
function createRequire(require, moduleId) {
|
||||
var me = installedModules[moduleId];
|
||||
if (!me) return require;
|
||||
var fn = function(request) {
|
||||
if (me.hot.active) {
|
||||
if (installedModules[request]) {
|
||||
var parents = installedModules[request].parents;
|
||||
if (parents.indexOf(moduleId) === -1) {
|
||||
parents.push(moduleId);
|
||||
}
|
||||
} else {
|
||||
currentParents = [moduleId];
|
||||
currentChildModule = request;
|
||||
}
|
||||
if (me.children.indexOf(request) === -1) {
|
||||
me.children.push(request);
|
||||
}
|
||||
} else {
|
||||
console.trace(
|
||||
"[HMR] unexpected require(" +
|
||||
request +
|
||||
") from disposed module " +
|
||||
moduleId
|
||||
);
|
||||
currentParents = [];
|
||||
}
|
||||
return require(request);
|
||||
};
|
||||
var createPropertyDescriptor = function(name) {
|
||||
return {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return require[name];
|
||||
},
|
||||
set: function(value) {
|
||||
require[name] = value;
|
||||
}
|
||||
};
|
||||
};
|
||||
for (var name in require) {
|
||||
if (Object.prototype.hasOwnProperty.call(require, name) && name !== "e") {
|
||||
Object.defineProperty(fn, name, createPropertyDescriptor(name));
|
||||
}
|
||||
}
|
||||
fn.e = function(chunkId) {
|
||||
return trackBlockingPromise(require.e(chunkId));
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
|
||||
function createModuleHotObject(moduleId, me) {
|
||||
var hot = {
|
||||
// private stuff
|
||||
_acceptedDependencies: {},
|
||||
_declinedDependencies: {},
|
||||
_selfAccepted: false,
|
||||
_selfDeclined: false,
|
||||
_disposeHandlers: [],
|
||||
_main: currentChildModule !== moduleId,
|
||||
_requireSelf: function() {
|
||||
currentParents = me.parents.slice();
|
||||
currentChildModule = moduleId;
|
||||
__webpack_require__(moduleId);
|
||||
},
|
||||
|
||||
// Module API
|
||||
active: true,
|
||||
accept: function(dep, callback) {
|
||||
if (dep === undefined) hot._selfAccepted = true;
|
||||
else if (typeof dep === "function") hot._selfAccepted = dep;
|
||||
else if (typeof dep === "object" && dep !== null)
|
||||
for (var i = 0; i < dep.length; i++)
|
||||
hot._acceptedDependencies[dep[i]] = callback || function() {};
|
||||
else hot._acceptedDependencies[dep] = callback || function() {};
|
||||
},
|
||||
decline: function(dep) {
|
||||
if (dep === undefined) hot._selfDeclined = true;
|
||||
else if (typeof dep === "object" && dep !== null)
|
||||
for (var i = 0; i < dep.length; i++)
|
||||
hot._declinedDependencies[dep[i]] = true;
|
||||
else hot._declinedDependencies[dep] = true;
|
||||
},
|
||||
dispose: function(callback) {
|
||||
hot._disposeHandlers.push(callback);
|
||||
},
|
||||
addDisposeHandler: function(callback) {
|
||||
hot._disposeHandlers.push(callback);
|
||||
},
|
||||
removeDisposeHandler: function(callback) {
|
||||
var idx = hot._disposeHandlers.indexOf(callback);
|
||||
if (idx >= 0) hot._disposeHandlers.splice(idx, 1);
|
||||
},
|
||||
|
||||
// Management API
|
||||
check: hotCheck,
|
||||
apply: hotApply,
|
||||
status: function(l) {
|
||||
if (!l) return currentStatus;
|
||||
registeredStatusHandlers.push(l);
|
||||
},
|
||||
addStatusHandler: function(l) {
|
||||
registeredStatusHandlers.push(l);
|
||||
},
|
||||
removeStatusHandler: function(l) {
|
||||
var idx = registeredStatusHandlers.indexOf(l);
|
||||
if (idx >= 0) registeredStatusHandlers.splice(idx, 1);
|
||||
},
|
||||
|
||||
//inherit from previous dispose call
|
||||
data: currentModuleData[moduleId]
|
||||
};
|
||||
currentChildModule = undefined;
|
||||
return hot;
|
||||
}
|
||||
|
||||
function setStatus(newStatus) {
|
||||
currentStatus = newStatus;
|
||||
for (var i = 0; i < registeredStatusHandlers.length; i++)
|
||||
registeredStatusHandlers[i].call(null, newStatus);
|
||||
}
|
||||
|
||||
function trackBlockingPromise(promise) {
|
||||
switch (currentStatus) {
|
||||
case "ready":
|
||||
setStatus("prepare");
|
||||
blockingPromises.push(promise);
|
||||
waitForBlockingPromises(function() {
|
||||
setStatus("ready");
|
||||
});
|
||||
return promise;
|
||||
case "prepare":
|
||||
blockingPromises.push(promise);
|
||||
return promise;
|
||||
default:
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
function waitForBlockingPromises(fn) {
|
||||
if (blockingPromises.length === 0) return fn();
|
||||
var blocker = blockingPromises;
|
||||
blockingPromises = [];
|
||||
return Promise.all(blocker).then(function() {
|
||||
return waitForBlockingPromises(fn);
|
||||
});
|
||||
}
|
||||
|
||||
function hotCheck(applyOnUpdate) {
|
||||
if (currentStatus !== "idle") {
|
||||
throw new Error("check() is only allowed in idle status");
|
||||
}
|
||||
setStatus("check");
|
||||
return $hmrDownloadManifest$().then(function(update) {
|
||||
if (!update) {
|
||||
setStatus("idle");
|
||||
return null;
|
||||
}
|
||||
|
||||
setStatus("prepare");
|
||||
|
||||
currentUpdateNewHash = update.h;
|
||||
var updatedModules = [];
|
||||
blockingPromises = [];
|
||||
currentUpdateApplyHandlers = [];
|
||||
|
||||
return Promise.all(
|
||||
Object.keys($hmrDownloadUpdateHandlers$).reduce(function(
|
||||
promises,
|
||||
key
|
||||
) {
|
||||
$hmrDownloadUpdateHandlers$[key](
|
||||
update.c,
|
||||
update.r,
|
||||
update.m,
|
||||
promises,
|
||||
currentUpdateApplyHandlers,
|
||||
updatedModules
|
||||
);
|
||||
return promises;
|
||||
},
|
||||
[])
|
||||
).then(function() {
|
||||
return waitForBlockingPromises(function() {
|
||||
if (applyOnUpdate) {
|
||||
return internalApply(applyOnUpdate);
|
||||
} else {
|
||||
setStatus("ready");
|
||||
|
||||
return updatedModules;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function hotApply(options) {
|
||||
if (currentStatus !== "ready") {
|
||||
return Promise.resolve().then(function() {
|
||||
throw new Error("apply() is only allowed in ready status");
|
||||
});
|
||||
}
|
||||
return internalApply(options);
|
||||
}
|
||||
|
||||
function internalApply(options) {
|
||||
options = options || {};
|
||||
|
||||
var results = currentUpdateApplyHandlers.map(function(handler) {
|
||||
return handler(options);
|
||||
});
|
||||
|
||||
var errors = results
|
||||
.map(function(r) {
|
||||
return r.error;
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (errors.length > 0) {
|
||||
setStatus("abort");
|
||||
return Promise.resolve().then(function() {
|
||||
throw errors[0];
|
||||
});
|
||||
}
|
||||
|
||||
// Now in "dispose" phase
|
||||
setStatus("dispose");
|
||||
|
||||
results.forEach(function(result) {
|
||||
if (result.dispose) result.dispose();
|
||||
});
|
||||
|
||||
// Now in "apply" phase
|
||||
setStatus("apply");
|
||||
|
||||
currentHash = currentUpdateNewHash;
|
||||
|
||||
var error;
|
||||
var reportError = function(err) {
|
||||
if (!error) error = err;
|
||||
};
|
||||
|
||||
var outdatedModules = [];
|
||||
results.forEach(function(result) {
|
||||
if (result.apply) {
|
||||
var modules = result.apply(reportError);
|
||||
if (modules) {
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
outdatedModules.push(modules[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// handle errors in accept handlers and self accepted module load
|
||||
if (error) {
|
||||
setStatus("fail");
|
||||
return Promise.resolve().then(function() {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
setStatus("idle");
|
||||
return Promise.resolve(outdatedModules);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const RuntimeModule = require("../RuntimeModule");
|
||||
const Template = require("../Template");
|
||||
|
||||
class HotModuleReplacementRuntimeModule extends RuntimeModule {
|
||||
constructor() {
|
||||
super("hot module replacement", 5);
|
||||
}
|
||||
/**
|
||||
* @returns {string} runtime code
|
||||
*/
|
||||
generate() {
|
||||
return Template.getFunctionContent(
|
||||
require("./HotModuleReplacement.runtime.js")
|
||||
)
|
||||
.replace(/\$getFullHash\$/g, RuntimeGlobals.getFullHash)
|
||||
.replace(
|
||||
/\$interceptModuleExecution\$/g,
|
||||
RuntimeGlobals.interceptModuleExecution
|
||||
)
|
||||
.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
||||
.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
||||
.replace(/\$hmrDownloadManifest\$/g, RuntimeGlobals.hmrDownloadManifest)
|
||||
.replace(
|
||||
/\$hmrDownloadUpdateHandlers\$/g,
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HotModuleReplacementRuntimeModule;
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*global $options$ $updateModuleFactories$ $updateRuntimeModules$ $moduleCache$ $moduleFactories$ $hmrModuleData$ __webpack_require__ */
|
||||
|
||||
module.exports = function() {
|
||||
function getAffectedModuleEffects(updateModuleId) {
|
||||
var outdatedModules = [updateModuleId];
|
||||
var outdatedDependencies = {};
|
||||
|
||||
var queue = outdatedModules.slice().map(function(id) {
|
||||
return {
|
||||
chain: [id],
|
||||
id: id
|
||||
};
|
||||
});
|
||||
while (queue.length > 0) {
|
||||
var queueItem = queue.pop();
|
||||
var moduleId = queueItem.id;
|
||||
var chain = queueItem.chain;
|
||||
var module = $moduleCache$[moduleId];
|
||||
if (!module || module.hot._selfAccepted) continue;
|
||||
if (module.hot._selfDeclined) {
|
||||
return {
|
||||
type: "self-declined",
|
||||
chain: chain,
|
||||
moduleId: moduleId
|
||||
};
|
||||
}
|
||||
if (module.hot._main) {
|
||||
return {
|
||||
type: "unaccepted",
|
||||
chain: chain,
|
||||
moduleId: moduleId
|
||||
};
|
||||
}
|
||||
for (var i = 0; i < module.parents.length; i++) {
|
||||
var parentId = module.parents[i];
|
||||
var parent = $moduleCache$[parentId];
|
||||
if (!parent) continue;
|
||||
if (parent.hot._declinedDependencies[moduleId]) {
|
||||
return {
|
||||
type: "declined",
|
||||
chain: chain.concat([parentId]),
|
||||
moduleId: moduleId,
|
||||
parentId: parentId
|
||||
};
|
||||
}
|
||||
if (outdatedModules.indexOf(parentId) !== -1) continue;
|
||||
if (parent.hot._acceptedDependencies[moduleId]) {
|
||||
if (!outdatedDependencies[parentId])
|
||||
outdatedDependencies[parentId] = [];
|
||||
addAllToSet(outdatedDependencies[parentId], [moduleId]);
|
||||
continue;
|
||||
}
|
||||
delete outdatedDependencies[parentId];
|
||||
outdatedModules.push(parentId);
|
||||
queue.push({
|
||||
chain: chain.concat([parentId]),
|
||||
id: parentId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: "accepted",
|
||||
moduleId: updateModuleId,
|
||||
outdatedModules: outdatedModules,
|
||||
outdatedDependencies: outdatedDependencies
|
||||
};
|
||||
}
|
||||
|
||||
function addAllToSet(a, b) {
|
||||
for (var i = 0; i < b.length; i++) {
|
||||
var item = b[i];
|
||||
if (a.indexOf(item) === -1) a.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// at begin all updates modules are outdated
|
||||
// the "outdated" status can propagate to parents if they don't accept the children
|
||||
var outdatedDependencies = {};
|
||||
var outdatedModules = [];
|
||||
var appliedUpdate = {};
|
||||
|
||||
var warnUnexpectedRequire = function warnUnexpectedRequire() {
|
||||
console.warn(
|
||||
"[HMR] unexpected require(" + result.moduleId + ") to disposed module"
|
||||
);
|
||||
};
|
||||
|
||||
for (var moduleId in $updateModuleFactories$) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call($updateModuleFactories$, moduleId)
|
||||
) {
|
||||
var newModuleFactory = $updateModuleFactories$[moduleId];
|
||||
/** @type {TODO} */
|
||||
var result;
|
||||
if (newModuleFactory) {
|
||||
result = getAffectedModuleEffects(moduleId);
|
||||
} else {
|
||||
result = {
|
||||
type: "disposed",
|
||||
moduleId: moduleId
|
||||
};
|
||||
}
|
||||
/** @type {Error|false} */
|
||||
var abortError = false;
|
||||
var doApply = false;
|
||||
var doDispose = false;
|
||||
var chainInfo = "";
|
||||
if (result.chain) {
|
||||
chainInfo = "\nUpdate propagation: " + result.chain.join(" -> ");
|
||||
}
|
||||
switch (result.type) {
|
||||
case "self-declined":
|
||||
if ($options$.onDeclined) $options$.onDeclined(result);
|
||||
if (!$options$.ignoreDeclined)
|
||||
abortError = new Error(
|
||||
"Aborted because of self decline: " + result.moduleId + chainInfo
|
||||
);
|
||||
break;
|
||||
case "declined":
|
||||
if ($options$.onDeclined) $options$.onDeclined(result);
|
||||
if (!$options$.ignoreDeclined)
|
||||
abortError = new Error(
|
||||
"Aborted because of declined dependency: " +
|
||||
result.moduleId +
|
||||
" in " +
|
||||
result.parentId +
|
||||
chainInfo
|
||||
);
|
||||
break;
|
||||
case "unaccepted":
|
||||
if ($options$.onUnaccepted) $options$.onUnaccepted(result);
|
||||
if (!$options$.ignoreUnaccepted)
|
||||
abortError = new Error(
|
||||
"Aborted because " + moduleId + " is not accepted" + chainInfo
|
||||
);
|
||||
break;
|
||||
case "accepted":
|
||||
if ($options$.onAccepted) $options$.onAccepted(result);
|
||||
doApply = true;
|
||||
break;
|
||||
case "disposed":
|
||||
if ($options$.onDisposed) $options$.onDisposed(result);
|
||||
doDispose = true;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexception type " + result.type);
|
||||
}
|
||||
if (abortError) {
|
||||
return {
|
||||
error: abortError
|
||||
};
|
||||
}
|
||||
if (doApply) {
|
||||
appliedUpdate[moduleId] = newModuleFactory;
|
||||
addAllToSet(outdatedModules, result.outdatedModules);
|
||||
for (moduleId in result.outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
result.outdatedDependencies,
|
||||
moduleId
|
||||
)
|
||||
) {
|
||||
if (!outdatedDependencies[moduleId])
|
||||
outdatedDependencies[moduleId] = [];
|
||||
addAllToSet(
|
||||
outdatedDependencies[moduleId],
|
||||
result.outdatedDependencies[moduleId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doDispose) {
|
||||
addAllToSet(outdatedModules, [result.moduleId]);
|
||||
appliedUpdate[moduleId] = warnUnexpectedRequire;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store self accepted outdated modules to require them later by the module system
|
||||
var outdatedSelfAcceptedModules = [];
|
||||
for (var j = 0; j < outdatedModules.length; j++) {
|
||||
var outdatedModuleId = outdatedModules[j];
|
||||
if (
|
||||
$moduleCache$[outdatedModuleId] &&
|
||||
$moduleCache$[outdatedModuleId].hot._selfAccepted
|
||||
)
|
||||
outdatedSelfAcceptedModules.push({
|
||||
module: outdatedModuleId,
|
||||
require: $moduleCache$[outdatedModuleId].hot._requireSelf,
|
||||
errorHandler: $moduleCache$[outdatedModuleId].hot._selfAccepted
|
||||
});
|
||||
}
|
||||
|
||||
var moduleOutdatedDependencies;
|
||||
|
||||
return {
|
||||
dispose: function() {
|
||||
// $dispose$
|
||||
|
||||
var idx;
|
||||
var queue = outdatedModules.slice();
|
||||
while (queue.length > 0) {
|
||||
var moduleId = queue.pop();
|
||||
var module = $moduleCache$[moduleId];
|
||||
if (!module) continue;
|
||||
|
||||
var data = {};
|
||||
|
||||
// Call dispose handlers
|
||||
var disposeHandlers = module.hot._disposeHandlers;
|
||||
for (j = 0; j < disposeHandlers.length; j++) {
|
||||
disposeHandlers[j].call(null, data);
|
||||
}
|
||||
$hmrModuleData$[moduleId] = data;
|
||||
|
||||
// disable module (this disables requires from this module)
|
||||
module.hot.active = false;
|
||||
|
||||
// remove module from cache
|
||||
delete $moduleCache$[moduleId];
|
||||
|
||||
// when disposing there is no need to call dispose handler
|
||||
delete outdatedDependencies[moduleId];
|
||||
|
||||
// remove "parents" references from all children
|
||||
for (j = 0; j < module.children.length; j++) {
|
||||
var child = $moduleCache$[module.children[j]];
|
||||
if (!child) continue;
|
||||
idx = child.parents.indexOf(moduleId);
|
||||
if (idx >= 0) {
|
||||
child.parents.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove outdated dependency from module children
|
||||
var dependency;
|
||||
for (var outdatedModuleId in outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
outdatedDependencies,
|
||||
outdatedModuleId
|
||||
)
|
||||
) {
|
||||
module = $moduleCache$[outdatedModuleId];
|
||||
if (module) {
|
||||
moduleOutdatedDependencies = outdatedDependencies[outdatedModuleId];
|
||||
for (j = 0; j < moduleOutdatedDependencies.length; j++) {
|
||||
dependency = moduleOutdatedDependencies[j];
|
||||
idx = module.children.indexOf(dependency);
|
||||
if (idx >= 0) module.children.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
apply: function(reportError) {
|
||||
// insert new code
|
||||
for (var updateModuleId in appliedUpdate) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(appliedUpdate, updateModuleId)
|
||||
) {
|
||||
$moduleFactories$[updateModuleId] = appliedUpdate[updateModuleId];
|
||||
}
|
||||
}
|
||||
|
||||
// run new runtime modules
|
||||
for (var i = 0; i < $updateRuntimeModules$.length; i++) {
|
||||
appliedUpdate[$updateRuntimeModules$[i]](0, 0, __webpack_require__);
|
||||
}
|
||||
|
||||
// call accept handlers
|
||||
var error = null;
|
||||
for (var outdatedModuleId in outdatedDependencies) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
outdatedDependencies,
|
||||
outdatedModuleId
|
||||
)
|
||||
) {
|
||||
var module = $moduleCache$[outdatedModuleId];
|
||||
if (module) {
|
||||
moduleOutdatedDependencies = outdatedDependencies[outdatedModuleId];
|
||||
var callbacks = [];
|
||||
for (var j = 0; j < moduleOutdatedDependencies.length; j++) {
|
||||
var dependency = moduleOutdatedDependencies[j];
|
||||
var acceptCallback = module.hot._acceptedDependencies[dependency];
|
||||
if (acceptCallback) {
|
||||
if (callbacks.indexOf(acceptCallback) !== -1) continue;
|
||||
callbacks.push(acceptCallback);
|
||||
}
|
||||
}
|
||||
for (var k = 0; k < callbacks.length; k++) {
|
||||
try {
|
||||
callbacks[k].call(null, moduleOutdatedDependencies);
|
||||
} catch (err) {
|
||||
if ($options$.onErrored) {
|
||||
$options$.onErrored({
|
||||
type: "accept-errored",
|
||||
moduleId: outdatedModuleId,
|
||||
dependencyId: moduleOutdatedDependencies[i],
|
||||
error: err
|
||||
});
|
||||
}
|
||||
if (!$options$.ignoreErrored) {
|
||||
if (!error) error = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load self accepted modules
|
||||
for (var o = 0; o < outdatedSelfAcceptedModules.length; o++) {
|
||||
var item = outdatedSelfAcceptedModules[o];
|
||||
var moduleId = item.module;
|
||||
try {
|
||||
item.require(moduleId);
|
||||
} catch (err) {
|
||||
if (typeof item.errorHandler === "function") {
|
||||
try {
|
||||
item.errorHandler(err);
|
||||
} catch (err2) {
|
||||
if ($options$.onErrored) {
|
||||
$options$.onErrored({
|
||||
type: "self-accept-error-handler-errored",
|
||||
moduleId: moduleId,
|
||||
error: err2,
|
||||
originalError: err
|
||||
});
|
||||
}
|
||||
if (!$options$.ignoreErrored) {
|
||||
reportError(err2);
|
||||
}
|
||||
reportError(err);
|
||||
}
|
||||
} else {
|
||||
if ($options$.onErrored) {
|
||||
$options$.onErrored({
|
||||
type: "self-accept-errored",
|
||||
moduleId: moduleId,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
if (!$options$.ignoreErrored) {
|
||||
reportError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outdatedModules;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -9,7 +9,16 @@ const { ConcatSource } = require("webpack-sources");
|
|||
|
||||
/** @typedef {import("../ChunkTemplate")} ChunkTemplate */
|
||||
|
||||
const getRuntimeModuleIds = (chunkGraph, chunk) => {
|
||||
return chunkGraph
|
||||
.getChunkRuntimeModulesInOrder(chunk)
|
||||
.map(m => chunkGraph.getModuleId(m));
|
||||
};
|
||||
|
||||
class NodeChunkTemplatePlugin {
|
||||
constructor(compilation) {
|
||||
this.compilation = compilation;
|
||||
}
|
||||
/**
|
||||
* @param {ChunkTemplate} chunkTemplate the chunk template
|
||||
* @returns {void}
|
||||
|
@ -17,19 +26,30 @@ class NodeChunkTemplatePlugin {
|
|||
apply(chunkTemplate) {
|
||||
chunkTemplate.hooks.render.tap(
|
||||
"NodeChunkTemplatePlugin",
|
||||
(modules, moduleTemplate, { chunk }) => {
|
||||
(modules, moduleTemplate, { chunk, chunkGraph }) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
`exports.ids = ${JSON.stringify(chunk.ids)};\nexports.modules = `
|
||||
);
|
||||
source.add(`exports.id = ${JSON.stringify(chunk.id)};\n`);
|
||||
source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`);
|
||||
source.add(`exports.modules = `);
|
||||
source.add(modules);
|
||||
source.add(";");
|
||||
source.add(";\n");
|
||||
const runtimeModules = getRuntimeModuleIds(chunkGraph, chunk);
|
||||
if (runtimeModules.length > 0) {
|
||||
source.add(`exports.runtime = ${JSON.stringify(runtimeModules)};\n`);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
);
|
||||
chunkTemplate.hooks.hashForChunk.tap(
|
||||
"NodeChunkTemplatePlugin",
|
||||
(hash, chunk) => {
|
||||
const chunkGraph = this.compilation.chunkGraph;
|
||||
hash.update(JSON.stringify(getRuntimeModuleIds(chunkGraph, chunk)));
|
||||
}
|
||||
);
|
||||
chunkTemplate.hooks.hash.tap("NodeChunkTemplatePlugin", hash => {
|
||||
hash.update("node");
|
||||
hash.update("3");
|
||||
hash.update("5");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("../HotUpdateChunkTemplate")} HotUpdateChunkTemplate */
|
||||
|
||||
class NodeHotUpdateChunkTemplatePlugin {
|
||||
/**
|
||||
* @param {HotUpdateChunkTemplate} hotUpdateChunkTemplate the hot update chunk template
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(hotUpdateChunkTemplate) {
|
||||
hotUpdateChunkTemplate.hooks.render.tap(
|
||||
"NodeHotUpdateChunkTemplatePlugin",
|
||||
(modulesSource, moduleTemplate, { chunk }) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
"exports.id = " + JSON.stringify(chunk.id) + ";\nexports.modules = "
|
||||
);
|
||||
source.add(modulesSource);
|
||||
source.add(";");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
hotUpdateChunkTemplate.hooks.hash.tap(
|
||||
"NodeHotUpdateChunkTemplatePlugin",
|
||||
hash => {
|
||||
hash.update("NodeHotUpdateChunkTemplatePlugin");
|
||||
hash.update("3");
|
||||
hash.update(
|
||||
hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + ""
|
||||
);
|
||||
hash.update(hotUpdateChunkTemplate.outputOptions.library + "");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = NodeHotUpdateChunkTemplatePlugin;
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*global installedChunks $hotChunkFilename$ hotAddUpdateChunk $hotMainFilename$ */
|
||||
module.exports = function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
var chunk = require("./" + $hotChunkFilename$);
|
||||
hotAddUpdateChunk(chunk.id, chunk.modules);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest() {
|
||||
try {
|
||||
var update = require("./" + $hotMainFilename$);
|
||||
} catch (e) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.resolve(update);
|
||||
}
|
||||
|
||||
//eslint-disable-next-line no-unused-vars
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
};
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*global installedChunks $hotChunkFilename$ hotAddUpdateChunk $hotMainFilename$ $onError$ */
|
||||
|
||||
module.exports = function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
var filename = require("path").join(__dirname, $hotChunkFilename$);
|
||||
require("fs").readFile(filename, "utf-8", function(err, content) {
|
||||
if (err) {
|
||||
if ($onError$) return $onError$(err);
|
||||
throw err;
|
||||
}
|
||||
var chunk = {};
|
||||
require("vm").runInThisContext(
|
||||
"(function(exports) {" + content + "\n})",
|
||||
{ filename: filename }
|
||||
)(chunk);
|
||||
hotAddUpdateChunk(chunk.id, chunk.modules);
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest() {
|
||||
var filename = require("path").join(__dirname, $hotMainFilename$);
|
||||
return new Promise(function(resolve, reject) {
|
||||
require("fs").readFile(filename, "utf-8", function(err, content) {
|
||||
if (err) return resolve();
|
||||
try {
|
||||
var update = JSON.parse(content);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
resolve(update);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
};
|
|
@ -5,11 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const NodeChunkTemplatePlugin = require("./NodeChunkTemplatePlugin");
|
||||
const NodeHotUpdateChunkTemplatePlugin = require("./NodeHotUpdateChunkTemplatePlugin");
|
||||
const ReadFileChunkLoadingRuntimeModule = require("./ReadFileChunkLoadingRuntimeModule");
|
||||
const RequireChunkLoadingRuntimeModule = require("./RequireChunkLoadingRuntimeModule");
|
||||
|
||||
|
@ -27,88 +24,57 @@ class NodeTemplatePlugin {
|
|||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("NodeTemplatePlugin", compilation => {
|
||||
new NodeChunkTemplatePlugin().apply(compilation.chunkTemplate);
|
||||
new NodeHotUpdateChunkTemplatePlugin().apply(
|
||||
compilation.hotUpdateChunkTemplate
|
||||
);
|
||||
new NodeChunkTemplatePlugin(compilation).apply(compilation.chunkTemplate);
|
||||
|
||||
const onceForChunkSet = new WeakSet();
|
||||
const handler = (chunk, set) => {
|
||||
if (onceForChunkSet.has(chunk)) return;
|
||||
onceForChunkSet.add(chunk);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
if (this.asyncChunkLoading) {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new ReadFileChunkLoadingRuntimeModule(chunk, set)
|
||||
);
|
||||
} else {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new RequireChunkLoadingRuntimeModule(chunk, set)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap("NodeTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.startup)
|
||||
.tap("NodeTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("NodeTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("NodeTemplatePlugin", handler);
|
||||
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap("NodeTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
set.add(RuntimeGlobals.getChunkScriptFilename);
|
||||
if (this.asyncChunkLoading) {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new ReadFileChunkLoadingRuntimeModule(chunk)
|
||||
);
|
||||
} else {
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new RequireChunkLoadingRuntimeModule(chunk)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const { hotBootstrap } = HotModuleReplacementPlugin.getMainTemplateHooks(
|
||||
mainTemplate
|
||||
);
|
||||
|
||||
hotBootstrap.tap("NodeTemplatePlugin", (source, chunk, hash) => {
|
||||
const hotUpdateChunkFilename =
|
||||
mainTemplate.outputOptions.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename =
|
||||
mainTemplate.outputOptions.hotUpdateMainFilename;
|
||||
const chunkMaps = chunk.getChunkMaps();
|
||||
const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateChunkFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "',
|
||||
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
|
||||
hashWithLength: length => {
|
||||
const shortChunkHashMap = {};
|
||||
for (const chunkId of Object.keys(chunkMaps.hash)) {
|
||||
if (typeof chunkMaps.hash[chunkId] === "string") {
|
||||
shortChunkHashMap[chunkId] = chunkMaps.hash[chunkId].substr(
|
||||
0,
|
||||
length
|
||||
);
|
||||
}
|
||||
}
|
||||
return `" + ${JSON.stringify(shortChunkHashMap)}[chunkId] + "`;
|
||||
},
|
||||
name: `" + (${JSON.stringify(
|
||||
chunkMaps.name
|
||||
)}[chunkId]||chunkId) + "`
|
||||
}
|
||||
}
|
||||
);
|
||||
const currentHotUpdateMainFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateMainFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`
|
||||
}
|
||||
);
|
||||
return Template.getFunctionContent(
|
||||
this.asyncChunkLoading
|
||||
? require("./NodeMainTemplateAsync.runtime")
|
||||
: require("./NodeMainTemplate.runtime")
|
||||
)
|
||||
.replace(/\$onError\$/g, RuntimeGlobals.uncaughtErrorHandler)
|
||||
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
||||
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename);
|
||||
});
|
||||
mainTemplate.hooks.hash.tap("NodeTemplatePlugin", hash => {
|
||||
hash.update("node");
|
||||
hash.update("4");
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("NodeTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
|
||||
set.add(RuntimeGlobals.moduleCache);
|
||||
set.add(RuntimeGlobals.hmrModuleData);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("NodeTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.getUpdateManifestFilename);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ const RuntimeModule = require("../RuntimeModule");
|
|||
const Template = require("../Template");
|
||||
|
||||
class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
||||
constructor(chunk) {
|
||||
constructor(chunk, runtimeRequirements) {
|
||||
super("readFile chunk loading", 10);
|
||||
this.chunk = chunk;
|
||||
this.runtimeRequirements = runtimeRequirements;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,15 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
generate() {
|
||||
const { chunk } = this;
|
||||
const fn = RuntimeGlobals.ensureChunkHandlers;
|
||||
const withLoading = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.ensureChunkHandlers
|
||||
);
|
||||
const withHmr = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
);
|
||||
const withHmrManifest = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadManifest
|
||||
);
|
||||
return Template.asString([
|
||||
"// object to store loaded chunks",
|
||||
'// "0" means "already loaded", Promise means loading',
|
||||
|
@ -29,66 +39,189 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
),
|
||||
"};",
|
||||
"",
|
||||
"// ReadFile + VM.run chunk loading for javascript",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
"",
|
||||
"var installedChunkData = installedChunks[chunkId];",
|
||||
'if(installedChunkData !== 0) { // 0 means "already installed".',
|
||||
Template.indent([
|
||||
'// array of [resolve, reject, promise] means "currently loading"',
|
||||
"if(installedChunkData) {",
|
||||
Template.indent(["promises.push(installedChunkData[2]);"]),
|
||||
"} else {",
|
||||
Template.indent([
|
||||
"// load the chunk and return promise to it",
|
||||
"var promise = new Promise(function(resolve, reject) {",
|
||||
withLoading
|
||||
? Template.asString([
|
||||
"// ReadFile + VM.run chunk loading for javascript",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
"installedChunkData = installedChunks[chunkId] = [resolve, reject];",
|
||||
`var filename = require('path').join(__dirname, ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId));`,
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
"",
|
||||
"var installedChunkData = installedChunks[chunkId];",
|
||||
'if(installedChunkData !== 0) { // 0 means "already installed".',
|
||||
Template.indent([
|
||||
"if(err) return reject(err);",
|
||||
"var chunk = {};",
|
||||
"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +
|
||||
"(chunk, require, require('path').dirname(filename), filename);",
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
'// array of [resolve, reject, promise] means "currently loading"',
|
||||
"if(installedChunkData) {",
|
||||
Template.indent(["promises.push(installedChunkData[2]);"]),
|
||||
"} else {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
"// load the chunk and return promise to it",
|
||||
"var promise = new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
"installedChunkData = installedChunks[chunkId] = [resolve, reject];",
|
||||
`var filename = require('path').join(__dirname, ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId));`,
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
Template.indent([
|
||||
"if(err) return reject(err);",
|
||||
"var chunk = {};",
|
||||
"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +
|
||||
"(chunk, require, require('path').dirname(filename), filename);",
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent([
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
`if(runtime) for(var i = 0; i < runtime.length; i++) moreModules[runtime[i]](0,0,__webpack_require__);`,
|
||||
"var callbacks = [];",
|
||||
"for(var i = 0; i < chunkIds.length; i++) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkIds[i]])",
|
||||
Template.indent([
|
||||
"callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);"
|
||||
]),
|
||||
"installedChunks[chunkIds[i]] = 0;"
|
||||
]),
|
||||
"}",
|
||||
"for(i = 0; i < callbacks.length; i++)",
|
||||
Template.indent("callbacks[i]();")
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"}"
|
||||
"});",
|
||||
"promises.push(installedChunkData[2] = promise);",
|
||||
"",
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"if(currentUpdateChunks && currentUpdateChunks[chunkId]) promises.push(loadUpdateChunk(chunkId));"
|
||||
])
|
||||
: "// no HMR"
|
||||
]),
|
||||
"}",
|
||||
"var callbacks = [];",
|
||||
"for(var i = 0; i < chunkIds.length; i++) {",
|
||||
"}"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"})"
|
||||
])
|
||||
: "// no chunk loading",
|
||||
"",
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"var currentUpdateChunks;",
|
||||
"var currentUpdate;",
|
||||
"var currentUpdateRuntime;",
|
||||
"function loadUpdateChunk(chunkId, updatedModulesList) {",
|
||||
Template.indent([
|
||||
"return new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
`var filename = require('path').join(__dirname, ${
|
||||
RuntimeGlobals.getChunkUpdateScriptFilename
|
||||
}(chunkId));`,
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkIds[i]])",
|
||||
"if(err) return reject(err);",
|
||||
"var update = {};",
|
||||
"require('vm').runInThisContext('(function(exports, require, __dirname, __filename) {' + content + '\\n})', filename)" +
|
||||
"(update, require, require('path').dirname(filename), filename);",
|
||||
"var updatedModules = update.modules;",
|
||||
"var runtime = update.runtime;",
|
||||
"for(var moduleId in updatedModules) {",
|
||||
Template.indent([
|
||||
"callbacks = callbacks.concat(installedChunks[chunkIds[i]][0]);"
|
||||
"if(Object.prototype.hasOwnProperty.call(updatedModules, moduleId)) {",
|
||||
Template.indent([
|
||||
`currentUpdate[moduleId] = updatedModules[moduleId];`,
|
||||
"if(updatedModulesList) updatedModulesList.push(moduleId);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"installedChunks[chunkIds[i]] = 0;"
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) currentUpdateRuntime.push(runtime[i]);",
|
||||
"resolve();"
|
||||
]),
|
||||
"}",
|
||||
"for(i = 0; i < callbacks.length; i++)",
|
||||
Template.indent("callbacks[i]();")
|
||||
"});"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"});",
|
||||
"promises.push(installedChunkData[2] = promise);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"})"
|
||||
"}",
|
||||
"",
|
||||
`${
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
}.readFileVm = function(chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) {`,
|
||||
Template.indent([
|
||||
"applyHandlers.push(function(options) {",
|
||||
Template.indent([
|
||||
"currentUpdateChunks = undefined;",
|
||||
Template.getFunctionContent(
|
||||
require("../hmr/JavascriptHotModuleReplacement.runtime.js")
|
||||
)
|
||||
.replace(/\$options\$/g, "options")
|
||||
.replace(/\$updateModuleFactories\$/g, "currentUpdate")
|
||||
.replace(/\$updateRuntimeModules\$/g, "currentUpdateRuntime")
|
||||
.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
||||
.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
||||
.replace(
|
||||
/\$moduleFactories\$/g,
|
||||
RuntimeGlobals.moduleFactories
|
||||
)
|
||||
.replace(
|
||||
/\/\/ \$dispose\$/g,
|
||||
Template.asString([
|
||||
"removedChunks.forEach(function(chunkId) { delete installedChunks[chunkId]; });"
|
||||
])
|
||||
)
|
||||
]),
|
||||
"});",
|
||||
"currentUpdateChunks = {};",
|
||||
"currentUpdate = removedModules.reduce(function(obj, key) { obj[key] = false; return obj; }, {});",
|
||||
"currentUpdateRuntime = [];",
|
||||
"chunkIds.forEach(function(chunkId) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkId] !== undefined) {",
|
||||
Template.indent([
|
||||
"promises.push(loadUpdateChunk(chunkId, updatedModulesList));"
|
||||
]),
|
||||
"}",
|
||||
"currentUpdateChunks[chunkId] = true;"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"};"
|
||||
])
|
||||
: "// no HMR",
|
||||
"",
|
||||
withHmrManifest
|
||||
? Template.asString([
|
||||
`${RuntimeGlobals.hmrDownloadManifest} = function() {`,
|
||||
Template.indent([
|
||||
"return new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
`var filename = require('path').join(__dirname, ${
|
||||
RuntimeGlobals.getUpdateManifestFilename
|
||||
}());`,
|
||||
"require('fs').readFile(filename, 'utf-8', function(err, content) {",
|
||||
Template.indent([
|
||||
"if(err) {",
|
||||
Template.indent([
|
||||
'if(err.code === "ENOENT") return resolve();',
|
||||
"return reject(err);"
|
||||
]),
|
||||
"}",
|
||||
"try { resolve(JSON.parse(content)); }",
|
||||
"catch(e) { reject(e); }"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"}"
|
||||
])
|
||||
: "// no HMR manifest"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ const RuntimeGlobals = require("../RuntimeGlobals");
|
|||
const RuntimeModule = require("../RuntimeModule");
|
||||
const Template = require("../Template");
|
||||
|
||||
class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
||||
constructor(chunk) {
|
||||
class RequireChunkLoadingRuntimeModule extends RuntimeModule {
|
||||
constructor(chunk, runtimeRequirements) {
|
||||
super("require chunk loading", 10);
|
||||
this.chunk = chunk;
|
||||
this.runtimeRequirements = runtimeRequirements;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,15 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
generate() {
|
||||
const { chunk } = this;
|
||||
const fn = RuntimeGlobals.ensureChunkHandlers;
|
||||
const withLoading = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.ensureChunkHandlers
|
||||
);
|
||||
const withHmr = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
);
|
||||
const withHmrManifest = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadManifest
|
||||
);
|
||||
return Template.asString([
|
||||
"// object to store loaded chunks",
|
||||
'// "1" means "loaded", otherwise not loaded yet',
|
||||
|
@ -29,36 +39,134 @@ class ReadFileChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
),
|
||||
"};",
|
||||
"",
|
||||
"// require() chunk loading for javascript",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
"",
|
||||
'// "0" is the signal for "already loaded"',
|
||||
"if(!installedChunks[chunkId]) {",
|
||||
Template.indent([
|
||||
`var chunk = require("./" + ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId));`,
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
withLoading
|
||||
? Template.asString([
|
||||
"// require() chunk loading for javascript",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
"",
|
||||
'// "0" is the signal for "already loaded"',
|
||||
"if(!installedChunks[chunkId]) {",
|
||||
Template.indent([
|
||||
`var chunk = require("./" + ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId));`,
|
||||
"var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;",
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent([
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
`if(runtime) for(var i = 0; i < runtime.length; i++) moreModules[runtime[i]](0,0,__webpack_require__);`,
|
||||
"for(var i = 0; i < chunkIds.length; i++)",
|
||||
Template.indent("installedChunks[chunkIds[i]] = 1;"),
|
||||
"",
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"if(currentUpdateChunks && currentUpdateChunks[chunkId]) loadUpdateChunk(chunkId);"
|
||||
])
|
||||
: "// no HMR"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"});"
|
||||
])
|
||||
: "// no chunk loading",
|
||||
"",
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"var currentUpdateChunks;",
|
||||
"var currentUpdate;",
|
||||
"var currentUpdateRuntime;",
|
||||
"function loadUpdateChunk(chunkId, updatedModulesList) {",
|
||||
Template.indent([
|
||||
`var update = require("./" + ${
|
||||
RuntimeGlobals.getChunkUpdateScriptFilename
|
||||
}(chunkId));`,
|
||||
"var updatedModules = update.modules;",
|
||||
"var runtime = update.runtime;",
|
||||
"for(var moduleId in updatedModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(updatedModules, moduleId)) {",
|
||||
Template.indent([
|
||||
`currentUpdate[moduleId] = updatedModules[moduleId];`,
|
||||
"if(updatedModulesList) updatedModulesList.push(moduleId);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) currentUpdateRuntime.push(runtime[i]);"
|
||||
]),
|
||||
"}",
|
||||
"",
|
||||
`${
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
}.require = function(chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) {`,
|
||||
Template.indent([
|
||||
"applyHandlers.push(function(options) {",
|
||||
Template.indent([
|
||||
"currentUpdateChunks = undefined;",
|
||||
Template.getFunctionContent(
|
||||
require("../hmr/JavascriptHotModuleReplacement.runtime.js")
|
||||
)
|
||||
.replace(/\$options\$/g, "options")
|
||||
.replace(/\$updateModuleFactories\$/g, "currentUpdate")
|
||||
.replace(/\$updateRuntimeModules\$/g, "currentUpdateRuntime")
|
||||
.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
||||
.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
||||
.replace(
|
||||
/\$moduleFactories\$/g,
|
||||
RuntimeGlobals.moduleFactories
|
||||
)
|
||||
.replace(
|
||||
/\/\/ \$dispose\$/g,
|
||||
Template.asString([
|
||||
"removedChunks.forEach(function(chunkId) { delete installedChunks[chunkId]; });"
|
||||
])
|
||||
)
|
||||
]),
|
||||
"});",
|
||||
"currentUpdateChunks = {};",
|
||||
"currentUpdate = removedModules.reduce(function(obj, key) { obj[key] = false; return obj; }, {});",
|
||||
"currentUpdateRuntime = [];",
|
||||
"chunkIds.forEach(function(chunkId) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkId] !== undefined) {",
|
||||
Template.indent([
|
||||
"loadUpdateChunk(chunkId, updatedModulesList);"
|
||||
]),
|
||||
"}",
|
||||
"currentUpdateChunks[chunkId] = true;"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"};"
|
||||
])
|
||||
: "// no HMR",
|
||||
"",
|
||||
withHmrManifest
|
||||
? Template.asString([
|
||||
`${RuntimeGlobals.hmrDownloadManifest} = function() {`,
|
||||
Template.indent([
|
||||
"return Promise.resolve().then(function() {",
|
||||
Template.indent([
|
||||
`return require("./" + ${
|
||||
RuntimeGlobals.getUpdateManifestFilename
|
||||
}());`
|
||||
]),
|
||||
'}).catch(function(err) { if(err.code !== "MODULE_NOT_FOUND") throw err; });'
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"for(var i = 0; i < chunkIds.length; i++)",
|
||||
Template.indent("installedChunks[chunkIds[i]] = 1;")
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"})"
|
||||
])
|
||||
: "// no HMR manifest"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReadFileChunkLoadingRuntimeModule;
|
||||
module.exports = RequireChunkLoadingRuntimeModule;
|
||||
|
|
|
@ -26,7 +26,7 @@ class CreateFakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
|
|||
"// mode & 8|1: behave like require",
|
||||
`${fn} = function(value, mode) {`,
|
||||
Template.indent([
|
||||
`if(mode & 1) value = __webpack_require__(value);`,
|
||||
`if(mode & 1) value = this(value);`,
|
||||
`if(mode & 8) return value;`,
|
||||
"if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;",
|
||||
"var ns = Object.create(null);",
|
||||
|
|
|
@ -9,8 +9,8 @@ const RuntimeModule = require("../RuntimeModule");
|
|||
const Template = require("../Template");
|
||||
|
||||
class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
||||
constructor(compilation, chunk, contentType, global, filename) {
|
||||
super(`get chunk ${contentType} filename`);
|
||||
constructor(compilation, chunk, contentType, name, global, filename) {
|
||||
super(`get ${name} chunk filename`);
|
||||
this.compilation = compilation;
|
||||
this.chunk = chunk;
|
||||
this.contentType = contentType;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const RuntimeModule = require("../RuntimeModule");
|
||||
const Template = require("../Template");
|
||||
|
||||
class GetMainFilenameRuntimeModule extends RuntimeModule {
|
||||
constructor(compilation, chunk, name, global, filename) {
|
||||
super(`get ${name} filename`);
|
||||
this.compilation = compilation;
|
||||
this.chunk = chunk;
|
||||
this.global = global;
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} runtime code
|
||||
*/
|
||||
generate() {
|
||||
const { global, filename, compilation } = this;
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
const url = mainTemplate.getAssetPath(JSON.stringify(filename), {
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`
|
||||
});
|
||||
return Template.asString([
|
||||
`${global} = function() {`,
|
||||
Template.indent([`return ${url};`]),
|
||||
"};"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GetMainFilenameRuntimeModule;
|
|
@ -51,6 +51,12 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
RuntimeGlobals.ensureChunkHandlers
|
||||
);
|
||||
const withDefer = this.runtimeRequirements.has(RuntimeGlobals.startup);
|
||||
const withHmr = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
);
|
||||
const withHmrManifest = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadManifest
|
||||
);
|
||||
const withPrefetch = needPrefetchingCode(chunk);
|
||||
const preloadChunkMap = chunk.getChildIdsByOrdersMap(chunkGraph).preload;
|
||||
const withPreload =
|
||||
|
@ -111,8 +117,16 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
"promises.push(installedChunkData[2] = promise);",
|
||||
"",
|
||||
"// start chunk loading",
|
||||
`var url = ${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId);`,
|
||||
"var loadingEnded = function() { if(installedChunks[chunkId]) return installedChunks[chunkId][1]; if(installedChunks[chunkId] !== 0) installedChunks[chunkId] = undefined; };",
|
||||
jsonpScript.call("", chunk),
|
||||
"head.appendChild(script);"
|
||||
"head.appendChild(script);",
|
||||
"",
|
||||
withHmr
|
||||
? "if(currentUpdateChunks && currentUpdateChunks[chunkId]) promises.push(loadUpdateChunk(chunkId));"
|
||||
: "// no HMR"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
|
@ -164,58 +178,126 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
])
|
||||
: "// no prefetching",
|
||||
"",
|
||||
"// install a JSONP callback for chunk loading",
|
||||
"function webpackJsonpCallback(data) {",
|
||||
Template.indent([
|
||||
"var chunkIds = data[0];",
|
||||
"var moreModules = data[1];",
|
||||
withDefer ? "var executeModules = data[2];" : "",
|
||||
withPrefetch ? "var prefetchChunks = data[3] || [];" : "",
|
||||
'// add "moreModules" to the modules object,',
|
||||
'// then flag all "chunkIds" as loaded and fire callback',
|
||||
"var moduleId, chunkId, i = 0, resolves = [];",
|
||||
"for(;i < chunkIds.length; i++) {",
|
||||
Template.indent([
|
||||
"chunkId = chunkIds[i];",
|
||||
"if(installedChunks[chunkId]) {",
|
||||
Template.indent("resolves.push(installedChunks[chunkId][0]);"),
|
||||
"}",
|
||||
"installedChunks[chunkId] = 0;"
|
||||
]),
|
||||
"}",
|
||||
"for(moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent(
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"var currentUpdateChunks;",
|
||||
"var currentUpdate;",
|
||||
"var currentUpdateRuntime;",
|
||||
"var currentUpdatedModulesList;",
|
||||
"var waitingUpdateResolves = {};",
|
||||
"var head = document.getElementsByTagName('head')[0];",
|
||||
"function loadUpdateChunk(chunkId) {",
|
||||
Template.indent([
|
||||
"return new Promise(function(resolve, reject) {",
|
||||
Template.indent([
|
||||
"waitingUpdateResolves[chunkId] = resolve;",
|
||||
"// start update chunk loading",
|
||||
`var url = ${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getChunkUpdateScriptFilename
|
||||
}(chunkId);`,
|
||||
"var loadingEnded = function() {",
|
||||
Template.indent([
|
||||
"if(waitingUpdateResolves[chunkId]) {",
|
||||
Template.indent([
|
||||
"waitingUpdateResolves[chunkId] = undefined",
|
||||
"return reject;"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"};",
|
||||
jsonpScript.call("", chunk),
|
||||
"head.appendChild(script);"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"}",
|
||||
"",
|
||||
`${outputOptions.globalObject}[${JSON.stringify(
|
||||
outputOptions.hotUpdateFunction
|
||||
)}] = function(chunkId, moreModules, runtime) {`,
|
||||
Template.indent([
|
||||
"for(moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent([
|
||||
"currentUpdate[moduleId] = moreModules[moduleId];",
|
||||
"if(currentUpdatedModulesList) currentUpdatedModulesList.push(moduleId);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) currentUpdateRuntime.push(runtime[i]);",
|
||||
"if(waitingUpdateResolves[chunkId]) {",
|
||||
Template.indent([
|
||||
"waitingUpdateResolves[chunkId]();",
|
||||
"waitingUpdateResolves[chunkId] = undefined;"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"};",
|
||||
"",
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(parentJsonpFunction) parentJsonpFunction(data);",
|
||||
withPrefetch
|
||||
? Template.asString([
|
||||
"// chunk prefetching for javascript",
|
||||
"prefetchChunks.forEach(prefetchChunk);"
|
||||
])
|
||||
: "",
|
||||
"while(resolves.length) {",
|
||||
Template.indent("resolves.shift()();"),
|
||||
"}",
|
||||
withDefer
|
||||
? Template.asString([
|
||||
"",
|
||||
"// add entry modules from loaded chunk to deferred list",
|
||||
"deferredModules.push.apply(deferredModules, executeModules || []);",
|
||||
"",
|
||||
"// run deferred modules when all chunks ready",
|
||||
"return checkDeferredModules();"
|
||||
])
|
||||
: ""
|
||||
]),
|
||||
"};",
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
}.jsonp = function(chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) {`,
|
||||
Template.indent([
|
||||
"applyHandlers.push(function(options) {",
|
||||
Template.indent([
|
||||
"currentUpdateChunks = undefined;",
|
||||
Template.getFunctionContent(
|
||||
require("../hmr/JavascriptHotModuleReplacement.runtime.js")
|
||||
)
|
||||
.replace(/\$options\$/g, "options")
|
||||
.replace(/\$updateModuleFactories\$/g, "currentUpdate")
|
||||
.replace(/\$updateRuntimeModules\$/g, "currentUpdateRuntime")
|
||||
.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
||||
.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
||||
.replace(
|
||||
/\$moduleFactories\$/g,
|
||||
RuntimeGlobals.moduleFactories
|
||||
)
|
||||
.replace(
|
||||
/\/\/ \$dispose\$/g,
|
||||
Template.asString([
|
||||
"removedChunks.forEach(function(chunkId) { delete installedChunks[chunkId]; });"
|
||||
])
|
||||
)
|
||||
]),
|
||||
"});",
|
||||
"currentUpdateChunks = {};",
|
||||
"currentUpdate = removedModules.reduce(function(obj, key) { obj[key] = false; return obj; }, {});",
|
||||
"currentUpdateRuntime = [];",
|
||||
"currentUpdatedModulesList = updatedModulesList;",
|
||||
"chunkIds.forEach(function(chunkId) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkId] !== undefined) {",
|
||||
Template.indent(["promises.push(loadUpdateChunk(chunkId));"]),
|
||||
"}",
|
||||
"currentUpdateChunks[chunkId] = true;"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"}"
|
||||
])
|
||||
: "// no HMR",
|
||||
"",
|
||||
withHmrManifest
|
||||
? Template.asString([
|
||||
`${RuntimeGlobals.hmrDownloadManifest} = function() {`,
|
||||
Template.indent([
|
||||
'if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");',
|
||||
`return fetch(${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getUpdateManifestFilename
|
||||
}()).then(function(response) {`,
|
||||
Template.indent([
|
||||
"if(response.status === 404) return; // no update available",
|
||||
'if(!response.ok) throw new Error("Failed to fetch update manifest " + response.statusText);',
|
||||
"return response.json();"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"};"
|
||||
])
|
||||
: "// no HMR manifest",
|
||||
"",
|
||||
withDefer
|
||||
? Template.asString([
|
||||
|
@ -254,16 +336,75 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
])
|
||||
: "// no deferred startup",
|
||||
"",
|
||||
`var jsonpArray = ${jsonpObject} = ${jsonpObject} || [];`,
|
||||
"var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);",
|
||||
"jsonpArray.push = webpackJsonpCallback;",
|
||||
withDefer
|
||||
withDefer || withLoading
|
||||
? Template.asString([
|
||||
"jsonpArray = jsonpArray.slice();",
|
||||
"for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);"
|
||||
"// install a JSONP callback for chunk loading",
|
||||
"function webpackJsonpCallback(data) {",
|
||||
Template.indent([
|
||||
"var chunkIds = data[0];",
|
||||
"var moreModules = data[1];",
|
||||
withDefer ? "var executeModules = data[2];" : "",
|
||||
"var runtime = data[3];",
|
||||
withPrefetch ? "var prefetchChunks = data[4];" : "",
|
||||
'// add "moreModules" to the modules object,',
|
||||
'// then flag all "chunkIds" as loaded and fire callback',
|
||||
"var moduleId, chunkId, i = 0, resolves = [];",
|
||||
"for(;i < chunkIds.length; i++) {",
|
||||
Template.indent([
|
||||
"chunkId = chunkIds[i];",
|
||||
"if(installedChunks[chunkId]) {",
|
||||
Template.indent("resolves.push(installedChunks[chunkId][0]);"),
|
||||
"}",
|
||||
"installedChunks[chunkId] = 0;"
|
||||
]),
|
||||
"}",
|
||||
"for(moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent(
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) moreModules[runtime[i]](0,0,__webpack_require__);",
|
||||
"if(parentJsonpFunction) parentJsonpFunction(data);",
|
||||
withPrefetch
|
||||
? Template.asString([
|
||||
"// chunk prefetching for javascript",
|
||||
"if(prefetchChunks) prefetchChunks.forEach(prefetchChunk);"
|
||||
])
|
||||
: "",
|
||||
"while(resolves.length) {",
|
||||
Template.indent("resolves.shift()();"),
|
||||
"}",
|
||||
withDefer
|
||||
? Template.asString([
|
||||
"",
|
||||
"// add entry modules from loaded chunk to deferred list",
|
||||
"if(executeModules) deferredModules.push.apply(deferredModules, executeModules);",
|
||||
"",
|
||||
"// run deferred modules when all chunks ready",
|
||||
"return checkDeferredModules();"
|
||||
])
|
||||
: ""
|
||||
]),
|
||||
"};",
|
||||
"",
|
||||
`var jsonpArray = ${jsonpObject} = ${jsonpObject} || [];`,
|
||||
"var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);",
|
||||
"jsonpArray.push = webpackJsonpCallback;",
|
||||
withDefer
|
||||
? Template.asString([
|
||||
"jsonpArray = jsonpArray.slice();",
|
||||
"for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);"
|
||||
])
|
||||
: "",
|
||||
"var parentJsonpFunction = oldJsonpFunction;"
|
||||
])
|
||||
: "",
|
||||
"var parentJsonpFunction = oldJsonpFunction;"
|
||||
: "// no jsonp function"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,31 +30,53 @@ class JsonpChunkTemplatePlugin {
|
|||
"JsonpChunkTemplatePlugin",
|
||||
(modules, moduleTemplate, { chunk, chunkGraph }) => {
|
||||
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
||||
const jsonpFunction = hotUpdateChunk
|
||||
? chunkTemplate.outputOptions.hotUpdateFunction
|
||||
: chunkTemplate.outputOptions.jsonpFunction;
|
||||
const globalObject = chunkTemplate.outputOptions.globalObject;
|
||||
const source = new ConcatSource();
|
||||
const prefetchChunks = chunk.getChildIdsByOrders(chunkGraph).prefetch;
|
||||
source.add(
|
||||
`(${globalObject}[${JSON.stringify(
|
||||
jsonpFunction
|
||||
)}] = ${globalObject}[${JSON.stringify(
|
||||
jsonpFunction
|
||||
)}] || []).push([${JSON.stringify(chunk.ids)},`
|
||||
);
|
||||
source.add(modules);
|
||||
const entries = getEntryInfo(chunkGraph, chunk);
|
||||
if (entries.length > 0) {
|
||||
source.add(`,${JSON.stringify(entries)}`);
|
||||
} else if (prefetchChunks && prefetchChunks.length) {
|
||||
source.add(`,0`);
|
||||
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
||||
const runtimePart =
|
||||
runtimeModules.length > 0 &&
|
||||
`,${JSON.stringify(
|
||||
runtimeModules.map(m => chunkGraph.getModuleId(m))
|
||||
)}`;
|
||||
if (hotUpdateChunk) {
|
||||
const jsonpFunction = chunkTemplate.outputOptions.hotUpdateFunction;
|
||||
source.add(`${globalObject}[${JSON.stringify(jsonpFunction)}](`);
|
||||
source.add(`${JSON.stringify(chunk.id)},`);
|
||||
source.add(modules);
|
||||
if (runtimePart) {
|
||||
source.add(runtimePart);
|
||||
}
|
||||
source.add(")");
|
||||
} else {
|
||||
const jsonpFunction = chunkTemplate.outputOptions.jsonpFunction;
|
||||
source.add(
|
||||
`(${globalObject}[${JSON.stringify(
|
||||
jsonpFunction
|
||||
)}] = ${globalObject}[${JSON.stringify(
|
||||
jsonpFunction
|
||||
)}] || []).push([`
|
||||
);
|
||||
source.add(`${JSON.stringify(chunk.ids)},`);
|
||||
source.add(modules);
|
||||
const entries = getEntryInfo(chunkGraph, chunk);
|
||||
const prefetchChunks = chunk.getChildIdsByOrders(chunkGraph).prefetch;
|
||||
const entriesPart =
|
||||
entries.length > 0 && `,${JSON.stringify(entries)}`;
|
||||
const prefetchPart =
|
||||
prefetchChunks &&
|
||||
prefetchChunks.length > 0 &&
|
||||
`,${JSON.stringify(prefetchChunks)}`;
|
||||
if (entriesPart || runtimePart || prefetchPart) {
|
||||
source.add(entriesPart || ",0");
|
||||
}
|
||||
if (runtimePart || prefetchPart) {
|
||||
source.add(runtimePart || ",0");
|
||||
}
|
||||
if (prefetchPart) {
|
||||
source.add(prefetchPart);
|
||||
}
|
||||
source.add("])");
|
||||
}
|
||||
|
||||
if (prefetchChunks && prefetchChunks.length) {
|
||||
source.add(`,${JSON.stringify(prefetchChunks)}`);
|
||||
}
|
||||
source.add("])");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
|
@ -73,6 +95,10 @@ class JsonpChunkTemplatePlugin {
|
|||
hash.update(
|
||||
JSON.stringify(chunk.getChildIdsByOrders(chunkGraph).prefetch) || ""
|
||||
);
|
||||
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
||||
hash.update(
|
||||
JSON.stringify(runtimeModules.map(m => chunkGraph.getModuleId(m)))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("../HotUpdateChunkTemplate")} HotUpdateChunkTemplate */
|
||||
|
||||
class JsonpHotUpdateChunkTemplatePlugin {
|
||||
/**
|
||||
* @param {HotUpdateChunkTemplate} hotUpdateChunkTemplate the hot update chunk template
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(hotUpdateChunkTemplate) {
|
||||
hotUpdateChunkTemplate.hooks.render.tap(
|
||||
"JsonpHotUpdateChunkTemplatePlugin",
|
||||
(modulesSource, moduleTemplate, { chunk }) => {
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
`${
|
||||
hotUpdateChunkTemplate.outputOptions.hotUpdateFunction
|
||||
}(${JSON.stringify(chunk.id)},`
|
||||
);
|
||||
source.add(modulesSource);
|
||||
source.add(")");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
hotUpdateChunkTemplate.hooks.hash.tap(
|
||||
"JsonpHotUpdateChunkTemplatePlugin",
|
||||
hash => {
|
||||
hash.update("JsonpHotUpdateChunkTemplatePlugin");
|
||||
hash.update("3");
|
||||
hash.update(
|
||||
`${hotUpdateChunkTemplate.outputOptions.hotUpdateFunction}`
|
||||
);
|
||||
hash.update(`${hotUpdateChunkTemplate.outputOptions.library}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = JsonpHotUpdateChunkTemplatePlugin;
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*globals hotAddUpdateChunk parentHotUpdateCallback document XMLHttpRequest $publicPath$ $hotChunkFilename$ $hotMainFilename$ $crossOriginLoading$ */
|
||||
|
||||
module.exports = function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function webpackHotUpdateCallback(chunkId, moreModules) {
|
||||
hotAddUpdateChunk(chunkId, moreModules);
|
||||
if (parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
|
||||
} //$semicolon
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
var script = document.createElement("script");
|
||||
script.charset = "utf-8";
|
||||
script.src = $publicPath$ + $hotChunkFilename$;
|
||||
if ($crossOriginLoading$) script.crossOrigin = $crossOriginLoading$;
|
||||
head.appendChild(script);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest(requestTimeout) {
|
||||
requestTimeout = requestTimeout || 10000;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof XMLHttpRequest === "undefined") {
|
||||
return reject(new Error("No browser support"));
|
||||
}
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
var requestPath = $publicPath$ + $hotMainFilename$;
|
||||
request.open("GET", requestPath, true);
|
||||
request.timeout = requestTimeout;
|
||||
request.send(null);
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
}
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState !== 4) return;
|
||||
if (request.status === 0) {
|
||||
// timeout
|
||||
reject(
|
||||
new Error("Manifest request to " + requestPath + " timed out.")
|
||||
);
|
||||
} else if (request.status === 404) {
|
||||
// no update available
|
||||
resolve();
|
||||
} else if (request.status !== 200 && request.status !== 304) {
|
||||
// other failure
|
||||
reject(new Error("Manifest request to " + requestPath + " failed."));
|
||||
} else {
|
||||
// success
|
||||
try {
|
||||
var update = JSON.parse(request.responseText);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
resolve(update);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
|
@ -7,12 +7,10 @@
|
|||
|
||||
const { SyncWaterfallHook } = require("tapable");
|
||||
const Compilation = require("../Compilation");
|
||||
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const JsonpChunkLoadingRuntimeModule = require("./JsonpChunkLoadingRuntimeModule");
|
||||
const JsonpChunkTemplatePlugin = require("./JsonpChunkTemplatePlugin");
|
||||
const JsonpHotUpdateChunkTemplatePlugin = require("./JsonpHotUpdateChunkTemplatePlugin");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
@ -60,9 +58,6 @@ class JsonpTemplatePlugin {
|
|||
new JsonpChunkTemplatePlugin(compilation).apply(
|
||||
compilation.chunkTemplate
|
||||
);
|
||||
new JsonpHotUpdateChunkTemplatePlugin().apply(
|
||||
compilation.hotUpdateChunkTemplate
|
||||
);
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
const needEntryDeferringCode = chunk => {
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
|
@ -77,10 +72,6 @@ class JsonpTemplatePlugin {
|
|||
linkPrefetch
|
||||
} = JsonpTemplatePlugin.getCompilationHooks(compilation);
|
||||
|
||||
const { hotBootstrap } = HotModuleReplacementPlugin.getMainTemplateHooks(
|
||||
mainTemplate
|
||||
);
|
||||
|
||||
jsonpScript.tap("JsonpTemplatePlugin", (_, chunk, hash) => {
|
||||
const crossOriginLoading =
|
||||
mainTemplate.outputOptions.crossOriginLoading;
|
||||
|
@ -100,9 +91,7 @@ class JsonpTemplatePlugin {
|
|||
`script.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
|
||||
),
|
||||
"}",
|
||||
`script.src = ${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId);`,
|
||||
`script.src = url;`,
|
||||
crossOriginLoading
|
||||
? Template.asString([
|
||||
"if (script.src.indexOf(window.location.origin + '/') !== 0) {",
|
||||
|
@ -117,20 +106,15 @@ class JsonpTemplatePlugin {
|
|||
"// avoid mem leaks in IE.",
|
||||
"script.onerror = script.onload = null;",
|
||||
"clearTimeout(timeout);",
|
||||
"var chunk = installedChunks[chunkId];",
|
||||
"if(chunk !== 0) {",
|
||||
"var reportError = loadingEnded();",
|
||||
"if(reportError) {",
|
||||
Template.indent([
|
||||
"if(chunk) {",
|
||||
Template.indent([
|
||||
"var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
|
||||
"var realSrc = event && event.target && event.target.src;",
|
||||
"var error = new Error('Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')');",
|
||||
"error.type = errorType;",
|
||||
"error.request = realSrc;",
|
||||
"chunk[1](error);"
|
||||
]),
|
||||
"}",
|
||||
"installedChunks[chunkId] = undefined;"
|
||||
"var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
|
||||
"var realSrc = event && event.target && event.target.src;",
|
||||
"var error = new Error('Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')');",
|
||||
"error.type = errorType;",
|
||||
"error.request = realSrc;",
|
||||
"reportError(error);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
|
@ -221,11 +205,33 @@ class JsonpTemplatePlugin {
|
|||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.startup)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.getChunkScriptFilename);
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getChunkScriptFilename);
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
|
||||
set.add(RuntimeGlobals.moduleCache);
|
||||
set.add(RuntimeGlobals.hmrModuleData);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getUpdateManifestFilename);
|
||||
});
|
||||
|
||||
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
||||
|
@ -236,60 +242,6 @@ class JsonpTemplatePlugin {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
hotBootstrap.tap("JsonpTemplatePlugin", (source, chunk, hash) => {
|
||||
const globalObject = mainTemplate.outputOptions.globalObject;
|
||||
const hotUpdateChunkFilename =
|
||||
mainTemplate.outputOptions.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename =
|
||||
mainTemplate.outputOptions.hotUpdateMainFilename;
|
||||
const crossOriginLoading =
|
||||
mainTemplate.outputOptions.crossOriginLoading;
|
||||
const hotUpdateFunction = mainTemplate.outputOptions.hotUpdateFunction;
|
||||
const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateChunkFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "'
|
||||
}
|
||||
}
|
||||
);
|
||||
const currentHotUpdateMainFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateMainFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`
|
||||
}
|
||||
);
|
||||
const runtimeSource = Template.getFunctionContent(
|
||||
require("./JsonpMainTemplate.runtime")
|
||||
)
|
||||
.replace(/\/\/\$semicolon/g, ";")
|
||||
.replace(
|
||||
/\$crossOriginLoading\$/g,
|
||||
crossOriginLoading ? JSON.stringify(crossOriginLoading) : "null"
|
||||
)
|
||||
.replace(/\$$publicPath$\$/g, RuntimeGlobals.publicPath)
|
||||
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
||||
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename)
|
||||
.replace(/\$hash\$/g, JSON.stringify(hash));
|
||||
return `${source}
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
var parentHotUpdateCallback = ${globalObject}[${JSON.stringify(
|
||||
hotUpdateFunction
|
||||
)}];
|
||||
${globalObject}[${JSON.stringify(hotUpdateFunction)}] = ${runtimeSource}`;
|
||||
});
|
||||
mainTemplate.hooks.hash.tap("JsonpTemplatePlugin", hash => {
|
||||
hash.update("jsonp");
|
||||
hash.update("6");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,19 +9,29 @@ const RuntimeModule = require("../RuntimeModule");
|
|||
const Template = require("../Template");
|
||||
|
||||
class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
|
||||
constructor(chunk, outputOptions) {
|
||||
constructor(chunk, outputOptions, runtimeRequirements) {
|
||||
super("importScripts chunk loading", 10);
|
||||
this.chunk = chunk;
|
||||
this.outputOptions = outputOptions;
|
||||
this.runtimeRequirements = runtimeRequirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} runtime code
|
||||
*/
|
||||
generate() {
|
||||
const { chunk } = this;
|
||||
const { globalObject, chunkCallbackName } = this.outputOptions;
|
||||
const { chunk, outputOptions } = this;
|
||||
const { globalObject, chunkCallbackName } = outputOptions;
|
||||
const fn = RuntimeGlobals.ensureChunkHandlers;
|
||||
const withLoading = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.ensureChunkHandlers
|
||||
);
|
||||
const withHmr = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
);
|
||||
const withHmrManifest = this.runtimeRequirements.has(
|
||||
RuntimeGlobals.hmrDownloadManifest
|
||||
);
|
||||
return Template.asString([
|
||||
"// object to store loaded chunks",
|
||||
'// "1" means "already loaded"',
|
||||
|
@ -31,41 +41,145 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
|
|||
),
|
||||
"};",
|
||||
"",
|
||||
"// importScripts chunk loading",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
'// "1" is the signal for "already loaded"',
|
||||
"if(!installedChunks[chunkId]) {",
|
||||
Template.indent([
|
||||
"promises.push(Promise.resolve().then(function() {",
|
||||
Template.indent([
|
||||
`importScripts(${RuntimeGlobals.getChunkScriptFilename}(chunkId));`
|
||||
]),
|
||||
"}));"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"});",
|
||||
withLoading
|
||||
? Template.asString([
|
||||
"// importScripts chunk loading",
|
||||
`${fn}.push(function(chunkId, promises) {`,
|
||||
Template.indent([
|
||||
'// "1" is the signal for "already loaded"',
|
||||
"if(!installedChunks[chunkId]) {",
|
||||
Template.indent([
|
||||
`${globalObject}[${JSON.stringify(
|
||||
chunkCallbackName
|
||||
)}] = function webpackChunkCallback(chunkIds, moreModules, runtime) {`,
|
||||
Template.indent([
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent(
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) moreModules[runtime[i]](0,0,__webpack_require__);",
|
||||
"while(chunkIds.length)",
|
||||
Template.indent("installedChunks[chunkIds.pop()] = 1;")
|
||||
]),
|
||||
"};",
|
||||
`importScripts(${
|
||||
RuntimeGlobals.getChunkScriptFilename
|
||||
}(chunkId));`,
|
||||
"",
|
||||
withHmr
|
||||
? "if(currentUpdateChunks && currentUpdateChunks[chunkId]) loadUpdateChunk(chunkId);"
|
||||
: "// no HMR"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"});"
|
||||
])
|
||||
: "// no chunk loading",
|
||||
"",
|
||||
`${globalObject}[${JSON.stringify(
|
||||
chunkCallbackName
|
||||
)}] = function webpackChunkCallback(chunkIds, moreModules) {`,
|
||||
Template.indent([
|
||||
"for(var moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent(
|
||||
withHmr
|
||||
? Template.asString([
|
||||
"var currentUpdateChunks;",
|
||||
"var currentUpdate;",
|
||||
"var currentUpdateRuntime;",
|
||||
"function loadUpdateChunk(chunkId, updatedModulesList) {",
|
||||
Template.indent([
|
||||
"var success = false;",
|
||||
`${outputOptions.globalObject}[${JSON.stringify(
|
||||
outputOptions.hotUpdateFunction
|
||||
)}] = function(moreModules, runtime) {`,
|
||||
Template.indent([
|
||||
"for(moduleId in moreModules) {",
|
||||
Template.indent([
|
||||
"if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {",
|
||||
Template.indent([
|
||||
"currentUpdate[moduleId] = moreModules[moduleId];",
|
||||
"if(updatedModulesList) updatedModulesList.push(moduleId);"
|
||||
]),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"if(runtime) for(var i = 0; i < runtime.length; i++) currentUpdateRuntime.push(runtime[i]);",
|
||||
"success = true;"
|
||||
]),
|
||||
"};",
|
||||
"// start update chunk loading",
|
||||
`importScripts(${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getChunkUpdateScriptFilename
|
||||
}(chunkId));`,
|
||||
'if(!success) throw new Error("Loading update chunk failed for unknown reason");'
|
||||
]),
|
||||
"}",
|
||||
"",
|
||||
`${
|
||||
RuntimeGlobals.moduleFactories
|
||||
}[moduleId] = moreModules[moduleId];`
|
||||
),
|
||||
"}"
|
||||
]),
|
||||
"}",
|
||||
"while(chunkIds.length)",
|
||||
Template.indent("installedChunks[chunkIds.pop()] = 1;")
|
||||
]),
|
||||
"};"
|
||||
RuntimeGlobals.hmrDownloadUpdateHandlers
|
||||
}.jsonp = function(chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList) {`,
|
||||
Template.indent([
|
||||
"applyHandlers.push(function(options) {",
|
||||
Template.indent([
|
||||
"currentUpdateChunks = undefined;",
|
||||
Template.getFunctionContent(
|
||||
require("../hmr/JavascriptHotModuleReplacement.runtime.js")
|
||||
)
|
||||
.replace(/\$options\$/g, "options")
|
||||
.replace(/\$updateModuleFactories\$/g, "currentUpdate")
|
||||
.replace(/\$updateRuntimeModules\$/g, "currentUpdateRuntime")
|
||||
.replace(/\$moduleCache\$/g, RuntimeGlobals.moduleCache)
|
||||
.replace(/\$hmrModuleData\$/g, RuntimeGlobals.hmrModuleData)
|
||||
.replace(
|
||||
/\$moduleFactories\$/g,
|
||||
RuntimeGlobals.moduleFactories
|
||||
)
|
||||
.replace(
|
||||
/\/\/ \$dispose\$/g,
|
||||
Template.asString([
|
||||
"removedChunks.forEach(function(chunkId) { delete installedChunks[chunkId]; });"
|
||||
])
|
||||
)
|
||||
]),
|
||||
"});",
|
||||
"currentUpdateChunks = {};",
|
||||
"currentUpdate = removedModules.reduce(function(obj, key) { obj[key] = false; return obj; }, {});",
|
||||
"currentUpdateRuntime = [];",
|
||||
"chunkIds.forEach(function(chunkId) {",
|
||||
Template.indent([
|
||||
"if(installedChunks[chunkId] !== undefined) {",
|
||||
Template.indent([
|
||||
"promises.push(loadUpdateChunk(chunkId, updatedModulesList));"
|
||||
]),
|
||||
"}",
|
||||
"currentUpdateChunks[chunkId] = true;"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"}"
|
||||
])
|
||||
: "// no HMR",
|
||||
"",
|
||||
withHmrManifest
|
||||
? Template.asString([
|
||||
`${RuntimeGlobals.hmrDownloadManifest} = function() {`,
|
||||
Template.indent([
|
||||
'if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");',
|
||||
`return fetch(${RuntimeGlobals.publicPath} + ${
|
||||
RuntimeGlobals.getUpdateManifestFilename
|
||||
}()).then(function(response) {`,
|
||||
Template.indent([
|
||||
"if(response.status === 404) return; // no update available",
|
||||
'if(!response.ok) throw new Error("Failed to fetch update manifest " + response.statusText);',
|
||||
"return response.json();"
|
||||
]),
|
||||
"});"
|
||||
]),
|
||||
"};"
|
||||
])
|
||||
: "// no HMR manifest"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,19 @@
|
|||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
const HotUpdateChunk = require("../HotUpdateChunk");
|
||||
|
||||
/** @typedef {import("../ChunkTemplate")} ChunkTemplate */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
||||
class WebWorkerChunkTemplatePlugin {
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation
|
||||
*/
|
||||
constructor(compilation) {
|
||||
this.compilation = compilation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkTemplate} chunkTemplate the chunk template
|
||||
* @returns {void}
|
||||
|
@ -17,27 +26,55 @@ class WebWorkerChunkTemplatePlugin {
|
|||
apply(chunkTemplate) {
|
||||
chunkTemplate.hooks.render.tap(
|
||||
"WebWorkerChunkTemplatePlugin",
|
||||
(modules, moduleTemplate, { chunk }) => {
|
||||
const chunkCallbackName = chunkTemplate.outputOptions.chunkCallbackName;
|
||||
(modules, moduleTemplate, { chunk, chunkGraph }) => {
|
||||
const hotUpdateChunk = chunk instanceof HotUpdateChunk ? chunk : null;
|
||||
const globalObject = chunkTemplate.outputOptions.globalObject;
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
`${globalObject}[${JSON.stringify(
|
||||
chunkCallbackName
|
||||
)}](${JSON.stringify(chunk.ids)},`
|
||||
);
|
||||
source.add(modules);
|
||||
source.add(")");
|
||||
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
||||
const runtimePart =
|
||||
runtimeModules.length > 0 &&
|
||||
`,${JSON.stringify(
|
||||
runtimeModules.map(m => chunkGraph.getModuleId(m))
|
||||
)}`;
|
||||
if (hotUpdateChunk) {
|
||||
const jsonpFunction = chunkTemplate.outputOptions.hotUpdateFunction;
|
||||
source.add(`${globalObject}[${JSON.stringify(jsonpFunction)}](`);
|
||||
source.add(modules);
|
||||
if (runtimePart) {
|
||||
source.add(runtimePart);
|
||||
}
|
||||
source.add(")");
|
||||
} else {
|
||||
const chunkCallbackName =
|
||||
chunkTemplate.outputOptions.chunkCallbackName;
|
||||
source.add(`${globalObject}[${JSON.stringify(chunkCallbackName)}](`);
|
||||
source.add(`${JSON.stringify(chunk.ids)},`);
|
||||
source.add(modules);
|
||||
if (runtimePart) {
|
||||
source.add(runtimePart);
|
||||
}
|
||||
source.add(")");
|
||||
}
|
||||
return source;
|
||||
}
|
||||
);
|
||||
chunkTemplate.hooks.hash.tap("WebWorkerChunkTemplatePlugin", hash => {
|
||||
hash.update("webworker");
|
||||
hash.update("3");
|
||||
hash.update("4");
|
||||
hash.update(`${chunkTemplate.outputOptions.chunkCallbackName}`);
|
||||
hash.update(`${chunkTemplate.outputOptions.hotUpdateFunction}`);
|
||||
hash.update(`${chunkTemplate.outputOptions.globalObject}`);
|
||||
});
|
||||
chunkTemplate.hooks.hashForChunk.tap(
|
||||
"WebWorkerChunkTemplatePlugin",
|
||||
(hash, chunk) => {
|
||||
const chunkGraph = this.compilation.chunkGraph;
|
||||
const runtimeModules = chunkGraph.getChunkRuntimeModulesInOrder(chunk);
|
||||
hash.update(
|
||||
JSON.stringify(runtimeModules.map(m => chunkGraph.getModuleId(m)))
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = WebWorkerChunkTemplatePlugin;
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("../HotUpdateChunkTemplate")} HotUpdateChunkTemplate */
|
||||
|
||||
class WebWorkerHotUpdateChunkTemplatePlugin {
|
||||
/**
|
||||
* @param {HotUpdateChunkTemplate} hotUpdateChunkTemplate the hot update chunk template
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(hotUpdateChunkTemplate) {
|
||||
hotUpdateChunkTemplate.hooks.render.tap(
|
||||
"WebWorkerHotUpdateChunkTemplatePlugin",
|
||||
(modulesSource, moduleTemplate, { chunk }) => {
|
||||
const hotUpdateFunction =
|
||||
hotUpdateChunkTemplate.outputOptions.hotUpdateFunction;
|
||||
const globalObject = hotUpdateChunkTemplate.outputOptions.globalObject;
|
||||
const source = new ConcatSource();
|
||||
source.add(
|
||||
`${globalObject}[${JSON.stringify(
|
||||
hotUpdateFunction
|
||||
)}](${JSON.stringify(chunk.id)},`
|
||||
);
|
||||
source.add(modulesSource);
|
||||
source.add(")");
|
||||
return source;
|
||||
}
|
||||
);
|
||||
hotUpdateChunkTemplate.hooks.hash.tap(
|
||||
"WebWorkerHotUpdateChunkTemplatePlugin",
|
||||
hash => {
|
||||
hash.update("WebWorkerHotUpdateChunkTemplatePlugin");
|
||||
hash.update("3");
|
||||
hash.update(
|
||||
hotUpdateChunkTemplate.outputOptions.hotUpdateFunction + ""
|
||||
);
|
||||
hash.update(hotUpdateChunkTemplate.outputOptions.globalObject + "");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
module.exports = WebWorkerHotUpdateChunkTemplatePlugin;
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*globals installedChunks hotAddUpdateChunk parentHotUpdateCallback importScripts XMLHttpRequest $publicPath$ $hotChunkFilename$ $hotMainFilename$ */
|
||||
|
||||
module.exports = function() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function webpackHotUpdateCallback(chunkId, moreModules) {
|
||||
hotAddUpdateChunk(chunkId, moreModules);
|
||||
if (parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
|
||||
} //$semicolon
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadUpdateChunk(chunkId) {
|
||||
importScripts($publicPath$ + $hotChunkFilename$);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function hotDownloadManifest(requestTimeout) {
|
||||
requestTimeout = requestTimeout || 10000;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof XMLHttpRequest === "undefined") {
|
||||
return reject(new Error("No browser support"));
|
||||
}
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
var requestPath = $publicPath$ + $hotMainFilename$;
|
||||
request.open("GET", requestPath, true);
|
||||
request.timeout = requestTimeout;
|
||||
request.send(null);
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
}
|
||||
request.onreadystatechange = function() {
|
||||
if (request.readyState !== 4) return;
|
||||
if (request.status === 0) {
|
||||
// timeout
|
||||
reject(
|
||||
new Error("Manifest request to " + requestPath + " timed out.")
|
||||
);
|
||||
} else if (request.status === 404) {
|
||||
// no update available
|
||||
resolve();
|
||||
} else if (request.status !== 200 && request.status !== 304) {
|
||||
// other failure
|
||||
reject(new Error("Manifest request to " + requestPath + " failed."));
|
||||
} else {
|
||||
// success
|
||||
try {
|
||||
var update = JSON.parse(request.responseText);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
resolve(update);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
//eslint-disable-next-line no-unused-vars
|
||||
function hotDisposeChunk(chunkId) {
|
||||
delete installedChunks[chunkId];
|
||||
}
|
||||
};
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin");
|
||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const ImportScriptsChunkLoadingRuntimeModule = require("./ImportScriptsChunkLoadingRuntimeModule");
|
||||
const WebWorkerChunkTemplatePlugin = require("./WebWorkerChunkTemplatePlugin");
|
||||
const WebWorkerHotUpdateChunkTemplatePlugin = require("./WebWorkerHotUpdateChunkTemplatePlugin");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
|
@ -22,71 +20,58 @@ class WebWorkerTemplatePlugin {
|
|||
compiler.hooks.thisCompilation.tap(
|
||||
"WebWorkerTemplatePlugin",
|
||||
compilation => {
|
||||
new WebWorkerChunkTemplatePlugin().apply(compilation.chunkTemplate);
|
||||
new WebWorkerHotUpdateChunkTemplatePlugin().apply(
|
||||
compilation.hotUpdateChunkTemplate
|
||||
new WebWorkerChunkTemplatePlugin(compilation).apply(
|
||||
compilation.chunkTemplate
|
||||
);
|
||||
|
||||
compilation.hooks.runtimeRequirementInTree.for(
|
||||
RuntimeGlobals.ensureChunkHandlers
|
||||
);
|
||||
const onceForChunkSet = new WeakSet();
|
||||
const handler = (chunk, set) => {
|
||||
if (onceForChunkSet.has(chunk)) return;
|
||||
onceForChunkSet.add(chunk);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
compilation.addRuntimeModule(
|
||||
chunk,
|
||||
new ImportScriptsChunkLoadingRuntimeModule(
|
||||
chunk,
|
||||
compilation.outputOptions,
|
||||
set
|
||||
)
|
||||
);
|
||||
};
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.startup)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("JsonpTemplatePlugin", handler);
|
||||
|
||||
const mainTemplate = compilation.mainTemplate;
|
||||
const {
|
||||
hotBootstrap
|
||||
} = HotModuleReplacementPlugin.getMainTemplateHooks(mainTemplate);
|
||||
hotBootstrap.tap(
|
||||
"WebWorkerMainTemplatePlugin",
|
||||
(source, chunk, hash) => {
|
||||
const hotUpdateChunkFilename =
|
||||
mainTemplate.outputOptions.hotUpdateChunkFilename;
|
||||
const hotUpdateMainFilename =
|
||||
mainTemplate.outputOptions.hotUpdateMainFilename;
|
||||
const hotUpdateFunction =
|
||||
mainTemplate.outputOptions.hotUpdateFunction;
|
||||
const globalObject = mainTemplate.outputOptions.globalObject;
|
||||
const currentHotUpdateChunkFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateChunkFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
|
||||
chunk: {
|
||||
id: '" + chunkId + "'
|
||||
}
|
||||
}
|
||||
);
|
||||
const currentHotUpdateMainFilename = mainTemplate.getAssetPath(
|
||||
JSON.stringify(hotUpdateMainFilename),
|
||||
{
|
||||
hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
|
||||
hashWithLength: length =>
|
||||
`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
source +
|
||||
"\n" +
|
||||
`var parentHotUpdateCallback = ${globalObject}[${JSON.stringify(
|
||||
hotUpdateFunction
|
||||
)}];\n` +
|
||||
`${globalObject}[${JSON.stringify(hotUpdateFunction)}] = ` +
|
||||
Template.getFunctionContent(
|
||||
require("./WebWorkerMainTemplate.runtime")
|
||||
)
|
||||
.replace(/\/\/\$semicolon/g, ";")
|
||||
.replace(/\$publicPath\$/g, RuntimeGlobals.publicPath)
|
||||
.replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
|
||||
.replace(/\$hotChunkFilename\$/g, currentHotUpdateChunkFilename)
|
||||
.replace(/\$hash\$/g, JSON.stringify(hash))
|
||||
);
|
||||
}
|
||||
);
|
||||
mainTemplate.hooks.hash.tap("WebWorkerMainTemplatePlugin", hash => {
|
||||
hash.update("webworker");
|
||||
hash.update("4");
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.ensureChunkHandlers)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getChunkScriptFilename);
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getChunkUpdateScriptFilename);
|
||||
set.add(RuntimeGlobals.moduleCache);
|
||||
set.add(RuntimeGlobals.hmrModuleData);
|
||||
set.add(RuntimeGlobals.moduleFactories);
|
||||
});
|
||||
compilation.hooks.runtimeRequirementInTree
|
||||
.for(RuntimeGlobals.hmrDownloadManifest)
|
||||
.tap("JsonpTemplatePlugin", (chunk, set) => {
|
||||
set.add(RuntimeGlobals.publicPath);
|
||||
set.add(RuntimeGlobals.getUpdateManifestFilename);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1868,6 +1868,10 @@
|
|||
"description": "add information about the reasons why modules are included",
|
||||
"type": "boolean"
|
||||
},
|
||||
"runtime": {
|
||||
"description": "add information about runtime modules",
|
||||
"type": "boolean"
|
||||
},
|
||||
"source": {
|
||||
"description": "add the source code of modules",
|
||||
"type": "boolean"
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
"use strict";
|
||||
|
||||
/* globals expect fit */
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const vm = require("vm");
|
||||
const checkArrayExpectation = require("./checkArrayExpectation");
|
||||
const createLazyTestEnv = require("./helpers/createLazyTestEnv");
|
||||
|
||||
const webpack = require("../lib/webpack");
|
||||
|
||||
const casesPath = path.join(__dirname, "hotCases");
|
||||
let categories = fs
|
||||
.readdirSync(casesPath)
|
||||
.filter(dir => fs.statSync(path.join(casesPath, dir)).isDirectory());
|
||||
categories = categories.map(cat => {
|
||||
return {
|
||||
name: cat,
|
||||
tests: fs
|
||||
.readdirSync(path.join(casesPath, cat))
|
||||
.filter(folder => folder.indexOf("_") < 0)
|
||||
};
|
||||
});
|
||||
|
||||
const describeCases = config => {
|
||||
describe(config.name, () => {
|
||||
categories.forEach(category => {
|
||||
describe(category.name, () => {
|
||||
category.tests.forEach(testName => {
|
||||
describe(testName, () => {
|
||||
it(
|
||||
testName + " should compile",
|
||||
done => {
|
||||
const testDirectory = path.join(
|
||||
casesPath,
|
||||
category.name,
|
||||
testName
|
||||
);
|
||||
const outputDirectory = path.join(
|
||||
__dirname,
|
||||
"js",
|
||||
`hot-cases-${config.name}`,
|
||||
category.name,
|
||||
testName
|
||||
);
|
||||
const recordsPath = path.join(outputDirectory, "records.json");
|
||||
if (fs.existsSync(recordsPath)) fs.unlinkSync(recordsPath);
|
||||
const fakeUpdateLoaderOptions = {
|
||||
updateIndex: 0
|
||||
};
|
||||
const configPath = path.join(testDirectory, "webpack.config.js");
|
||||
let options = {};
|
||||
if (fs.existsSync(configPath)) options = require(configPath);
|
||||
if (!options.mode) options.mode = "development";
|
||||
if (!options.devtool) options.devtool = false;
|
||||
if (!options.context) options.context = testDirectory;
|
||||
if (!options.entry) options.entry = "./index.js";
|
||||
if (!options.output) options.output = {};
|
||||
if (!options.output.path) options.output.path = outputDirectory;
|
||||
if (!options.output.filename)
|
||||
options.output.filename = "bundle.js";
|
||||
if (!options.output.chunkFilename)
|
||||
options.output.chunkFilename = "[name].chunk.[hash].js";
|
||||
if (options.output.pathinfo === undefined)
|
||||
options.output.pathinfo = true;
|
||||
if (!options.optimization) options.optimization = {};
|
||||
if (!options.optimization.moduleIds)
|
||||
options.optimization.moduleIds = "named";
|
||||
if (!options.module) options.module = {};
|
||||
if (!options.module.rules) options.module.rules = [];
|
||||
options.module.rules.push({
|
||||
loader: path.join(
|
||||
__dirname,
|
||||
"hotCases",
|
||||
"fake-update-loader.js"
|
||||
),
|
||||
enforce: "pre"
|
||||
});
|
||||
if (!options.target) options.target = config.target;
|
||||
if (!options.plugins) options.plugins = [];
|
||||
options.plugins.push(
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.LoaderOptionsPlugin(fakeUpdateLoaderOptions)
|
||||
);
|
||||
if (!options.recordsPath) options.recordsPath = recordsPath;
|
||||
const compiler = webpack(options);
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return done(err);
|
||||
const jsonStats = stats.toJson({
|
||||
errorDetails: true
|
||||
});
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"error",
|
||||
"Error",
|
||||
done
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"warning",
|
||||
"Warning",
|
||||
done
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const window = {
|
||||
fetch: (url) => {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json() {
|
||||
return Promise.resolve(require(path.resolve(outputDirectory, url)));
|
||||
}
|
||||
})
|
||||
},
|
||||
importScripts: url => {
|
||||
_require("./" + url);
|
||||
},
|
||||
document: {
|
||||
createElement(type) {
|
||||
return {
|
||||
_type: type,
|
||||
_attrs: {},
|
||||
setAttribute(name, value) {
|
||||
this._attrs[name] = value;
|
||||
}
|
||||
};
|
||||
},
|
||||
head: {
|
||||
appendChild(element) {
|
||||
if(element._type === "script") {
|
||||
// run it
|
||||
Promise.resolve().then(() => {
|
||||
_require("./" + element.src);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
getElementsByTagName(name) {
|
||||
if(name === "head") return [this.head];
|
||||
throw new Error("Not supported");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function _next(callback) {
|
||||
fakeUpdateLoaderOptions.updateIndex++;
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return callback(err);
|
||||
const jsonStats = stats.toJson({
|
||||
errorDetails: true
|
||||
});
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"error",
|
||||
"errors" + fakeUpdateLoaderOptions.updateIndex,
|
||||
"Error",
|
||||
callback
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"warning",
|
||||
"warnings" + fakeUpdateLoaderOptions.updateIndex,
|
||||
"Warning",
|
||||
callback
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
callback(null, jsonStats);
|
||||
});
|
||||
}
|
||||
|
||||
function _require(module) {
|
||||
if (module.substr(0, 2) === "./") {
|
||||
const p = path.join(outputDirectory, module);
|
||||
if(module.endsWith(".json")) {
|
||||
return JSON.parse(fs.readFileSync(p, "utf-8"));
|
||||
} else {
|
||||
const fn = vm.runInThisContext(
|
||||
"(function(require, module, exports, __dirname, __filename, it, expect, self, window, fetch, document, importScripts, NEXT, STATS) {" +
|
||||
"global.expect = expect;" +
|
||||
'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' +
|
||||
fs.readFileSync(p, "utf-8") +
|
||||
"\n})",
|
||||
p
|
||||
);
|
||||
const m = {
|
||||
exports: {}
|
||||
};
|
||||
fn.call(
|
||||
m.exports,
|
||||
_require,
|
||||
m,
|
||||
m.exports,
|
||||
outputDirectory,
|
||||
p,
|
||||
_it,
|
||||
expect,
|
||||
window,
|
||||
window,
|
||||
window.fetch,
|
||||
window.document,
|
||||
window.importScripts,
|
||||
_next,
|
||||
jsonStats
|
||||
);
|
||||
return m.exports;
|
||||
}
|
||||
} else return require(module);
|
||||
}
|
||||
_require("./bundle.js");
|
||||
if (getNumberOfTests() < 1)
|
||||
return done(new Error("No tests exported by test case"));
|
||||
|
||||
done();
|
||||
});
|
||||
},
|
||||
10000
|
||||
);
|
||||
|
||||
const { it: _it, getNumberOfTests } = createLazyTestEnv(
|
||||
jasmine.getEnv(),
|
||||
10000
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.describeCases = describeCases;
|
|
@ -1,193 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/* globals expect fit */
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const vm = require("vm");
|
||||
const checkArrayExpectation = require("./checkArrayExpectation");
|
||||
const createLazyTestEnv = require("./helpers/createLazyTestEnv");
|
||||
|
||||
const webpack = require("../lib/webpack");
|
||||
|
||||
describe("HotTestCases", () => {
|
||||
const casesPath = path.join(__dirname, "hotCases");
|
||||
let categories = fs
|
||||
.readdirSync(casesPath)
|
||||
.filter(dir => fs.statSync(path.join(casesPath, dir)).isDirectory());
|
||||
categories = categories.map(cat => {
|
||||
return {
|
||||
name: cat,
|
||||
tests: fs
|
||||
.readdirSync(path.join(casesPath, cat))
|
||||
.filter(folder => folder.indexOf("_") < 0)
|
||||
};
|
||||
});
|
||||
categories.forEach(category => {
|
||||
describe(category.name, () => {
|
||||
category.tests.forEach(testName => {
|
||||
describe(testName, () => {
|
||||
it(
|
||||
testName + " should compile",
|
||||
done => {
|
||||
const testDirectory = path.join(
|
||||
casesPath,
|
||||
category.name,
|
||||
testName
|
||||
);
|
||||
const outputDirectory = path.join(
|
||||
__dirname,
|
||||
"js",
|
||||
"hot-cases",
|
||||
category.name,
|
||||
testName
|
||||
);
|
||||
const recordsPath = path.join(outputDirectory, "records.json");
|
||||
if (fs.existsSync(recordsPath)) fs.unlinkSync(recordsPath);
|
||||
const fakeUpdateLoaderOptions = {
|
||||
updateIndex: 0
|
||||
};
|
||||
const configPath = path.join(testDirectory, "webpack.config.js");
|
||||
let options = {};
|
||||
if (fs.existsSync(configPath)) options = require(configPath);
|
||||
if (!options.mode) options.mode = "development";
|
||||
if (!options.devtool) options.devtool = false;
|
||||
if (!options.context) options.context = testDirectory;
|
||||
if (!options.entry) options.entry = "./index.js";
|
||||
if (!options.output) options.output = {};
|
||||
if (!options.output.path) options.output.path = outputDirectory;
|
||||
if (!options.output.filename)
|
||||
options.output.filename = "bundle.js";
|
||||
if (options.output.pathinfo === undefined)
|
||||
options.output.pathinfo = true;
|
||||
if (!options.optimization) options.optimization = {};
|
||||
if (!options.optimization.moduleIds)
|
||||
options.optimization.moduleIds = "named";
|
||||
if (!options.module) options.module = {};
|
||||
if (!options.module.rules) options.module.rules = [];
|
||||
options.module.rules.push({
|
||||
loader: path.join(
|
||||
__dirname,
|
||||
"hotCases",
|
||||
"fake-update-loader.js"
|
||||
),
|
||||
enforce: "pre"
|
||||
});
|
||||
if (!options.target) options.target = "async-node";
|
||||
if (!options.plugins) options.plugins = [];
|
||||
options.plugins.push(
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.LoaderOptionsPlugin(fakeUpdateLoaderOptions)
|
||||
);
|
||||
if (!options.recordsPath) options.recordsPath = recordsPath;
|
||||
const compiler = webpack(options);
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return done(err);
|
||||
const jsonStats = stats.toJson({
|
||||
errorDetails: true
|
||||
});
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"error",
|
||||
"Error",
|
||||
done
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"warning",
|
||||
"Warning",
|
||||
done
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
function _next(callback) {
|
||||
fakeUpdateLoaderOptions.updateIndex++;
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return callback(err);
|
||||
const jsonStats = stats.toJson({
|
||||
errorDetails: true
|
||||
});
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"error",
|
||||
"errors" + fakeUpdateLoaderOptions.updateIndex,
|
||||
"Error",
|
||||
callback
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
checkArrayExpectation(
|
||||
testDirectory,
|
||||
jsonStats,
|
||||
"warning",
|
||||
"warnings" + fakeUpdateLoaderOptions.updateIndex,
|
||||
"Warning",
|
||||
callback
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
callback(null, jsonStats);
|
||||
});
|
||||
}
|
||||
|
||||
function _require(module) {
|
||||
if (module.substr(0, 2) === "./") {
|
||||
const p = path.join(outputDirectory, module);
|
||||
const fn = vm.runInThisContext(
|
||||
"(function(require, module, exports, __dirname, __filename, it, expect, NEXT, STATS) {" +
|
||||
"global.expect = expect;" +
|
||||
'function nsObj(m) { Object.defineProperty(m, Symbol.toStringTag, { value: "Module" }); return m; }' +
|
||||
fs.readFileSync(p, "utf-8") +
|
||||
"\n})",
|
||||
p
|
||||
);
|
||||
const m = {
|
||||
exports: {}
|
||||
};
|
||||
fn.call(
|
||||
m.exports,
|
||||
_require,
|
||||
m,
|
||||
m.exports,
|
||||
outputDirectory,
|
||||
p,
|
||||
_it,
|
||||
expect,
|
||||
_next,
|
||||
jsonStats
|
||||
);
|
||||
return m.exports;
|
||||
} else return require(module);
|
||||
}
|
||||
_require("./bundle.js");
|
||||
if (getNumberOfTests() < 1)
|
||||
return done(new Error("No tests exported by test case"));
|
||||
|
||||
done();
|
||||
});
|
||||
},
|
||||
10000
|
||||
);
|
||||
|
||||
const { it: _it, getNumberOfTests } = createLazyTestEnv(
|
||||
jasmine.getEnv(),
|
||||
10000
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
const { describeCases } = require("./HotTestCases.template");
|
||||
|
||||
describe("HotTestCases", () => {
|
||||
describeCases({
|
||||
name: "async-node",
|
||||
target: "async-node"
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
const { describeCases } = require("./HotTestCases.template");
|
||||
|
||||
describe("HotTestCases", () => {
|
||||
describeCases({
|
||||
name: "node",
|
||||
target: "node"
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
const { describeCases } = require("./HotTestCases.template");
|
||||
|
||||
describe("HotTestCases", () => {
|
||||
describeCases({
|
||||
name: "web",
|
||||
target: "web"
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
const { describeCases } = require("./HotTestCases.template");
|
||||
|
||||
describe("HotTestCases", () => {
|
||||
describeCases({
|
||||
name: "webworker",
|
||||
target: "webworker"
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +0,0 @@
|
|||
require("./common");
|
||||
|
||||
module.exports = "vendor";
|
||||
|
||||
it("should have the correct main flag for multi vendor module", function() {
|
||||
expect(module.hot._main).toBe(true);
|
||||
});
|
|
@ -1,7 +1,6 @@
|
|||
var HotModuleReplacementPlugin = require("../../../../lib/HotModuleReplacementPlugin");
|
||||
module.exports = {
|
||||
entry: {
|
||||
vendor: ["./vendor"],
|
||||
first: ["./shared", "./first"],
|
||||
second: ["./shared", "./second"]
|
||||
},
|
||||
|
@ -11,8 +10,14 @@ module.exports = {
|
|||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
minSize: 1,
|
||||
name: "vendor"
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
chunks: "all",
|
||||
name: "vendor",
|
||||
minChunks: 2,
|
||||
enforce: true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [new HotModuleReplacementPlugin()]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
var HotModuleReplacementPlugin = require("../../../../lib/HotModuleReplacementPlugin");
|
||||
module.exports = {
|
||||
entry: {
|
||||
vendor: ["./vendor"],
|
||||
main: "./index"
|
||||
},
|
||||
target: "web",
|
||||
|
@ -10,8 +9,14 @@ module.exports = {
|
|||
},
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
minSize: 1,
|
||||
name: "vendor"
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
chunks: "all",
|
||||
name: "vendor",
|
||||
test: /vendor/,
|
||||
enforce: true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [new HotModuleReplacementPlugin()]
|
||||
|
|
|
@ -17,6 +17,6 @@ it("should give modules the correct ids", function() {
|
|||
"./index.js",
|
||||
"dll-reference ../0-create-dll/dll.js",
|
||||
"dll/index.js",
|
||||
"runtime: make namespace object",
|
||||
"webpack/runtime/make namespace object",
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -44,8 +44,8 @@ it("should give modules the correct ids", function() {
|
|||
"dll/e2.js",
|
||||
"dll/f.jsx",
|
||||
"dll/g.abc.js",
|
||||
"runtime: compat get default export",
|
||||
"runtime: define property getter",
|
||||
"runtime: make namespace object",
|
||||
"webpack/runtime/compat get default export",
|
||||
"webpack/runtime/define property getter",
|
||||
"webpack/runtime/make namespace object",
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -44,8 +44,8 @@ it("should give modules the correct ids", function() {
|
|||
"../0-create-dll/g.abc.js",
|
||||
"./index.js",
|
||||
"dll-reference ../0-create-dll/dll.js",
|
||||
"runtime: compat get default export",
|
||||
"runtime: define property getter",
|
||||
"runtime: make namespace object",
|
||||
"webpack/runtime/compat get default export",
|
||||
"webpack/runtime/define property getter",
|
||||
"webpack/runtime/make namespace object",
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -1 +1,8 @@
|
|||
export default Date.now();
|
||||
export default "version a1";
|
||||
---
|
||||
export default "version a1";
|
||||
---
|
||||
export default "version a2";
|
||||
---
|
||||
export default "version a2";
|
||||
---
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export default "version b1";
|
||||
---
|
||||
export default "version b1";
|
||||
---
|
||||
export default "version b2";
|
||||
---
|
||||
export default "version b2";
|
|
@ -1,14 +1,23 @@
|
|||
it("should dispose a chunk which is removed from bundle", (done) => {
|
||||
var m1 = require("./module");
|
||||
m1.default.then((x1) => {
|
||||
expect(x1.default).toEqual("version a1");
|
||||
NEXT(require("../../update")(done, true, () => {
|
||||
var m2 = require("./module");
|
||||
m2.default.then((x2) => {
|
||||
expect(x2.default).toEqual("version b1");
|
||||
NEXT(require("../../update")(done, true, () => {
|
||||
var m3 = require("./module");
|
||||
m3.default.then((x3) => {
|
||||
expect(x1).not.toEqual(x2);
|
||||
done();
|
||||
expect(x3.default).toEqual("version b2");
|
||||
NEXT(require("../../update")(done, true, () => {
|
||||
var m4 = require("./module");
|
||||
m4.default.then((x4) => {
|
||||
expect(x4.default).toEqual("version a2");
|
||||
expect(x4).not.toEqual(x1);
|
||||
done();
|
||||
}).catch(done);
|
||||
}));
|
||||
}).catch(done);
|
||||
}));
|
||||
}).catch(done);
|
||||
|
|
|
@ -2,4 +2,6 @@ export default import("./a");
|
|||
---
|
||||
export default import("./b");
|
||||
---
|
||||
export default import("./b");
|
||||
---
|
||||
export default import("./a");
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import value from "./inner";
|
||||
|
||||
module.hot.accept("./inner");
|
||||
|
||||
export { value as default };
|
|
@ -0,0 +1,3 @@
|
|||
export default 1;
|
||||
---
|
||||
export default 2;
|
|
@ -0,0 +1,28 @@
|
|||
import value from "./file";
|
||||
|
||||
module.hot.accept("./file");
|
||||
|
||||
const asyncNext = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
NEXT((err, stats) => {
|
||||
if(err) return reject(err);
|
||||
resolve(stats);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it("should download the missing update chunk on import", () => {
|
||||
expect(value).toBe(1);
|
||||
return asyncNext().then(() => {
|
||||
return module.hot.check().then(() => {
|
||||
return import("./chunk").then(chunk => {
|
||||
expect(value).toBe(1);
|
||||
expect(chunk.default).toBe(10);
|
||||
return module.hot.apply().then(() => {
|
||||
expect(value).toBe(2);
|
||||
expect(chunk.default).toBe(20);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export default 10;
|
||||
---
|
||||
export default 20;
|
Loading…
Reference in New Issue