webpackHotDevClient.js 8.12 KiB
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
// This alternative WebpackDevServer combines the functionality of:
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
// It only supports their simplest configuration (hot updates on same server).
// It makes some opinionated choices on top, like adding a syntax error overlay
// that looks similar to our console output. The error overlay is inspired by:
// https://github.com/glenjamin/webpack-hot-middleware
var ansiHTML = require('ansi-html');
var SockJS = require('sockjs-client');
var stripAnsi = require('strip-ansi');
var url = require('url');
var formatWebpackMessages = require('./formatWebpackMessages');
var Entities = require('html-entities').AllHtmlEntities;
var entities = new Entities();
// Color scheme inspired by https://github.com/glenjamin/webpack-hot-middleware
var colors = {
  reset: ['transparent', 'transparent'],
  black: '181818',
  red: 'E36049',
  green: 'B3CB74',
  yellow: 'FFD080',
  blue: '7CAFC2',
  magenta: '7FACCA',
  cyan: 'C3C2EF',
  lightgrey: 'EBE7E3',
  darkgrey: '6D7891'
ansiHTML.setColors(colors);
function createOverlayIframe(onIframeLoad) {
  var iframe = document.createElement('iframe');
  iframe.id = 'react-dev-utils-webpack-hot-dev-client-overlay';
  iframe.src = 'about:blank';
  iframe.style.position = 'fixed';
  iframe.style.left = 0;
  iframe.style.top = 0;
  iframe.style.right = 0;
  iframe.style.bottom = 0;
  iframe.style.width = '100vw';
  iframe.style.height = '100vh';
  iframe.style.border = 'none';
  iframe.style.zIndex = 9999999999;
  iframe.onload = onIframeLoad;
  return iframe;
function addOverlayDivTo(iframe) {
  var div =  iframe.contentDocument.createElement('div');
  div.id = 'react-dev-utils-webpack-hot-dev-client-overlay-div';
  div.style.position = 'fixed';
  div.style.boxSizing = 'border-box';
  div.style.left = 0;
  div.style.top = 0;
  div.style.right = 0;
  div.style.bottom = 0;
  div.style.width = '100vw';
  div.style.height = '100vh';
  div.style.backgroundColor = 'black';
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
div.style.color = '#E8E8E8'; div.style.fontFamily = 'Menlo, Consolas, monospace'; div.style.fontSize = 'large'; div.style.padding = '2rem'; div.style.lineHeight = '1.2'; div.style.whiteSpace = 'pre-wrap'; div.style.overflow = 'auto'; iframe.contentDocument.body.appendChild(div); return div; } var overlayIframe = null; var overlayDiv = null; var lastOnOverlayDivReady = null; function ensureOverlayDivExists(onOverlayDivReady) { if (overlayDiv) { // Everything is ready, call the callback right away. onOverlayDivReady(overlayDiv); return; } // Creating an iframe may be asynchronous so we'll schedule the callback. // In case of multiple calls, last callback wins. lastOnOverlayDivReady = onOverlayDivReady; if (overlayIframe) { // We're already creating it. return; } // Create iframe and, when it is ready, a div inside it. overlayIframe = createOverlayIframe(function onIframeLoad() { overlayDiv = addOverlayDivTo(overlayIframe); // Now we can talk! lastOnOverlayDivReady(overlayDiv); }); // Zalgo alert: onIframeLoad() will be called either synchronously // or asynchronously depending on the browser. // We delay adding it so `overlayIframe` is set when `onIframeLoad` fires. document.body.appendChild(overlayIframe); } function showErrorOverlay(message) { ensureOverlayDivExists(function onOverlayDivReady(overlayDiv) { // Make it look similar to our terminal. overlayDiv.innerHTML = '<span style="color: #' + colors.red + '">Failed to compile.</span><br><br>' + ansiHTML(entities.encode(message)); }); } // Connect to WebpackDevServer via a socket. var connection = new SockJS(url.format({ protocol: window.location.protocol, hostname: window.location.hostname, port: window.location.port, // Hardcoded in WebpackDevServer pathname: '/sockjs-node' })); // Unlike WebpackDevServer client, we won't try to reconnect // to avoid spamming the console. Disconnect usually happens // when developer stops the server. connection.onclose = function() { console.info( 'The development server has disconnected.\nRefresh the page if necessary.'
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
); }; // Remember some state related to hot module replacement. var isFirstCompilation = true; var mostRecentCompilationHash = null; var hasCompileErrors = false; function clearOutdatedErrors() { // Clean up outdated compile errors, if any. if (hasCompileErrors && typeof console.clear === 'function') { console.clear(); } } // Successful compilation. function handleSuccess() { clearOutdatedErrors(); var isHotUpdate = !isFirstCompilation; isFirstCompilation = false; hasCompileErrors = false; // Attempt to apply hot updates or reload. if (isHotUpdate) { tryApplyUpdates(); } } // Compilation with warnings (e.g. ESLint). function handleWarnings(warnings) { clearOutdatedErrors(); var isHotUpdate = !isFirstCompilation; isFirstCompilation = false; hasCompileErrors = false; function printWarnings() { // Print warnings to the console. for (var i = 0; i < warnings.length; i++) { console.warn(stripAnsi(warnings[i])); } } // Attempt to apply hot updates or reload. if (isHotUpdate) { tryApplyUpdates(function onSuccessfulHotUpdate() { // Only print warnings if we aren't refreshing the page. // Otherwise they'll disappear right away anyway. printWarnings(); }); } else { // Print initial warnings immediately. printWarnings(); } } // Compilation with errors (e.g. syntax error or missing modules). function handleErrors(errors) { clearOutdatedErrors(); isFirstCompilation = false; hasCompileErrors = true; // "Massage" webpack messages. var formatted = formatWebpackMessages({ errors: errors, warnings: [] });
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
// Only show the first error. showErrorOverlay(formatted.errors[0]); // Also log them to the console. for (var i = 0; i < formatted.errors.length; i++) { console.error(stripAnsi(formatted.errors[i])); } // Do not attempt to reload now. // We will reload on next success instead. } // There is a newer version of the code available. function handleAvailableHash(hash) { // Update last known compilation hash. mostRecentCompilationHash = hash; } // Handle messages from the server. connection.onmessage = function(e) { var message = JSON.parse(e.data); switch (message.type) { case 'hash': handleAvailableHash(message.data); break; case 'ok': handleSuccess(); break; case 'warnings': handleWarnings(message.data); break; case 'errors': handleErrors(message.data); break; default: // Do nothing. } } // Is there a newer version of this code available? function isUpdateAvailable() { /* globals __webpack_hash__ */ // __webpack_hash__ is the hash of the current compilation. // It's a global variable injected by Webpack. return mostRecentCompilationHash !== __webpack_hash__; } // Webpack disallows updates in other states. function canApplyUpdates() { return module.hot.status() === 'idle'; } // Attempt to update code on the fly, fall back to a hard reload. function tryApplyUpdates(onHotUpdateSuccess) { if (!module.hot) { // HotModuleReplacementPlugin is not in Webpack configuration. window.location.reload(); return; } if (!isUpdateAvailable() || !canApplyUpdates()) { return; } // https://webpack.github.io/docs/hot-module-replacement.html#check module.hot.check(/* autoApply */true, function(err, updatedModules) { if (err || !updatedModules) { window.location.reload(); return; }
281282283284285286287288289290291292293
if (typeof onHotUpdateSuccess === 'function') { // Maybe we want to do something. onHotUpdateSuccess(); } if (isUpdateAvailable()) { // While we were updating, there was a new update! Do it again. tryApplyUpdates(); } }); };