'use strict'; // The error overlay is inspired (and mostly copied) from Create React App (https://github.com/facebookincubator/create-react-app) // They, in turn, got inspired by webpack-hot-middleware (https://github.com/glenjamin/webpack-hot-middleware). // For Humus, it's ripped from webpack-dev-server (https://github.com/webpack/webpack-dev-server/blob/master/client-src/default/overlay.js). const ansiHTML = require('ansi-html'); const Entities = require('html-entities').AllHtmlEntities; const entities = new Entities(); const 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) { const iframe = document.createElement('iframe'); iframe.id = 'humus-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) { const div = iframe.contentDocument.createElement('div'); div.id = 'humus-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 = 'rgba(0, 0, 0, 0.85)'; 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; } let overlayIframe = null; let overlayDiv = null; let 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(() => { 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); } exports.formatErrorMessage = function formatErrorMessage(error) { const stack = error.stack; let message = ''; const lines = stack.split('\n'); const [errorType, ...errorMessage] = lines.shift().split(': '); message += formatErrorPrologue(errorType, errorMessage.join('')); while (lines.length > 0) { const [at, fn, location] = lines.shift().trim().split(' '); message += formatErrorAt(); message += formatErrorFn(fn); message += formatErrorLocation(location); message += '
'; } return message; } function sanitize(message) { return ansiHTML(entities.encode(message)); } function formatErrorPrologue(type, message) { return `${sanitize(type)}: ${sanitize(message)}

`; } function formatErrorAt() { return '  at '; } function formatErrorFn(fn) { return `${sanitize(fn)} `; } function formatErrorLocation(location) { return `${sanitize(location.replace( 'webpack-internal:///./', '' ).replace( 'webpack-internal:///', '' ))}`; } function formatMessage(message) { if (!(message instanceof Error)) { return sanitize(message); } return exports.formatErrorMessage(message); } function showMessageOverlay(message) { ensureOverlayDivExists((div) => { // Make it look similar to our terminal. div.innerHTML = formatMessage(message); }); } function destroyErrorOverlay() { if (!overlayDiv) { // It is not there in the first place. return; } // Clean up and reset internal state. document.body.removeChild(overlayIframe); overlayDiv = null; overlayIframe = null; lastOnOverlayDivReady = null; } // Successful compilation. exports.clear = function handleSuccess() { destroyErrorOverlay(); }; // Compilation with errors (e.g. syntax error or missing modules). exports.showMessage = function handleMessage(message) { showMessageOverlay(message); };