mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 17:22:18 +03:00
feat(core): add global error handler (#8509)
This commit is contained in:
parent
4b77f6ed34
commit
9b31183bd1
@ -1,3 +1 @@
|
|||||||
import { setupBrowser } from '@affine/core/bootstrap';
|
import '@affine/core/bootstrap/browser';
|
||||||
|
|
||||||
await setupBrowser();
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
|
import '@affine/core/bootstrap/electron';
|
||||||
import '@affine/component/theme';
|
import '@affine/component/theme';
|
||||||
import './global.css';
|
import './global.css';
|
||||||
|
|
||||||
import { setupElectron } from '@affine/core/bootstrap';
|
|
||||||
|
|
||||||
setupElectron();
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
|
import '@affine/core/bootstrap/electron';
|
||||||
import '@affine/component/theme';
|
import '@affine/component/theme';
|
||||||
import '../global.css';
|
import '../global.css';
|
||||||
|
|
||||||
import { setupElectron } from '@affine/core/bootstrap';
|
|
||||||
|
|
||||||
setupElectron();
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
|
import '@affine/core/bootstrap/browser';
|
||||||
import '@affine/component/theme';
|
import '@affine/component/theme';
|
||||||
import '@affine/core/mobile/styles/mobile.css';
|
import '@affine/core/mobile/styles/mobile.css';
|
||||||
|
|
||||||
import { setupBrowser } from '@affine/core/bootstrap';
|
|
||||||
|
|
||||||
await setupBrowser();
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
|
import '@affine/core/bootstrap/browser';
|
||||||
import '@affine/component/theme';
|
import '@affine/component/theme';
|
||||||
|
|
||||||
import { setupBrowser } from '@affine/core/bootstrap';
|
|
||||||
|
|
||||||
await setupBrowser();
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
import '@affine/env/constant';
|
|
||||||
import '../types/types.d.ts';
|
|
||||||
|
|
||||||
export { setupGlobal as setupEnvironment } from '@affine/env/global';
|
|
5
packages/frontend/core/src/bootstrap/browser.ts
Normal file
5
packages/frontend/core/src/bootstrap/browser.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// ORDER MATTERS
|
||||||
|
import './global-error-handler';
|
||||||
|
import './env';
|
||||||
|
import './public-path';
|
||||||
|
import './polyfill/browser';
|
4
packages/frontend/core/src/bootstrap/electron.ts
Normal file
4
packages/frontend/core/src/bootstrap/electron.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// ORDER MATTERS
|
||||||
|
import './env';
|
||||||
|
import './public-path';
|
||||||
|
import './polyfill/electron';
|
6
packages/frontend/core/src/bootstrap/env.ts
Normal file
6
packages/frontend/core/src/bootstrap/env.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import '@affine/env/constant';
|
||||||
|
import '../types/types.d.ts';
|
||||||
|
|
||||||
|
import { setupGlobal } from '@affine/env/global';
|
||||||
|
|
||||||
|
setupGlobal();
|
BIN
packages/frontend/core/src/bootstrap/error.png
Normal file
BIN
packages/frontend/core/src/bootstrap/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
81
packages/frontend/core/src/bootstrap/global-error-handler.ts
Normal file
81
packages/frontend/core/src/bootstrap/global-error-handler.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* eslint-disable no-var */
|
||||||
|
import errorImg from './error.png';
|
||||||
|
|
||||||
|
var errorEl: HTMLDivElement | null = null;
|
||||||
|
function showGlobalErrorPage() {
|
||||||
|
if (errorEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorEl = document.createElement('div');
|
||||||
|
errorEl.innerHTML = [
|
||||||
|
'<style>',
|
||||||
|
'.gue {display:flex;flex-direction:column;align-items:center;justify-content:center;width:380px;}',
|
||||||
|
'.gue img{width:380px;}',
|
||||||
|
'.gue div{padding:16px 40px 0 40px;text-align:center;}',
|
||||||
|
'.gue .p1{color:#141414;line-height:24px;font-weight:500;}',
|
||||||
|
'.gue .p2{color:#7A7A7A;line-height:22px;}',
|
||||||
|
'</style>',
|
||||||
|
'<div class="gue">',
|
||||||
|
'<img src="',
|
||||||
|
errorImg,
|
||||||
|
'" />',
|
||||||
|
'<div>',
|
||||||
|
'<p class="p1">Unsupported Environment</p>',
|
||||||
|
'<p class="p2">',
|
||||||
|
'It looks like AFFiNE cannot run in this environment.',
|
||||||
|
"Please ensure you are using a supported browser or update your device's operating system to the latest version.",
|
||||||
|
'If the issue persists, visit our <a href="https://github.com/toeverything/AFFiNE/issues">support page</a> for further assistance.',
|
||||||
|
'</p>',
|
||||||
|
'</div>',
|
||||||
|
'</div>',
|
||||||
|
].join('');
|
||||||
|
errorEl.setAttribute(
|
||||||
|
'style',
|
||||||
|
'position:absolute;top:0;left:0;height:100vh;width:100vw;display:flex;flex-direction:column;align-items:center;justify-content:center;background:white;z-index:999;'
|
||||||
|
);
|
||||||
|
document.body.append(errorEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerGlobalErrorHandler() {
|
||||||
|
function handleGlobalUnrecoverableError(
|
||||||
|
e: ErrorEvent | PromiseRejectionEvent
|
||||||
|
) {
|
||||||
|
var error =
|
||||||
|
'error' in e ? e.error : e.reason instanceof Error ? e.reason : null;
|
||||||
|
console.error('unhandled unrecoverable error', error);
|
||||||
|
|
||||||
|
const shouldCache =
|
||||||
|
// syntax error
|
||||||
|
error && error instanceof SyntaxError;
|
||||||
|
|
||||||
|
if (!shouldCache) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
showGlobalErrorPage();
|
||||||
|
}
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
globalThis.addEventListener(
|
||||||
|
'unhandledrejection',
|
||||||
|
handleGlobalUnrecoverableError
|
||||||
|
);
|
||||||
|
globalThis.addEventListener('error', handleGlobalUnrecoverableError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureBasicEnvironment() {
|
||||||
|
var globals = ['Promise', 'Map', 'fetch', 'customElements'];
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||||
|
for (var i = 0; i < globals.length; i++) {
|
||||||
|
if (!(globals[i] in globalThis)) {
|
||||||
|
showGlobalErrorPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerGlobalErrorHandler();
|
||||||
|
ensureBasicEnvironment();
|
@ -1,15 +0,0 @@
|
|||||||
import '../types/types.d.ts';
|
|
||||||
|
|
||||||
import { setupEnvironment } from './app';
|
|
||||||
import { polyfillBrowser, polyfillElectron } from './polyfill';
|
|
||||||
|
|
||||||
export function setupElectron() {
|
|
||||||
setupEnvironment();
|
|
||||||
polyfillElectron();
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function setupBrowser() {
|
|
||||||
setupEnvironment();
|
|
||||||
__webpack_public_path__ = environment.publicPath;
|
|
||||||
await polyfillBrowser();
|
|
||||||
}
|
|
@ -3,13 +3,7 @@ import { polyfillPromise } from './promise-with-resolvers';
|
|||||||
import { polyfillEventLoop } from './request-idle-callback';
|
import { polyfillEventLoop } from './request-idle-callback';
|
||||||
import { polyfillResizeObserver } from './resize-observer';
|
import { polyfillResizeObserver } from './resize-observer';
|
||||||
|
|
||||||
export function polyfillElectron() {
|
polyfillResizeObserver();
|
||||||
polyfillResizeObserver();
|
polyfillEventLoop();
|
||||||
}
|
await polyfillPromise();
|
||||||
|
await polyfillDispose();
|
||||||
export async function polyfillBrowser() {
|
|
||||||
polyfillResizeObserver();
|
|
||||||
polyfillEventLoop();
|
|
||||||
await polyfillPromise();
|
|
||||||
await polyfillDispose();
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
import { polyfillResizeObserver } from './resize-observer';
|
||||||
|
|
||||||
|
polyfillResizeObserver();
|
1
packages/frontend/core/src/bootstrap/public-path.ts
Normal file
1
packages/frontend/core/src/bootstrap/public-path.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
__webpack_public_path__ = environment.publicPath;
|
@ -5,6 +5,11 @@ function testPackageName(regexp: RegExp): (module: any) => boolean {
|
|||||||
|
|
||||||
// https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
|
// https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
|
||||||
export const productionCacheGroups = {
|
export const productionCacheGroups = {
|
||||||
|
errorHandler: {
|
||||||
|
test: /global-error-handler/,
|
||||||
|
priority: 1000,
|
||||||
|
enforce: true,
|
||||||
|
},
|
||||||
asyncVendor: {
|
asyncVendor: {
|
||||||
test: /[\\/]node_modules[\\/]/,
|
test: /[\\/]node_modules[\\/]/,
|
||||||
name(module: any) {
|
name(module: any) {
|
||||||
|
@ -56,13 +56,7 @@ const OptimizeOptionOptions: (
|
|||||||
minChunks: 1,
|
minChunks: 1,
|
||||||
maxInitialRequests: Number.MAX_SAFE_INTEGER,
|
maxInitialRequests: Number.MAX_SAFE_INTEGER,
|
||||||
maxAsyncRequests: Number.MAX_SAFE_INTEGER,
|
maxAsyncRequests: Number.MAX_SAFE_INTEGER,
|
||||||
cacheGroups:
|
cacheGroups: productionCacheGroups,
|
||||||
buildFlags.mode === 'production'
|
|
||||||
? productionCacheGroups
|
|
||||||
: {
|
|
||||||
default: false,
|
|
||||||
vendors: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -404,6 +398,11 @@ export const createConfiguration: (
|
|||||||
maxInitialRequests: Infinity,
|
maxInitialRequests: Infinity,
|
||||||
chunks: 'all',
|
chunks: 'all',
|
||||||
cacheGroups: {
|
cacheGroups: {
|
||||||
|
errorHandler: {
|
||||||
|
test: /global-error-handler/,
|
||||||
|
priority: 1000,
|
||||||
|
enforce: true,
|
||||||
|
},
|
||||||
defaultVendors: {
|
defaultVendors: {
|
||||||
test: `[\\/]node_modules[\\/](?!.*vanilla-extract)`,
|
test: `[\\/]node_modules[\\/](?!.*vanilla-extract)`,
|
||||||
priority: -10,
|
priority: -10,
|
||||||
|
Loading…
Reference in New Issue
Block a user