diff --git a/packages/react-dev-utils/ansiHTML.js b/packages/react-dev-utils/ansiHTML.js
new file mode 100644
index 00000000000..27a514e01d0
--- /dev/null
+++ b/packages/react-dev-utils/ansiHTML.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var Anser = require('anser');
+
+// Color scheme inspired by https://chriskempson.github.io/base16/css/base16-github.css
+// var base00 = 'ffffff'; // Default Background
+var base01 = 'f5f5f5'; // Lighter Background (Used for status bars)
+// var base02 = 'c8c8fa'; // Selection Background
+var base03 = '969896'; // Comments, Invisibles, Line Highlighting
+// var base04 = 'e8e8e8'; // Dark Foreground (Used for status bars)
+var base05 = '333333'; // Default Foreground, Caret, Delimiters, Operators
+// var base06 = 'ffffff'; // Light Foreground (Not often used)
+// var base07 = 'ffffff'; // Light Background (Not often used)
+var base08 = 'ed6a43'; // Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
+// var base09 = '0086b3'; // Integers, Boolean, Constants, XML Attributes, Markup Link Url
+// var base0A = '795da3'; // Classes, Markup Bold, Search Text Background
+var base0B = '183691'; // Strings, Inherited Class, Markup Code, Diff Inserted
+var base0C = '183691'; // Support, Regular Expressions, Escape Characters, Markup Quotes
+// var base0D = '795da3'; // Functions, Methods, Attribute IDs, Headings
+var base0E = 'a71d5d'; // Keywords, Storage, Selector, Markup Italic, Diff Changed
+// var base0F = '333333'; // Deprecated, Opening/Closing Embedded Language Tags e.g.
+
+// Map ANSI colors from what babel-code-frame uses to base16-github
+// See: https://github.com/babel/babel/blob/e86f62b304d280d0bab52c38d61842b853848ba6/packages/babel-code-frame/src/index.js#L9-L22
+var colors = {
+ reset: [base05, 'transparent'],
+ black: base05,
+ red: base08, /* marker, bg-invalid */
+ green: base0B, /* string */
+ yellow: base08, /* capitalized, jsx_tag, punctuator */
+ blue: base0C,
+ magenta: base0C, /* regex */
+ cyan: base0E, /* keyword */
+ gray: base03, /* comment, gutter */
+ lightgrey: base01,
+ darkgrey: base03
+};
+
+var anserMap = {
+ 'ansi-bright-black': 'black',
+ 'ansi-bright-yellow': 'yellow',
+ 'ansi-yellow': 'yellow',
+ 'ansi-bright-green': 'green',
+ 'ansi-green': 'green',
+ 'ansi-bright-cyan': 'cyan',
+ 'ansi-cyan': 'cyan',
+ 'ansi-bright-red': 'red',
+ 'ansi-red': 'red',
+ 'ansi-bright-magenta': 'magenta',
+ 'ansi-magenta': 'magenta'
+};
+
+function ansiHTML(txt) {
+ var arr = new Anser().ansiToJson(txt, {
+ use_classes: true
+ });
+
+ var result = '';
+ var open = false;
+ for (var index = 0; index < arr.length; ++index) {
+ var c = arr[index];
+ var content = c.content,
+ fg = c.fg;
+
+ var contentParts = content.split('\n');
+ for (var _index = 0; _index < contentParts.length; ++_index) {
+ if (!open) {
+ result += '';
+ open = true;
+ }
+ var part = contentParts[_index].replace('\r', '');
+ var color = colors[anserMap[fg]];
+ if (color != null) {
+ result += '' + part + '';
+ } else {
+ if (fg != null) console.log('Missing color mapping: ', fg);
+ result += '' + part + '';
+ }
+ if (_index < contentParts.length - 1) {
+ result += '';
+ open = false;
+ result += '
';
+ }
+ }
+ }
+ if (open) {
+ result += '';
+ open = false;
+ }
+ return result;
+}
+
+module.exports = ansiHTML;
diff --git a/packages/react-dev-utils/crashOverlay.js b/packages/react-dev-utils/crashOverlay.js
new file mode 100644
index 00000000000..d92e793ac18
--- /dev/null
+++ b/packages/react-dev-utils/crashOverlay.js
@@ -0,0 +1,831 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var codeFrame = require('babel-code-frame');
+var ansiHTML = require('./ansiHTML');
+var StackTraceResolve = require('stack-frame-resolver').default;
+
+var CONTEXT_SIZE = 3;
+
+var black = '#293238';
+var darkGray = '#878e91';
+var lightGray = '#fafafa';
+var red = '#ce1126';
+var lightRed = '#fccfcf';
+var yellow = '#fbf5b4';
+
+function getHead() {
+ return document.head || document.getElementsByTagName('head')[0];
+}
+
+var injectedCss = [];
+
+// From: http://stackoverflow.com/a/524721/127629
+function injectCss(css) {
+ var head = getHead();
+ var style = document.createElement('style');
+
+ style.type = 'text/css';
+ if (style.styleSheet) {
+ style.styleSheet.cssText = css;
+ } else {
+ style.appendChild(document.createTextNode(css));
+ }
+
+ head.appendChild(style);
+ injectedCss.push(style);
+}
+
+var css = [
+ '.cra-container {',
+ ' padding-right: 15px;',
+ ' padding-left: 15px;',
+ ' margin-right: auto;',
+ ' margin-left: auto;',
+ '}',
+ '',
+ '@media (min-width: 768px) {',
+ ' .cra-container {',
+ ' width: calc(750px - 6em);',
+ ' }',
+ '}',
+ '',
+ '@media (min-width: 992px) {',
+ ' .cra-container {',
+ ' width: calc(970px - 6em);',
+ ' }',
+ '}',
+ '',
+ '@media (min-width: 1200px) {',
+ ' .cra-container {',
+ ' width: calc(1170px - 6em);',
+ ' }',
+ '}'
+].join('\n');
+
+var overlayStyle = {
+ position: 'fixed',
+ 'box-sizing': 'border-box',
+ top: '1em', left: '1em',
+ bottom: '1em', right: '1em',
+ width: 'calc(100% - 2em)', height: 'calc(100% - 2em)',
+ 'border-radius': '3px',
+ 'background-color': lightGray,
+ padding: '4rem',
+ 'z-index': 1337,
+ 'font-family': 'Consolas, Menlo, monospace',
+ color: black,
+ 'white-space': 'pre-wrap',
+ overflow: 'auto',
+ 'overflow-x': 'hidden',
+ 'word-break': 'break-all',
+ 'box-shadow': '0 0 6px 0 rgba(0, 0, 0, 0.5)',
+ 'line-height': 1.5
+};
+
+var hintsStyle = {
+ 'font-size': '0.8em',
+ 'margin-top': '-3em',
+ 'margin-bottom': '3em',
+ 'text-align': 'right',
+ color: darkGray
+};
+
+var hintStyle = {
+ padding: '0.5em 1em',
+ cursor: 'pointer'
+};
+
+var closeButtonStyle = {
+ 'font-size': '26px',
+ color: black,
+ padding: '0.5em 1em',
+ cursor: 'pointer',
+ position: 'absolute',
+ right: 0,
+ top: 0
+};
+
+var additionalStyle = {
+ 'margin-bottom': '1.5em',
+ 'margin-top': '-4em'
+};
+
+var headerStyle = {
+ 'font-size': '1.7em',
+ 'font-weight': 'bold',
+ color: red
+};
+
+var functionNameStyle = {
+ 'margin-top': '1em',
+ 'font-size': '1.2em'
+};
+
+var linkStyle = {
+ 'font-size': '0.9em'
+};
+
+var anchorStyle = {
+ 'text-decoration': 'none',
+ color: darkGray
+};
+
+var traceStyle = {
+ 'font-size': '1em'
+};
+
+var depStyle = {
+ 'font-size': '1.2em'
+};
+
+var primaryErrorStyle = {
+ 'background-color': lightRed
+};
+
+var secondaryErrorStyle = {
+ 'background-color': yellow
+};
+
+var omittedFramesStyle = {
+ color: black,
+ 'font-size': '0.9em',
+ 'margin': '1.5em 0',
+ cursor: 'pointer'
+};
+
+var preStyle = {
+ display: 'block',
+ padding: '0.5em',
+ 'margin-top': '1.5em',
+ 'margin-bottom': '0px',
+ 'overflow-x': 'auto',
+ 'font-size': '1.1em',
+ 'white-space': 'pre'
+};
+
+var toggleStyle = {
+ 'margin-bottom': '1.5em',
+ color: darkGray,
+ cursor: 'pointer'
+};
+
+var codeStyle = {
+ 'font-family': 'Consolas, Menlo, monospace'
+};
+
+var hiddenStyle = {
+ display: 'none'
+};
+
+var groupStyle = {
+ 'margin-left': '1em'
+};
+
+var _groupElemStyle = {
+ 'background-color': 'inherit',
+ 'border-color': '#ddd',
+ 'border-width': '1px',
+ 'border-radius': '4px',
+ 'border-style': 'solid',
+ padding: '3px 6px',
+ cursor: 'pointer'
+};
+
+var groupElemLeft = Object.assign({}, _groupElemStyle, {
+ 'border-top-right-radius': '0px',
+ 'border-bottom-right-radius': '0px',
+ 'margin-right': '0px'
+});
+
+var groupElemRight = Object.assign({}, _groupElemStyle, {
+ 'border-top-left-radius': '0px',
+ 'border-bottom-left-radius': '0px',
+ 'margin-left': '-1px'
+});
+
+var footerStyle = {
+ 'text-align': 'center',
+ color: darkGray
+};
+
+function applyStyles(element, styles) {
+ element.setAttribute('style', '');
+ // Firefox can't handle const due to non-compliant implementation
+ // Revisit Jan 2016
+ // https://developer.mozilla.org/en-US/Firefox/Releases/51#JavaScript
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1101653
+ for (var key in styles) {
+ if (!styles.hasOwnProperty(key)) continue;
+ var val = styles[key];
+ if (typeof val === 'function') val = val();
+ element.style[key] = val.toString();
+ }
+}
+
+var overlayReference = null;
+var additionalReference = null;
+var capturedErrors = [];
+var viewIndex = -1;
+var frameSettings = [];
+
+function consumeEvent(e) {
+ e.preventDefault();
+ e.target.blur();
+}
+
+function accessify(node) {
+ node.setAttribute('tabindex', 0);
+ node.addEventListener('keydown', function (e) {
+ var key = e.key,
+ which = e.which,
+ keyCode = e.keyCode;
+ if (key === 'Enter' || which === 13 || keyCode === 13) {
+ e.preventDefault();
+ e.target.click();
+ }
+ });
+}
+
+function renderAdditional() {
+ if (additionalReference.lastChild) {
+ additionalReference.removeChild(additionalReference.lastChild);
+ }
+
+ var text = ' ';
+ if (capturedErrors.length <= 1) {
+ additionalReference.appendChild(document.createTextNode(text));
+ return;
+ }
+ text = 'Errors ' + (viewIndex + 1) + ' of ' + capturedErrors.length;
+ var span = document.createElement('span');
+ span.appendChild(document.createTextNode(text));
+ var group = document.createElement('span');
+ applyStyles(group, groupStyle);
+ var left = document.createElement('button');
+ applyStyles(left, groupElemLeft);
+ left.addEventListener('click', function (e) {
+ consumeEvent(e);
+ switchError(-1);
+ });
+ left.appendChild(document.createTextNode('←'));
+ accessify(left);
+ var right = document.createElement('button');
+ applyStyles(right, groupElemRight);
+ right.addEventListener('click', function (e) {
+ consumeEvent(e);
+ switchError(1);
+ });
+ right.appendChild(document.createTextNode('→'));
+ accessify(right);
+ group.appendChild(left);
+ group.appendChild(right);
+ span.appendChild(group);
+ additionalReference.appendChild(span);
+}
+
+function removeNextBr(parent, component) {
+ while (component != null && component.tagName.toLowerCase() !== 'br') {
+ component = component.nextSibling;
+ }
+ if (component != null) {
+ parent.removeChild(component);
+ }
+}
+
+function absolutifyCode(component) {
+ var ccn = component.childNodes;
+ for (var index = 0; index < ccn.length; ++index) {
+ var c = ccn[index];
+ if (c.tagName.toLowerCase() !== 'span') continue;
+ var text = c.innerText.replace(/\s/g, '');
+ if (text !== '|^') continue;
+ c.style.position = 'absolute';
+ removeNextBr(component, c);
+ }
+}
+
+function sourceCodePre(sourceLines, lineNum, columnNum) {
+ var main = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
+
+ var sourceCode = [];
+ var whiteSpace = Infinity;
+ sourceLines.forEach(function (_ref2) {
+ var text = _ref2.text;
+
+ var m = text.match(/^\s*/);
+ if (text === '') return;
+ if (m && m[0]) {
+ whiteSpace = Math.min(whiteSpace, m[0].length);
+ } else {
+ whiteSpace = 0;
+ }
+ });
+ sourceLines.forEach(function (_ref3) {
+ var text = _ref3.text,
+ line = _ref3.line;
+
+ if (isFinite(whiteSpace)) text = text.substring(whiteSpace);
+ sourceCode[line - 1] = text;
+ });
+ sourceCode = sourceCode.join('\n');
+ var ansiHighlight = codeFrame(sourceCode, lineNum, columnNum - (isFinite(whiteSpace) ? whiteSpace : 0), {
+ forceColor: true,
+ linesAbove: CONTEXT_SIZE,
+ linesBelow: CONTEXT_SIZE
+ });
+ var htmlHighlight = ansiHTML(ansiHighlight);
+ var code = document.createElement('code');
+ code.innerHTML = htmlHighlight;
+ absolutifyCode(code);
+ applyStyles(code, codeStyle);
+
+ var ccn = code.childNodes;
+ for (var index = 0; index < ccn.length; ++index) {
+ var node = ccn[index];
+ var breakOut = false;
+ var ccn2 = node.childNodes;
+ for (var index2 = 0; index2 < ccn2.length; ++index2) {
+ var lineNode = ccn2[index2];
+ if (lineNode.innerText.indexOf(' ' + lineNum + ' |') === -1) continue;
+ applyStyles(node, main ? primaryErrorStyle : secondaryErrorStyle);
+ breakOut = true;
+ }
+ if (breakOut) break;
+ }
+ var pre = document.createElement('pre');
+ applyStyles(pre, preStyle);
+ pre.appendChild(code);
+ return pre;
+}
+
+function createHint(hint) {
+ var span = document.createElement('span');
+ span.appendChild(document.createTextNode(hint));
+ applyStyles(span, hintStyle);
+ return span;
+}
+
+function hintsDiv() {
+ var hints = document.createElement('div');
+ applyStyles(hints, hintsStyle);
+
+ var close = createHint('×');
+ close.addEventListener('click', function () {
+ unmount();
+ });
+ applyStyles(close, closeButtonStyle);
+ hints.appendChild(close);
+ return hints;
+}
+
+function frameDiv(functionName, url, internalUrl) {
+ var frame = document.createElement('div');
+ var frameFunctionName = document.createElement('div');
+
+ var cleanedFunctionName = void 0;
+ if (!functionName || functionName === 'Object.') {
+ cleanedFunctionName = '(anonymous function)';
+ } else {
+ cleanedFunctionName = functionName;
+ }
+
+ var cleanedUrl = url.replace('webpack://', '.');
+
+ if (internalUrl) {
+ applyStyles(frameFunctionName, Object.assign({}, functionNameStyle, depStyle));
+ } else {
+ applyStyles(frameFunctionName, functionNameStyle);
+ }
+
+ frameFunctionName.appendChild(document.createTextNode(cleanedFunctionName));
+ frame.appendChild(frameFunctionName);
+
+ var frameLink = document.createElement('div');
+ applyStyles(frameLink, linkStyle);
+ var frameAnchor = document.createElement('a');
+ applyStyles(frameAnchor, anchorStyle);
+ //frameAnchor.href = url
+ frameAnchor.appendChild(document.createTextNode(cleanedUrl));
+ frameLink.appendChild(frameAnchor);
+ frame.appendChild(frameLink);
+
+ return frame;
+}
+
+function getGroupToggle(omitsCount, omitBundle) {
+ var omittedFrames = document.createElement('div');
+ accessify(omittedFrames);
+ var text1 = document.createTextNode('\u25B6 ' + omitsCount + ' stack frames were collapsed.');
+ omittedFrames.appendChild(text1);
+ omittedFrames.addEventListener('click', function () {
+ var hide = text1.textContent.match(/▲/);
+ var list = document.getElementsByName('bundle-' + omitBundle);
+ for (var index = 0; index < list.length; ++index) {
+ var n = list[index];
+ if (hide) {
+ n.style.display = 'none';
+ } else {
+ n.style.display = '';
+ }
+ }
+ if (hide) {
+ text1.textContent = text1.textContent.replace(/▲/, '▶');
+ text1.textContent = text1.textContent.replace(/expanded/, 'collapsed');
+ } else {
+ text1.textContent = text1.textContent.replace(/▶/, '▲');
+ text1.textContent = text1.textContent.replace(/collapsed/, 'expanded');
+ }
+ });
+ applyStyles(omittedFrames, omittedFramesStyle);
+ return omittedFrames;
+}
+
+function insertBeforeBundle(parent, omitsCount, omitBundle, actionElement) {
+ var children = document.getElementsByName('bundle-' + omitBundle);
+ if (children.length < 1) return;
+ var first = children[0];
+ while (first.parentNode !== parent) {
+ first = first.parentNode;
+ }
+ var div = document.createElement('div');
+ accessify(div);
+ div.setAttribute('name', 'bundle-' + omitBundle);
+ var text = document.createTextNode('\u25BC ' + omitsCount + ' stack frames were expanded.');
+ div.appendChild(text);
+ div.addEventListener('click', function () {
+ return actionElement.click();
+ });
+ applyStyles(div, omittedFramesStyle);
+ div.style.display = 'none';
+
+ parent.insertBefore(div, first);
+}
+
+function traceFrame(frameSetting, frame, critical, omits, omitBundle, parentContainer, lastElement) {
+ var compiled = frameSetting.compiled;
+ var functionName = frame.functionName,
+ fileName = frame.fileName,
+ lineNumber = frame.lineNumber,
+ columnNumber = frame.columnNumber,
+ scriptLines = frame.scriptLines,
+ sourceFileName = frame.sourceFileName,
+ sourceLineNumber = frame.sourceLineNumber,
+ sourceColumnNumber = frame.sourceColumnNumber,
+ sourceLines = frame.sourceLines;
+
+ var url = void 0;
+ if (!compiled && sourceFileName) {
+ url = sourceFileName + ':' + sourceLineNumber;
+ if (sourceColumnNumber) url += ':' + sourceColumnNumber;
+ } else {
+ url = fileName + ':' + lineNumber;
+ if (columnNumber) url += ':' + columnNumber;
+ }
+
+ var needsHidden = false;
+ var internalUrl = isInternalFile(url, sourceFileName);
+ if (internalUrl) {
+ ++omits.value;
+ needsHidden = true;
+ }
+ var collapseElement = null;
+ if (!internalUrl || lastElement) {
+ if (omits.value > 0) {
+ var omittedFrames = getGroupToggle(omits.value, omitBundle);
+ setTimeout(function () {
+ insertBeforeBundle.apply(undefined, arguments);
+ }.bind(undefined, parentContainer, omits.value, omitBundle, omittedFrames), 1);
+ if (lastElement && internalUrl) {
+ collapseElement = omittedFrames;
+ } else {
+ parentContainer.appendChild(omittedFrames);
+ }
+ ++omits.bundle;
+ }
+ omits.value = 0;
+ }
+
+ var elem = frameDiv(functionName, url, internalUrl);
+ if (needsHidden) {
+ applyStyles(elem, hiddenStyle);
+ elem.setAttribute('name', 'bundle-' + omitBundle);
+ }
+
+ var hasSource = false;
+ if (!internalUrl) {
+ if (compiled && scriptLines.length !== 0) {
+ elem.appendChild(sourceCodePre(scriptLines, lineNumber, columnNumber, critical));
+ hasSource = true;
+ } else if (!compiled && sourceLines.length !== 0) {
+ elem.appendChild(sourceCodePre(sourceLines, sourceLineNumber, sourceColumnNumber, critical));
+ hasSource = true;
+ }
+ }
+
+ return { elem: elem, hasSource: hasSource, collapseElement: collapseElement };
+}
+
+function lazyFrame(parent, factory, lIndex) {
+ var fac = factory();
+ if (fac == null) return;
+ var hasSource = fac.hasSource,
+ elem = fac.elem,
+ collapseElement = fac.collapseElement;
+
+ var elemWrapper = document.createElement('div');
+ elemWrapper.appendChild(elem);
+
+ if (hasSource) {
+ (function () {
+ var compiledDiv = document.createElement('div');
+ accessify(compiledDiv);
+ applyStyles(compiledDiv, toggleStyle);
+
+ var o = frameSettings[lIndex];
+ var compiledText = document.createTextNode('View ' + (o && o.compiled ? 'source' : 'compiled'));
+ compiledDiv.addEventListener('click', function () {
+ if (o) o.compiled = !o.compiled;
+
+ var next = lazyFrame(parent, factory, lIndex);
+ if (next != null) {
+ parent.insertBefore(next, elemWrapper);
+ parent.removeChild(elemWrapper);
+ }
+ });
+ compiledDiv.appendChild(compiledText);
+ elemWrapper.appendChild(compiledDiv);
+ })();
+ }
+
+ if (collapseElement != null) {
+ elemWrapper.appendChild(collapseElement);
+ }
+
+ return elemWrapper;
+}
+
+function traceDiv(resolvedFrames) {
+ var trace = document.createElement('div');
+ applyStyles(trace, traceStyle);
+
+ var index = 0;
+ var critical = true;
+ var omits = { value: 0, bundle: 1 };
+ resolvedFrames.forEach(function (frame) {
+ var lIndex = index++;
+ var elem = lazyFrame(trace, traceFrame.bind(undefined, frameSettings[lIndex], frame, critical, omits, omits.bundle, trace, index === resolvedFrames.length), lIndex);
+ if (elem == null) return;
+ critical = false;
+ trace.appendChild(elem);
+ });
+ //TODO: fix this
+ omits.value = 0;
+
+ return trace;
+}
+
+function footer() {
+ var div = document.createElement('div');
+ applyStyles(div, footerStyle);
+ div.appendChild(document.createTextNode('This screen is visible only in development. It will not appear when the app crashes in production.'));
+ div.appendChild(document.createElement('br'));
+ div.appendChild(document.createTextNode('Open your browser’s developer console to further inspect this error.'));
+ return div;
+}
+
+function render(error, name, message, resolvedFrames) {
+ dispose();
+
+ frameSettings = resolvedFrames.map(function () {
+ return { compiled: false };
+ });
+
+ injectCss(css);
+
+ // Create overlay
+ var overlay = document.createElement('div');
+ applyStyles(overlay, overlayStyle);
+ overlay.appendChild(hintsDiv());
+
+ // Create container
+ var container = document.createElement('div');
+ container.className = 'cra-container';
+ overlay.appendChild(container);
+
+ // Create additional
+ additionalReference = document.createElement('div');
+ applyStyles(additionalReference, additionalStyle);
+ container.appendChild(additionalReference);
+ renderAdditional();
+
+ // Create header
+ var header = document.createElement('div');
+ applyStyles(header, headerStyle);
+ if (message.match(/^\w*:/)) {
+ header.appendChild(document.createTextNode(message));
+ } else {
+ header.appendChild(document.createTextNode(name + ': ' + message));
+ }
+ container.appendChild(header);
+
+ // Create trace
+ container.appendChild(traceDiv(resolvedFrames));
+
+ // Show message
+ container.appendChild(footer());
+
+ // Mount
+ document.body.appendChild(overlayReference = overlay);
+}
+
+function dispose() {
+ if (overlayReference === null) return;
+ document.body.removeChild(overlayReference);
+ overlayReference = null;
+ var head = getHead();
+ injectedCss.forEach(function (node) {
+ head.removeChild(node);
+ });
+ injectedCss = [];
+}
+
+function unmount() {
+ dispose();
+ capturedErrors = [];
+ viewIndex = -1;
+}
+
+function isInternalFile(url, sourceFileName) {
+ return url.indexOf('/~/') !== -1 || url.trim().indexOf(' ') !== -1 || !sourceFileName;
+}
+
+function renderError(index) {
+ viewIndex = index;
+ var _capturedErrors$index = capturedErrors[index],
+ error = _capturedErrors$index.error,
+ unhandledRejection = _capturedErrors$index.unhandledRejection,
+ resolvedFrames = _capturedErrors$index.resolvedFrames;
+
+ if (unhandledRejection) {
+ render(error, 'Unhandled Rejection (' + error.name + ')', error.message, resolvedFrames);
+ } else {
+ render(error, error.name, error.message, resolvedFrames);
+ }
+}
+
+function crash(error) {
+ var unhandledRejection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+ var sourceOverrides = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
+
+ if (module.hot) module.hot.decline();
+
+ StackTraceResolve(error, CONTEXT_SIZE).then(function (resolvedFrames) {
+ resolvedFrames = resolvedFrames.filter(function (_ref) {
+ var functionName = _ref.functionName;
+ return functionName.indexOf('__cra_proxy_console__') === -1;
+ });
+ var overrideCount = sourceOverrides.length,
+ frameCount = resolvedFrames.length;
+ var frameIndex = 0;
+ for (var overrideIndex = 0; overrideIndex < overrideCount; ++overrideIndex) {
+ var tag = sourceOverrides[overrideIndex];
+ var shouldContinue = false;
+ for (; frameIndex < frameCount; ++frameIndex) {
+ var sourceFileName = resolvedFrames[frameIndex].sourceFileName;
+
+ if (sourceFileName == null) continue;
+ if (sourceFileName.indexOf('/' + tag.file) !== -1) {
+ var prevLineNumber = resolvedFrames[frameIndex].sourceLineNumber;
+ if (Math.abs(prevLineNumber - tag.lineNum) < CONTEXT_SIZE) {
+ resolvedFrames[frameIndex].sourceLineNumber = tag.lineNum;
+ }
+ shouldContinue = true;
+ break;
+ }
+ }
+ if (shouldContinue) continue;
+ break;
+ }
+ capturedErrors.push({ error: error, unhandledRejection: unhandledRejection, resolvedFrames: resolvedFrames });
+ if (overlayReference !== null) renderAdditional();
+ else {
+ renderError(viewIndex = 0);
+ }
+ }).catch(function (e) {
+ // This is another fail case (unlikely to happen)
+ // e.g. render(...) throws an error with provided arguments
+ console.log('Red box renderer error:', e);
+ unmount();
+ render(null, 'Error', 'There is an error with red box. *Please* report this (see console).', []);
+ });
+}
+
+function switchError(offset) {
+ try {
+ var nextView = viewIndex + offset;
+ if (nextView < 0 || nextView >= capturedErrors.length) return;
+ renderError(nextView);
+ } catch (e) {
+ console.log('Red box renderer error:', e);
+ unmount();
+ render(null, 'Error', 'There is an error with red box. *Please* report this (see console).', []);
+ }
+}
+
+window.onerror = function (messageOrEvent, source, lineno, colno, error) {
+ if (error == null || !(error instanceof Error) || messageOrEvent.indexOf('Script error') !== -1) {
+ crash(new Error(error || messageOrEvent)); // TODO: more helpful message
+ } else {
+ crash(error);
+ }
+};
+
+var promiseHandler = function promiseHandler(event) {
+ if (event != null && event.reason != null) {
+ var reason = event.reason;
+
+ if (reason == null || !(reason instanceof Error)) {
+ crash(new Error(reason), true);
+ } else {
+ crash(reason, true);
+ }
+ } else {
+ crash(new Error('Unknown event'), true);
+ }
+};
+
+window.addEventListener('unhandledrejection', promiseHandler);
+
+var escapeHandler = function escapeHandler(event) {
+ var key = event.key,
+ keyCode = event.keyCode,
+ which = event.which;
+
+ if (key === 'Escape' || keyCode === 27 || which === 27) unmount();
+ else if (key === 'ArrowLeft' || keyCode === 37 || which === 37) switchError(-1);
+ else if (key === 'ArrowRight' || keyCode === 39 || which === 39) switchError(1);
+};
+
+window.addEventListener('keydown', escapeHandler);
+
+try {
+ Error.stackTraceLimit = 50;
+} catch (e) {
+ // Browser may not support this, we don't care.
+}
+
+// eslint-disable-next-line
+var proxyConsole = function proxyConsole(type) {
+ var orig = console[type];
+ console[type] = function __cra_proxy_console__() {
+ var warning = [].slice.call(arguments).join(' ');
+ var nIndex = warning.indexOf('\n');
+ var message = warning;
+ if (nIndex !== -1) message = message.substring(0, nIndex);
+ var stack = warning.substring(nIndex + 1).split('\n').filter(function (line) {
+ return line.indexOf('(at ') !== -1;
+ }).map(function (line) {
+ var prefix = '(at ';
+ var suffix = ')';
+ line = line.substring(line.indexOf(prefix) + prefix.length);
+ line = line.substring(0, line.indexOf(suffix));
+ var parts = line.split(/[:]/g);
+ if (parts.length !== 2) return null;
+ var file = parts[0];
+ var lineNum = Number(parts[1]);
+ if (isNaN(lineNum)) return null;
+ return { file: file, lineNum: lineNum };
+ }).filter(function (obj) {
+ return obj !== null;
+ });
+ var error = void 0;
+ try {
+ throw new Error(message);
+ } catch (e) {
+ error = e;
+ }
+ setTimeout(function () {
+ return crash(error, false, stack);
+ });
+ return orig.apply(this, arguments);
+ };
+};
+
+// proxyConsole('error');
+
+if (module.hot) {
+ module.hot.dispose(function () {
+ unmount();
+ window.removeEventListener('unhandledrejection', promiseHandler);
+ window.removeEventListener('keydown', escapeHandler);
+ });
+}
diff --git a/packages/react-dev-utils/package.json b/packages/react-dev-utils/package.json
index 4e1b350c0d1..64037886a0e 100644
--- a/packages/react-dev-utils/package.json
+++ b/packages/react-dev-utils/package.json
@@ -11,8 +11,10 @@
"node": ">=4"
},
"files": [
+ "ansiHTML.js",
"checkRequiredFiles.js",
"clearConsole.js",
+ "crashOverlay.js",
"FileSizeReporter.js",
"formatWebpackMessages.js",
"getProcessForPort.js",
@@ -24,7 +26,8 @@
"webpackHotDevClient.js"
],
"dependencies": {
- "ansi-html": "0.0.5",
+ "anser": "1.1.0",
+ "babel-code-frame": "6.20.0",
"chalk": "1.1.3",
"escape-string-regexp": "1.0.5",
"filesize": "3.3.0",
@@ -33,6 +36,7 @@
"opn": "4.0.2",
"recursive-readdir": "2.1.1",
"sockjs-client": "1.1.2",
+ "stack-frame-resolver": "0.1.3",
"strip-ansi": "3.0.1"
}
}
diff --git a/packages/react-dev-utils/webpackHotDevClient.js b/packages/react-dev-utils/webpackHotDevClient.js
index f4b88fd82e3..b060ddea48c 100644
--- a/packages/react-dev-utils/webpackHotDevClient.js
+++ b/packages/react-dev-utils/webpackHotDevClient.js
@@ -18,28 +18,15 @@
// 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 ansiHTML = require('./ansiHTML');
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);
+var red = '#E36049';
function createOverlayIframe(onIframeLoad) {
var iframe = document.createElement('iframe');
@@ -69,8 +56,8 @@ function addOverlayDivTo(iframe) {
div.style.bottom = 0;
div.style.width = '100vw';
div.style.height = '100vh';
- div.style.backgroundColor = 'black';
- div.style.color = '#E8E8E8';
+ div.style.backgroundColor = '#fafafa';
+ div.style.color = '#333';
div.style.fontFamily = 'Menlo, Consolas, monospace';
div.style.fontSize = 'large';
div.style.padding = '2rem';
@@ -118,14 +105,12 @@ function showErrorOverlay(message) {
ensureOverlayDivExists(function onOverlayDivReady(overlayDiv) {
// Make it look similar to our terminal.
overlayDiv.innerHTML =
- 'Failed to compile.
' +
+ 'Failed to compile.
' +
ansiHTML(entities.encode(message));
});
}
-function destroyErrorOverlay() {
+function destroyErrorOverlay() {
if (!overlayDiv) {
// It is not there in the first place.
return;
diff --git a/packages/react-scripts/config/webpack.config.dev.js b/packages/react-scripts/config/webpack.config.dev.js
index a279a60a99d..a952969e00f 100644
--- a/packages/react-scripts/config/webpack.config.dev.js
+++ b/packages/react-scripts/config/webpack.config.dev.js
@@ -58,6 +58,8 @@ module.exports = {
require.resolve('react-dev-utils/webpackHotDevClient'),
// We ship a few polyfills by default:
require.resolve('./polyfills'),
+ // Errors should be considered fatal in development
+ require.resolve('react-dev-utils/crashOverlay'),
// Finally, this is your app's code:
paths.appIndexJs
// We include the app code last so that if there is a runtime error during