webpack-dev-middleware
Version:
A development middleware for webpack
193 lines (183 loc) • 7.96 kB
JavaScript
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
/* global __webpack_hash__ */
import getHot from "./utils/get-hot.js";
import { log } from "./utils/log.js";
import reloadPage from "./utils/reload.js";
var HMR_DOCS_URL = "https://webpack.js.org/concepts/hot-module-replacement/";
/** @type {string | undefined} */
var lastHash;
// Name of the compilation this runtime belongs to, locked on the first event
// whose hash matches `__webpack_hash__` (e.g. the `sync` sent on connect).
/** @type {string | undefined} */
var ownName;
/** @type {Record<string, number>} */
var failureStatuses = {
abort: 1,
fail: 1
};
// Set per applyUpdate() call from the client's `reload` option.
var reloadOnErrored = false;
var loggedRuntimeMissing = false;
/** @type {webpack.ApplyOptions} */
var applyOptions = {
ignoreUnaccepted: true,
ignoreDeclined: true,
ignoreErrored: true,
onUnaccepted: function onUnaccepted(event) {
log.warn("Ignored an update to unaccepted module ".concat(event.chain.join(" -> ")));
},
onDeclined: function onDeclined(event) {
log.warn("Ignored an update to declined module ".concat(event.chain.join(" -> ")));
},
onErrored: function onErrored(event) {
log.error(event.error);
log.warn("Ignored an error while updating module ".concat(event.moduleId, " (").concat(event.type, ")"));
// An error thrown inside an accept handler leaves the app in an
// undefined state — fall back to a full page reload.
if (reloadOnErrored) {
log.warn("Reloading page");
reloadPage();
}
}
};
/**
* @param {string=} hash latest webpack compilation hash
* @returns {boolean} true when the current bundle matches the latest hash
*/
function upToDate(hash) {
if (hash) lastHash = hash;
return lastHash === __webpack_hash__;
}
/**
* @param {string} hash latest hash from the SSE payload
* @param {{ reload?: boolean }} options client options
* @param {string=} name compilation name the payload belongs to
*/
export default function applyUpdate(hash, options, name) {
// MultiCompiler: a sibling bundle's hash would poison `lastHash` and end
// in "Cannot find update" plus a spurious full reload.
if (name) {
if (ownName === undefined && hash === __webpack_hash__) {
ownName = name;
}
if (ownName !== undefined && name !== ownName) {
return;
}
}
var hot = getHot();
if (!hot) {
// Logged (once) instead of thrown: this runs inside the SSE message
// handler, whose catch would mislabel a throw as an invalid message.
if (!loggedRuntimeMissing) {
loggedRuntimeMissing = true;
log.error("[HMR] Hot Module Replacement is disabled. " + "Add HotModuleReplacementPlugin to the webpack configuration.");
}
return;
}
var reload = options.reload;
reloadOnErrored = Boolean(reload);
/**
* Trigger a full page reload when HMR cannot apply the update.
*/
var performReload = function performReload() {
if (reload) {
log.warn("Reloading page");
reloadPage();
}
};
/**
* @param {Error} err error
*/
var handleError = function handleError(err) {
// `hot.check()` rejecting while the runtime is already in `abort`/`fail`
// is a webpack-internal state the browser suite cannot stage.
/* istanbul ignore next -- @preserve */
if (hot.status() in failureStatuses) {
log.warn("Cannot check for update (Full reload needed)");
log.warn(err.stack || err.message);
performReload();
return;
}
log.warn("Update check failed: ".concat(err.stack || err.message));
};
/**
* @param {(string | number)[]} updatedModules ids of modules that were attempted to update
* @param {(string | number)[] | null | undefined} renewedModules ids of modules that were successfully renewed
*/
var logUpdates = function logUpdates(updatedModules, renewedModules) {
var unacceptedModules = updatedModules.filter(function (moduleId) {
return !renewedModules || renewedModules.indexOf(moduleId) === -1;
});
if (unacceptedModules.length > 0) {
log.warn("The following modules couldn't be hot updated: " + "(Full reload needed)\n" + "This is usually because the modules which have changed " + "(and their parents) do not know how to hot reload themselves. " + "See ".concat(HMR_DOCS_URL, " for more details."));
var _iterator = _createForOfIteratorHelper(unacceptedModules),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var moduleId = _step.value;
log.warn(" - ".concat(moduleId));
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
performReload();
return;
}
// An applied update that renews nothing: webpack does not produce one
// from an edit, so there is no build to drive this from.
/* istanbul ignore next -- @preserve */
if (!renewedModules || renewedModules.length === 0) {
log.info("Nothing hot updated.");
} else {
log.info("Hot updated ".concat(renewedModules.length, " modules."));
// Detail as a collapsed group, visible from the "log" level up.
log.groupCollapsed("Updated modules:");
var _iterator2 = _createForOfIteratorHelper(renewedModules),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _moduleId = _step2.value;
log.log(" - ".concat(_moduleId));
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
log.groupEnd();
}
if (upToDate()) {
log.info("App is up to date.");
}
};
/**
* Ask webpack for the next chunk of HMR updates and apply them.
*/
var _check = function check() {
hot.check(false).then(function (updatedModules) {
if (!updatedModules) {
// A sibling bundle's event that raced the connect-time lock — the
// missing manifest is expected, not a reason to reload.
if (name && ownName !== undefined && name !== ownName) {
return undefined;
}
log.warn("Cannot find update (Full reload needed)");
log.warn("(Probably because of restarting the server)");
performReload();
return undefined;
}
return hot.apply(applyOptions).then(function (renewedModules) {
if (!upToDate()) _check();
logUpdates(updatedModules, renewedModules);
});
}).catch(handleError);
};
if (!upToDate(hash) && hot.status() === "idle") {
log.info("Checking for updates on the server...");
_check();
}
}