diff --git a/packages/frontend/core/src/bootstrap/browser.ts b/packages/frontend/core/src/bootstrap/browser.ts index cac814e59a..35073fbc88 100644 --- a/packages/frontend/core/src/bootstrap/browser.ts +++ b/packages/frontend/core/src/bootstrap/browser.ts @@ -1,5 +1,4 @@ // ORDER MATTERS -import './global-error-handler'; import './env'; import './public-path'; import './polyfill/browser'; diff --git a/packages/frontend/core/src/bootstrap/error.png b/packages/frontend/core/src/bootstrap/error.png deleted file mode 100644 index 03327d40ea..0000000000 Binary files a/packages/frontend/core/src/bootstrap/error.png and /dev/null differ diff --git a/packages/frontend/core/src/bootstrap/global-error-handler.ts b/packages/frontend/core/src/bootstrap/global-error-handler.ts deleted file mode 100644 index 597769e852..0000000000 --- a/packages/frontend/core/src/bootstrap/global-error-handler.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* 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 = [ - '', - '
', - '', - '
', - '

Unsupported Environment

', - '

', - '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 support page for further assistance.', - '

', - '
', - '
', - ].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(); diff --git a/tools/cli/src/webpack/cache-group.ts b/tools/cli/src/webpack/cache-group.ts index 0329009711..1ec621cf74 100644 --- a/tools/cli/src/webpack/cache-group.ts +++ b/tools/cli/src/webpack/cache-group.ts @@ -5,11 +5,6 @@ function testPackageName(regexp: RegExp): (module: any) => boolean { // https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758 export const productionCacheGroups = { - errorHandler: { - test: /global-error-handler/, - priority: 1000, - enforce: true, - }, asyncVendor: { test: /[\\/]node_modules[\\/]/, name(module: any) { diff --git a/tools/cli/src/webpack/config.ts b/tools/cli/src/webpack/config.ts index 6b5b001fb3..b6abab4958 100644 --- a/tools/cli/src/webpack/config.ts +++ b/tools/cli/src/webpack/config.ts @@ -400,11 +400,6 @@ export const createConfiguration: ( maxInitialRequests: Infinity, chunks: 'all', cacheGroups: { - errorHandler: { - test: /global-error-handler/, - priority: 1000, - enforce: true, - }, defaultVendors: { test: `[\\/]node_modules[\\/](?!.*vanilla-extract)`, priority: -10, diff --git a/tools/cli/src/webpack/error-handler.js b/tools/cli/src/webpack/error-handler.js new file mode 100644 index 0000000000..2acd7a46d1 --- /dev/null +++ b/tools/cli/src/webpack/error-handler.js @@ -0,0 +1,73 @@ +(function () { + var errorEl = null; + function showGlobalErrorPage() { + if (errorEl) { + return; + } + + errorEl = document.createElement('div'); + errorEl.innerHTML = [ + '', + '
', + '', + '
', + '

Unsupported Environment

', + '

', + '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 support page for further assistance.', + '

', + '
', + '
', + ].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 handler(e) { + 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', handler); + globalThis.addEventListener('error', handler); + } + } + + 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(); +})(); diff --git a/tools/cli/src/webpack/webpack.config.ts b/tools/cli/src/webpack/webpack.config.ts index dbeb696fb4..290ce1fc38 100644 --- a/tools/cli/src/webpack/webpack.config.ts +++ b/tools/cli/src/webpack/webpack.config.ts @@ -1,4 +1,5 @@ import { execSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import type { BuildFlags } from '@affine/cli/config'; @@ -52,6 +53,14 @@ export function createWebpackConfig(cwd: string, flags: BuildFlags) { ? undefined : new URL(publicPath).origin; + const globalErrorHandler = [ + 'js/global-error-handler.js', + readFileSync( + join(workspaceRoot, 'tools/cli/src/webpack/error-handler.js'), + 'utf-8' + ), + ]; + const templateParams = { GIT_SHORT_SHA: gitShortHash(), DESCRIPTION, @@ -86,7 +95,24 @@ export function createWebpackConfig(cwd: string, flags: BuildFlags) { HTMLPlugin.getHooks(compilation).beforeAssetTagGeneration.tap( 'assets-manifest-plugin', arg => { + if ( + flags.distribution !== 'desktop' && + !compilation.getAsset(globalErrorHandler[0]) + ) { + compilation.emitAsset( + globalErrorHandler[0], + new webpack.sources.RawSource(globalErrorHandler[1]) + ); + arg.assets.js.unshift( + arg.assets.publicPath + globalErrorHandler[0] + ); + } + if (!compilation.getAsset('assets-manifest.json')) { + compilation.emitAsset( + globalErrorHandler[0], + new webpack.sources.RawSource(globalErrorHandler[1]) + ); compilation.emitAsset( `assets-manifest.json`, new webpack.sources.RawSource(