Skip to content

Instantly share code, notes, and snippets.

@rlamana
Last active November 4, 2018 00:37
Show Gist options
  • Save rlamana/41c4aaa1bbf79a50c4df841fb376c0c4 to your computer and use it in GitHub Desktop.
Save rlamana/41c4aaa1bbf79a50c4df841fb376c0c4 to your computer and use it in GitHub Desktop.
webpack-hot-middleware client.js to support port option
/*eslint-env browser*/
/*global __resourceQuery __webpack_public_path__*/
var options = {
path: "/__webpack_hmr",
timeout: 20 * 1000,
overlay: true,
reload: false,
log: true,
warn: true,
name: '',
autoConnect: true,
overlayStyles: {},
overlayWarnings: false,
ansiColors: {}
};
if (__resourceQuery) {
var querystring = require('querystring');
var overrides = querystring.parse(__resourceQuery.slice(1));
setOverrides(overrides);
}
if (typeof window === 'undefined') {
// do nothing
} else if (typeof window.EventSource === 'undefined') {
console.warn(
"webpack-hot-middleware's client requires EventSource to work. " +
"You should include a polyfill if you want to support this browser: " +
"https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events#Tools"
);
} else {
if (options.autoConnect) {
connect();
}
}
/* istanbul ignore next */
function setOptionsAndConnect(overrides) {
setOverrides(overrides);
connect();
}
function setOverrides(overrides) {
if (overrides.autoConnect) options.autoConnect = overrides.autoConnect == 'true';
if (overrides.path) options.path = overrides.path;
if (overrides.port) options.port = overrides.port;
if (overrides.timeout) options.timeout = overrides.timeout;
if (overrides.overlay) options.overlay = overrides.overlay !== 'false';
if (overrides.reload) options.reload = overrides.reload !== 'false';
if (overrides.noInfo && overrides.noInfo !== 'false') {
options.log = false;
}
if (overrides.name) {
options.name = overrides.name;
}
if (overrides.quiet && overrides.quiet !== 'false') {
options.log = false;
options.warn = false;
}
if (overrides.dynamicPublicPath) {
options.path = __webpack_public_path__ + options.path;
}
if (overrides.ansiColors) options.ansiColors = JSON.parse(overrides.ansiColors);
if (overrides.overlayStyles) options.overlayStyles = JSON.parse(overrides.overlayStyles);
if (overrides.overlayWarnings) {
options.overlayWarnings = overrides.overlayWarnings == 'true';
}
}
function EventSourceWrapper() {
var source;
var lastActivity = new Date();
var listeners = [];
init();
var timer = setInterval(function() {
if ((new Date() - lastActivity) > options.timeout) {
handleDisconnect();
}
}, options.timeout / 2);
function init() {
var url = new URL(location.origin);
if (options.port) {
url.port = overrides.port;
}
url.pathname = options.path;
source = new window.EventSource(url.href);
source.onopen = handleOnline;
source.onerror = handleDisconnect;
source.onmessage = handleMessage;
}
function handleOnline() {
if (options.log) console.log("[HMR] connected");
lastActivity = new Date();
}
function handleMessage(event) {
lastActivity = new Date();
for (var i = 0; i < listeners.length; i++) {
listeners[i](event);
}
}
function handleDisconnect() {
clearInterval(timer);
source.close();
setTimeout(init, options.timeout);
}
return {
addMessageListener: function(fn) {
listeners.push(fn);
}
};
}
function getEventSourceWrapper() {
if (!window.__whmEventSourceWrapper) {
window.__whmEventSourceWrapper = {};
}
if (!window.__whmEventSourceWrapper[options.path]) {
// cache the wrapper for other entries loaded on
// the same page with the same options.path
window.__whmEventSourceWrapper[options.path] = EventSourceWrapper();
}
return window.__whmEventSourceWrapper[options.path];
}
function connect() {
getEventSourceWrapper().addMessageListener(handleMessage);
function handleMessage(event) {
if (event.data == "\uD83D\uDC93") {
return;
}
try {
processMessage(JSON.parse(event.data));
} catch (ex) {
if (options.warn) {
console.warn("Invalid HMR message: " + event.data + "\n" + ex);
}
}
}
}
// the reporter needs to be a singleton on the page
// in case the client is being used by multiple bundles
// we only want to report once.
// all the errors will go to all clients
var singletonKey = '__webpack_hot_middleware_reporter__';
var reporter;
if (typeof window !== 'undefined') {
if (!window[singletonKey]) {
window[singletonKey] = createReporter();
}
reporter = window[singletonKey];
}
function createReporter() {
var strip = require('strip-ansi');
var overlay;
if (typeof document !== 'undefined' && options.overlay) {
overlay = require('./client-overlay')({
ansiColors: options.ansiColors,
overlayStyles: options.overlayStyles
});
}
var styles = {
errors: "color: #ff0000;",
warnings: "color: #999933;"
};
var previousProblems = null;
function log(type, obj) {
var newProblems = obj[type].map(function(msg) { return strip(msg); }).join('\n');
if (previousProblems == newProblems) {
return;
} else {
previousProblems = newProblems;
}
var style = styles[type];
var name = obj.name ? "'" + obj.name + "' " : "";
var title = "[HMR] bundle " + name + "has " + obj[type].length + " " + type;
// NOTE: console.warn or console.error will print the stack trace
// which isn't helpful here, so using console.log to escape it.
if (console.group && console.groupEnd) {
console.group("%c" + title, style);
console.log("%c" + newProblems, style);
console.groupEnd();
} else {
console.log(
"%c" + title + "\n\t%c" + newProblems.replace(/\n/g, "\n\t"),
style + "font-weight: bold;",
style + "font-weight: normal;"
);
}
}
return {
cleanProblemsCache: function () {
previousProblems = null;
},
problems: function(type, obj) {
if (options.warn) {
log(type, obj);
}
if (overlay) {
if (options.overlayWarnings || type === 'errors') {
overlay.showProblems(type, obj[type]);
return false;
}
overlay.clear();
}
return true;
},
success: function() {
if (overlay) overlay.clear();
},
useCustomOverlay: function(customOverlay) {
overlay = customOverlay;
}
};
}
var processUpdate = require('./process-update');
var customHandler;
var subscribeAllHandler;
function processMessage(obj) {
switch(obj.action) {
case "building":
if (options.log) {
console.log(
"[HMR] bundle " + (obj.name ? "'" + obj.name + "' " : "") +
"rebuilding"
);
}
break;
case "built":
if (options.log) {
console.log(
"[HMR] bundle " + (obj.name ? "'" + obj.name + "' " : "") +
"rebuilt in " + obj.time + "ms"
);
}
// fall through
case "sync":
if (obj.name && options.name && obj.name !== options.name) {
return;
}
var applyUpdate = true;
if (obj.errors.length > 0) {
if (reporter) reporter.problems('errors', obj);
applyUpdate = false;
} else if (obj.warnings.length > 0) {
if (reporter) {
var overlayShown = reporter.problems('warnings', obj);
applyUpdate = overlayShown;
}
} else {
if (reporter) {
reporter.cleanProblemsCache();
reporter.success();
}
}
if (applyUpdate) {
processUpdate(obj.hash, obj.modules, options);
}
break;
default:
if (customHandler) {
customHandler(obj);
}
}
if (subscribeAllHandler) {
subscribeAllHandler(obj);
}
}
if (module) {
module.exports = {
subscribeAll: function subscribeAll(handler) {
subscribeAllHandler = handler;
},
subscribe: function subscribe(handler) {
customHandler = handler;
},
useCustomOverlay: function useCustomOverlay(customOverlay) {
if (reporter) reporter.useCustomOverlay(customOverlay);
},
setOptionsAndConnect: setOptionsAndConnect
};
}
@rlamana
Copy link
Author

rlamana commented Nov 3, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment