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(