You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

503 lines
19 KiB

/**
* The following code is modified based on
* https://github.com/webpack/webpack-dev-server
*
* MIT Licensed
* Author Tobias Koppers @sokra
* Copyright (c) JS Foundation and other contributors
* https://github.com/webpack/webpack-dev-server/blob/main/LICENSE
*/
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
// 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).
import ansiHTML from './utils/ansiHTML';
var getCodePoint = !!String.prototype.codePointAt
? function (input, position) {
return input.codePointAt(position);
}
: function (input, position) {
return (input.charCodeAt(position) - 0xd800) * 0x400 +
input.charCodeAt(position + 1) -
0xdc00 +
0x10000;
};
var replaceUsingRegExp = function (macroText, macroRegExp, macroReplacer) {
macroRegExp.lastIndex = 0;
var replaceMatch = macroRegExp.exec(macroText);
var replaceResult;
if (replaceMatch) {
replaceResult = '';
var replaceLastIndex = 0;
do {
if (replaceLastIndex !== replaceMatch.index) {
replaceResult += macroText.slice(replaceLastIndex, replaceMatch.index);
}
var replaceInput = replaceMatch[0];
replaceResult += macroReplacer(replaceInput);
replaceLastIndex = replaceMatch.index + replaceInput.length;
} while ((replaceMatch = macroRegExp.exec(macroText)));
if (replaceLastIndex !== macroText.length) {
replaceResult += macroText.slice(replaceLastIndex);
}
}
else {
replaceResult = macroText;
}
return replaceResult;
};
var references = {
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&apos;',
'&': '&amp;',
};
function encode(text) {
if (!text) {
return '';
}
return replaceUsingRegExp(text, /[<>'"&]/g, function (input) {
var result = references[input];
if (!result) {
var code = input.length > 1 ? getCodePoint(input, 0) : input.charCodeAt(0);
result = "&#".concat(code, ";");
}
return result;
});
}
/**
* A simplified `createMachine` from `@xstate/fsm` with the following differences:
* - the returned machine is technically a "service". No `interpret(machine).start()` is needed.
* - the state definition only support `on` and target must be declared with { target: 'nextState', actions: [] } explicitly.
* - event passed to `send` must be an object with `type` property.
* - actions implementation will be [assign action](https://xstate.js.org/docs/guides/context.html#assign-action) if you return any value.
* Do not return anything if you just want to invoke side effect.
*
* The goal of this custom function is to avoid installing the entire `'xstate/fsm'` package, while enabling modeling using
* state machine. You can copy the first parameter into the editor at https://stately.ai/viz to visualize the state machine.
*/
function createMachine(_a, _b) {
var states = _a.states, context = _a.context, initial = _a.initial;
var actions = _b.actions;
var currentState = initial;
var currentContext = context;
return {
send: function (event) {
var currentStateOn = states[currentState].on;
var transitionConfig = currentStateOn && currentStateOn[event.type];
if (transitionConfig) {
currentState = transitionConfig.target;
if (transitionConfig.actions) {
transitionConfig.actions.forEach(function (actName) {
var actionImpl = actions[actName];
var nextContextValue = actionImpl && actionImpl(currentContext, event);
if (nextContextValue) {
currentContext = __assign(__assign({}, currentContext), nextContextValue);
}
});
}
}
},
};
}
var createOverlayMachine = function (options) {
var hideOverlay = options.hideOverlay, showOverlay = options.showOverlay;
return createMachine({
initial: 'hidden',
context: {
level: 'error',
messages: [],
messageSource: 'build',
},
states: {
hidden: {
on: {
BUILD_ERROR: {
target: 'displayBuildError',
actions: ['setMessages', 'showOverlay'],
},
RUNTIME_ERROR: {
target: 'displayRuntimeError',
actions: ['setMessages', 'showOverlay'],
},
},
},
displayBuildError: {
on: {
DISMISS: {
target: 'hidden',
actions: ['dismissMessages', 'hideOverlay'],
},
BUILD_ERROR: {
target: 'displayBuildError',
actions: ['appendMessages', 'showOverlay'],
},
},
},
displayRuntimeError: {
on: {
DISMISS: {
target: 'hidden',
actions: ['dismissMessages', 'hideOverlay'],
},
RUNTIME_ERROR: {
target: 'displayRuntimeError',
actions: ['appendMessages', 'showOverlay'],
},
BUILD_ERROR: {
target: 'displayBuildError',
actions: ['setMessages', 'showOverlay'],
},
},
},
},
}, {
actions: {
dismissMessages: function () {
return {
messages: [],
level: 'error',
messageSource: 'build',
};
},
appendMessages: function (context, event) {
return {
messages: context.messages.concat(event.messages),
level: event.level || context.level,
messageSource: event.type === 'RUNTIME_ERROR' ? 'runtime' : 'build',
};
},
setMessages: function (context, event) {
return {
messages: event.messages,
level: event.level || context.level,
messageSource: event.type === 'RUNTIME_ERROR' ? 'runtime' : 'build',
};
},
hideOverlay: hideOverlay,
showOverlay: showOverlay,
},
});
};
var parseErrorToStacks = function (error) {
if (!error || !(error instanceof Error)) {
throw new Error('parseErrorToStacks expects Error object');
}
if (typeof error.stack === 'string') {
return error.stack
.split('\n')
.filter(function (stack) { return stack !== "Error: ".concat(error.message); });
}
};
var listenToRuntimeError = function (callback) {
window.addEventListener('error', callback);
return function cleanup() {
window.removeEventListener('error', callback);
};
};
var listenToUnhandledRejection = function (callback) {
window.addEventListener('unhandledrejection', callback);
return function cleanup() {
window.removeEventListener('unhandledrejection', callback);
};
};
// Styles are inspired by `react-error-overlay`
var msgStyles = {
error: {
backgroundColor: 'rgba(206, 17, 38, 0.1)',
color: '#fccfcf',
},
warning: {
backgroundColor: 'rgba(251, 245, 180, 0.1)',
color: '#fbf5b4',
},
};
var iframeStyle = {
position: 'fixed',
top: '0px',
left: '0px',
right: '0px',
bottom: '0px',
width: '100vw',
height: '100vh',
border: 'none',
'z-index': 9999999999,
};
var containerStyle = {
position: 'fixed',
boxSizing: 'border-box',
left: '0px',
top: '0px',
right: '0px',
bottom: '0px',
width: '100vw',
height: '100vh',
fontSize: 'large',
padding: '2rem 2rem 4rem 2rem',
lineHeight: '1.2',
whiteSpace: 'pre-wrap',
overflow: 'auto',
backgroundColor: 'rgba(0, 0, 0, 0.9)',
color: 'white',
};
var headerStyle = {
color: '#e83b46',
fontSize: '2em',
whiteSpace: 'pre-wrap',
fontFamily: 'sans-serif',
margin: '0 2rem 2rem 0',
flex: '0 0 auto',
maxHeight: '50%',
overflow: 'auto',
};
var dismissButtonStyle = {
color: '#ffffff',
lineHeight: '1rem',
fontSize: '1.5rem',
padding: '1rem',
cursor: 'pointer',
position: 'absolute',
right: '0px',
top: '0px',
backgroundColor: 'transparent',
border: 'none',
};
var msgTypeStyle = {
color: '#e83b46',
fontSize: '1.2em',
marginBottom: '1rem',
fontFamily: 'sans-serif',
};
var msgTextStyle = {
lineHeight: '1.5',
fontSize: '1rem',
fontFamily: 'Menlo, Consolas, monospace',
};
// ANSI HTML
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 formatProblem = function (type, item) {
var header = type === 'warning' ? 'WARNING' : 'ERROR';
var body = '';
if (typeof item === 'string') {
body += item;
}
else {
var file = item.file || '';
var moduleName = item.moduleName
? item.moduleName.indexOf('!') !== -1
? "".concat(item.moduleName.replace(/^(\s|\S)*!/, ''), " (").concat(item.moduleName, ")")
: "".concat(item.moduleName)
: '';
var loc = item.loc;
header += "".concat(moduleName || file
? " in ".concat(moduleName ? "".concat(moduleName).concat(file ? " (".concat(file, ")") : '') : file).concat(loc ? " ".concat(loc) : '')
: '');
body += item.message || '';
}
if (typeof item !== 'string' && Array.isArray(item.stack)) {
item.stack.forEach(function (stack) {
if (typeof stack === 'string') {
body += "\r\n".concat(stack);
}
});
}
return { header: header, body: body };
};
var createOverlay = function (options) {
var iframeContainerElement;
var containerElement;
var headerElement;
var onLoadQueue = [];
var overlayTrustedTypesPolicy;
function applyStyle(element, style) {
Object.keys(style).forEach(function (prop) {
element.style[prop] =
style[prop];
});
}
function createContainer(trustedTypesPolicyName) {
// Enable Trusted Types if they are available in the current browser.
if (window.trustedTypes) {
overlayTrustedTypesPolicy = window.trustedTypes.createPolicy(trustedTypesPolicyName || 'webpack-dev-server#overlay', {
createHTML: function (value) { return value; },
});
}
iframeContainerElement = document.createElement('iframe');
iframeContainerElement.id = 'webpack-dev-server-client-overlay';
iframeContainerElement.src = 'about:blank';
applyStyle(iframeContainerElement, iframeStyle);
iframeContainerElement.onload = function () {
var contentElement = (iframeContainerElement === null || iframeContainerElement === void 0 ? void 0 : iframeContainerElement.contentDocument).createElement('div');
containerElement = (iframeContainerElement === null || iframeContainerElement === void 0 ? void 0 : iframeContainerElement.contentDocument).createElement('div');
contentElement.id = 'webpack-dev-server-client-overlay-div';
applyStyle(contentElement, containerStyle);
headerElement = document.createElement('div');
headerElement.innerText = 'Compiled with problems:';
applyStyle(headerElement, headerStyle);
var closeButtonElement = document.createElement('button');
applyStyle(closeButtonElement, dismissButtonStyle);
closeButtonElement.innerText = '×';
closeButtonElement.ariaLabel = 'Dismiss';
closeButtonElement.addEventListener('click', function () {
// eslint-disable-next-line no-use-before-define
overlayService.send({ type: 'DISMISS' });
});
contentElement.appendChild(headerElement);
contentElement.appendChild(closeButtonElement);
contentElement.appendChild(containerElement);
(iframeContainerElement === null || iframeContainerElement === void 0 ? void 0 : iframeContainerElement.contentDocument).body.appendChild(contentElement);
onLoadQueue.forEach(function (onLoad) {
onLoad(contentElement);
});
onLoadQueue = [];
iframeContainerElement.onload = null;
};
document.body.appendChild(iframeContainerElement);
}
function ensureOverlayExists(callback, trustedTypesPolicyName) {
if (containerElement) {
containerElement.innerHTML = overlayTrustedTypesPolicy
? overlayTrustedTypesPolicy.createHTML('')
: '';
// Everything is ready, call the callback right away.
callback(containerElement);
return;
}
onLoadQueue.push(callback);
if (iframeContainerElement) {
return;
}
createContainer(trustedTypesPolicyName);
}
// Successful compilation.
function hide() {
if (!iframeContainerElement) {
return;
}
// Clean up and reset internal state.
document.body.removeChild(iframeContainerElement);
iframeContainerElement = null;
containerElement = null;
}
// Compilation with errors (e.g. syntax error or missing modules).
function show(type, messages, trustedTypesPolicyName, messageSource) {
ensureOverlayExists(function () {
headerElement.innerText =
messageSource === 'runtime'
? 'Uncaught runtime errors:'
: 'Compiled with problems:';
messages.forEach(function (message) {
var entryElement = document.createElement('div');
var msgStyle = type === 'warning' ? msgStyles.warning : msgStyles.error;
applyStyle(entryElement, __assign(__assign({}, msgStyle), { padding: '1rem 1rem 1.5rem 1rem' }));
var typeElement = document.createElement('div');
var _a = formatProblem(type, message), header = _a.header, body = _a.body;
typeElement.innerText = header;
applyStyle(typeElement, msgTypeStyle);
if (typeof message !== 'string' && message.moduleIdentifier) {
applyStyle(typeElement, { cursor: 'pointer' });
// element.dataset not supported in IE
typeElement.setAttribute('data-can-open', 'true');
typeElement.addEventListener('click', function () {
fetch("/webpack-dev-server/open-editor?fileName=".concat(message.moduleIdentifier));
});
}
// Make it look similar to our terminal.
var text = ansiHTML(encode(body));
var messageTextNode = document.createElement('div');
applyStyle(messageTextNode, msgTextStyle);
messageTextNode.innerHTML = overlayTrustedTypesPolicy
? overlayTrustedTypesPolicy.createHTML(text)
: text;
entryElement.appendChild(typeElement);
entryElement.appendChild(messageTextNode);
containerElement === null || containerElement === void 0 ? void 0 : containerElement.appendChild(entryElement);
});
}, trustedTypesPolicyName);
}
var handleEscapeKey;
var hideOverlayWithEscCleanup = function () {
window.removeEventListener('keydown', handleEscapeKey);
hide();
};
var overlayService = createOverlayMachine({
showOverlay: function (_a) {
var _b = _a.level, level = _b === void 0 ? 'error' : _b, messages = _a.messages, messageSource = _a.messageSource;
return show(level, messages, options.trustedTypesPolicyName, messageSource);
},
hideOverlay: hideOverlayWithEscCleanup,
});
/**
* ESC key press to dismiss the overlay.
*/
handleEscapeKey = function (event) {
if (event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27) {
overlayService.send({ type: 'DISMISS' });
}
};
window.addEventListener('keydown', handleEscapeKey);
if (options.catchRuntimeError) {
var handleError_1 = function (error, fallbackMessage) {
var errorObject = error instanceof Error
? error
: // @ts-expect-error error options
new Error(error || fallbackMessage, { cause: error });
var shouldDisplay = typeof options.catchRuntimeError === 'function'
? options.catchRuntimeError(errorObject)
: true;
if (shouldDisplay) {
overlayService.send({
type: 'RUNTIME_ERROR',
messages: [
{
message: errorObject.message,
stack: parseErrorToStacks(errorObject),
},
],
});
}
};
listenToRuntimeError(function (errorEvent) {
// error property may be empty in older browser like IE
var error = errorEvent.error, message = errorEvent.message;
if (!error && !message) {
return;
}
// if error stack indicates a React error boundary caught the error, do not show overlay.
if (error &&
error.stack &&
error.stack.includes('invokeGuardedCallbackDev')) {
return;
}
handleError_1(error, message);
});
listenToUnhandledRejection(function (promiseRejectionEvent) {
var reason = promiseRejectionEvent.reason;
handleError_1(reason, 'Unknown promise rejection reason');
});
}
return overlayService;
};
export { createOverlay, formatProblem };