refactor: webpack config (#11421)

This commit is contained in:
forehalo
2025-04-03 11:55:56 +00:00
parent 565d7b2b1e
commit c8d22d97d5
51 changed files with 766 additions and 547 deletions

View File

@@ -17,7 +17,7 @@ if (typeof window !== 'undefined') {
debug.enable('*');
console.warn('Debug logs enabled');
}
if (process.env.NODE_ENV === 'development') {
if (BUILD_CONFIG.debug) {
debug.enable('*,-micromark');
console.warn('Debug logs enabled');
}

View File

@@ -12,7 +12,8 @@
"./workspace": "./src/workspace.ts",
"./workspace/legacy-cloud": "./src/workspace/legacy-cloud/index.ts",
"./filter": "./src/filter.ts",
"./blocksuite": "./src/blocksuite/index.ts"
"./blocksuite": "./src/blocksuite/index.ts",
"./worker": "./src/worker.ts"
},
"peerDependencies": {
"@affine/templates": "workspace:*",

View File

@@ -17,6 +17,7 @@ export function setupGlobal() {
isMobile: false,
isSelfHosted: false,
publicPath: '/',
workerPath: '/js/',
};
if (globalThis.navigator) {

7
packages/common/env/src/worker.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
export function getWorkerUrl(name: string) {
if (BUILD_CONFIG.debug && !name.endsWith('.worker.js')) {
throw new Error(`worker should be named with '.worker.js', get ${name}`);
}
return environment.workerPath + name + '?v=' + BUILD_CONFIG.appVersion;
}

View File

@@ -8,6 +8,7 @@
"./utils": "./src/utils/index.ts",
"./app-config-storage": "./src/app-config-storage.ts",
"./op": "./src/op/index.ts",
"./atom": "./src/atom/index.ts",
".": "./src/index.ts"
},
"dependencies": {

View File

@@ -10,6 +10,7 @@
"dependencies": {
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/nbstore": "workspace:*",
"@blocksuite/affine": "workspace:*",

View File

@@ -23,6 +23,7 @@ import { ClientSchemeProvider } from '@affine/core/modules/url/providers/client-
import { configureBrowserWorkbenchModule } from '@affine/core/modules/workbench';
import { WorkspacesService } from '@affine/core/modules/workspace';
import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspace-engine';
import { getWorkerUrl } from '@affine/env/worker';
import { I18n } from '@affine/i18n';
import { StoreManagerClient } from '@affine/nbstore/worker/client';
import { defaultBlockMarkdownAdapterMatchers } from '@blocksuite/affine/adapters';
@@ -51,11 +52,7 @@ import { AffineTheme } from './plugins/affine-theme';
import { AIButton } from './plugins/ai-button';
const storeManagerClient = new StoreManagerClient(
new OpClient(
new Worker(
new URL(/* webpackChunkName: "nbstore" */ './nbstore.ts', import.meta.url)
)
)
new OpClient(new Worker(getWorkerUrl('nbstore.worker.js')))
);
window.addEventListener('beforeunload', () => {
storeManagerClient.dispose();

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../component" },
{ "path": "../../core" },
{ "path": "../../../common/env" },
{ "path": "../../i18n" },
{ "path": "../../../common/nbstore" },
{ "path": "../../../../blocksuite/affine/all" },

View File

@@ -1,8 +0,0 @@
export const config = {
entry: {
app: './src/app/index.tsx',
shell: './src/shell/index.tsx',
backgroundWorker: './src/background-worker/index.ts',
popup: './src/popup/index.tsx',
},
};

View File

@@ -2,7 +2,13 @@ import path from 'node:path';
import type { _AsyncVersionOf } from 'async-call-rpc';
import { AsyncCall } from 'async-call-rpc';
import type { UtilityProcess, WebContents } from 'electron';
import type {
BaseWindow,
OpenDialogOptions,
SaveDialogOptions,
UtilityProcess,
WebContents,
} from 'electron';
import {
app,
dialog,
@@ -57,7 +63,6 @@ class HelperProcessManager {
this.ready = new Promise((resolve, reject) => {
helperProcess.once('spawn', () => {
try {
this.#connectMain();
logger.info('[helper] forked', helperProcess.pid);
resolve();
} catch (err) {
@@ -91,11 +96,15 @@ class HelperProcessManager {
// bridge main <-> helper process
// also set up the RPC to the helper process
#connectMain() {
const dialogMethods = pickAndBind(dialog, [
'showOpenDialog',
'showSaveDialog',
]);
connectMain(window: BaseWindow) {
const dialogMethods = {
showOpenDialog: async (opts: OpenDialogOptions) => {
return dialog.showOpenDialog(window, opts);
},
showSaveDialog: async (opts: SaveDialogOptions) => {
return dialog.showSaveDialog(window, opts);
},
};
const shellMethods = pickAndBind(shell, [
'openExternal',
'showItemInFolder',

View File

@@ -63,8 +63,6 @@ export class MainWindowManager {
defaultHeight: 800,
});
await ensureHelperProcess();
const browserWindow = new BrowserWindow({
titleBarStyle: isMacOS()
? 'hiddenInset'
@@ -88,6 +86,8 @@ export class MainWindowManager {
sandbox: false,
},
});
const helper = await ensureHelperProcess();
helper.connectMain(browserWindow);
if (isLinux()) {
browserWindow.setIcon(

View File

@@ -16,6 +16,7 @@
"dependencies": {
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/nbstore": "workspace:*",
"@blocksuite/affine": "workspace:*",

View File

@@ -35,6 +35,7 @@ import {
WorkspacesService,
} from '@affine/core/modules/workspace';
import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspace-engine';
import { getWorkerUrl } from '@affine/env/worker';
import { I18n } from '@affine/i18n';
import { StoreManagerClient } from '@affine/nbstore/worker/client';
import { defaultBlockMarkdownAdapterMatchers } from '@blocksuite/affine/adapters';
@@ -414,12 +415,7 @@ export function App() {
}
function createStoreManagerClient() {
const worker = new Worker(
new URL(
/* webpackChunkName: "nbstore-worker" */ './worker.ts',
import.meta.url
)
);
const worker = new Worker(getWorkerUrl('nbstore.worker.js'));
const { port1: nativeDBApiChannelServer, port2: nativeDBApiChannelClient } =
new MessageChannel();
AsyncCall<typeof NbStoreNativeDBApis>(NbStoreNativeDBApis, {

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../component" },
{ "path": "../../core" },
{ "path": "../../../common/env" },
{ "path": "../../i18n" },
{ "path": "../../../common/nbstore" },
{ "path": "../../../../blocksuite/affine/all" },

View File

@@ -11,6 +11,7 @@
"dependencies": {
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/nbstore": "workspace:*",
"@blocksuite/affine": "workspace:*",

View File

@@ -14,6 +14,7 @@ import {
import { PopupWindowProvider } from '@affine/core/modules/url';
import { configureBrowserWorkbenchModule } from '@affine/core/modules/workbench';
import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspace-engine';
import { getWorkerUrl } from '@affine/env/worker';
import { StoreManagerClient } from '@affine/nbstore/worker/client';
import { Framework, FrameworkRoot, getCurrentStore } from '@toeverything/infra';
import { OpClient } from '@toeverything/infra/op';
@@ -22,16 +23,12 @@ import { RouterProvider } from 'react-router-dom';
let storeManagerClient: StoreManagerClient;
const workerUrl = getWorkerUrl('nbstore.worker.js');
if (window.SharedWorker) {
const worker = new SharedWorker(
new URL(/* webpackChunkName: "nbstore" */ './nbstore.ts', import.meta.url),
{ name: 'affine-shared-worker' }
);
const worker = new SharedWorker(workerUrl, { name: 'affine-shared-worker' });
storeManagerClient = new StoreManagerClient(new OpClient(worker.port));
} else {
const worker = new Worker(
new URL(/* webpackChunkName: "nbstore" */ './nbstore.ts', import.meta.url)
);
const worker = new Worker(workerUrl);
storeManagerClient = new StoreManagerClient(new OpClient(worker));
}
window.addEventListener('beforeunload', () => {

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../component" },
{ "path": "../../core" },
{ "path": "../../../common/env" },
{ "path": "../../i18n" },
{ "path": "../../../common/nbstore" },
{ "path": "../../../../blocksuite/affine/all" },

View File

@@ -11,6 +11,7 @@
"dependencies": {
"@affine/component": "workspace:*",
"@affine/core": "workspace:*",
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/nbstore": "workspace:*",
"@affine/track": "workspace:*",

View File

@@ -12,6 +12,7 @@ import { PopupWindowProvider } from '@affine/core/modules/url';
import { configureBrowserWorkbenchModule } from '@affine/core/modules/workbench';
import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspace-engine';
import createEmotionCache from '@affine/core/utils/create-emotion-cache';
import { getWorkerUrl } from '@affine/env/worker';
import { StoreManagerClient } from '@affine/nbstore/worker/client';
import { CacheProvider } from '@emotion/react';
import { Framework, FrameworkRoot, getCurrentStore } from '@toeverything/infra';
@@ -23,19 +24,16 @@ const cache = createEmotionCache();
let storeManagerClient: StoreManagerClient;
const workerUrl = getWorkerUrl('nbstore.worker.js');
if (
window.SharedWorker &&
localStorage.getItem('disableSharedWorker') !== 'true'
) {
const worker = new SharedWorker(
new URL(/* webpackChunkName: "nbstore" */ './nbstore.ts', import.meta.url),
{ name: 'affine-shared-worker' }
);
const worker = new SharedWorker(workerUrl);
storeManagerClient = new StoreManagerClient(new OpClient(worker.port));
} else {
const worker = new Worker(
new URL(/* webpackChunkName: "nbstore" */ './nbstore.ts', import.meta.url)
);
const worker = new Worker(workerUrl);
storeManagerClient = new StoreManagerClient(new OpClient(worker));
}
window.addEventListener('beforeunload', () => {

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../component" },
{ "path": "../../core" },
{ "path": "../../../common/env" },
{ "path": "../../i18n" },
{ "path": "../../../common/nbstore" },
{ "path": "../../track" },

View File

@@ -54,18 +54,15 @@ export default {
inlineSourcesContent: true,
}),
],
define: {
'process.env.CAPTCHA_SITE_KEY': `"${process.env.CAPTCHA_SITE_KEY}"`,
...Object.entries(
getBuildConfig(new Package('@affine/web'), {
mode: 'development',
channel: 'canary',
})
).reduce((envs, [key, value]) => {
envs[`BUILD_CONFIG.${key}`] = JSON.stringify(value);
return envs;
}, {}),
},
define: Object.entries(
getBuildConfig(new Package('@affine/web'), {
mode: 'development',
channel: 'canary',
})
).reduce((envs, [key, value]) => {
envs[`BUILD_CONFIG.${key}`] = JSON.stringify(value);
return envs;
}, {}),
});
},

View File

@@ -7,7 +7,6 @@ import { useDebugValue, useEffect, useState } from 'react';
/* eslint-disable react-hooks/exhaustive-deps */
// the `process.env.NODE_ENV !== 'production'` condition is resolved by the build tool
/* eslint-disable react-hooks/rules-of-hooks */
const noop: (...args: any[]) => any = () => {};
@@ -67,7 +66,7 @@ export const useRefEffect = <T>(
// Show the current ref value in development
// in react dev tools
if (process.env.NODE_ENV !== 'production') {
if (BUILD_CONFIG.debug) {
useDebugValue(internalRef.ref_.current);
}

View File

@@ -7,8 +7,6 @@
import type { PropertyDeclaration } from 'lit';
import type React from 'react';
const DEV_MODE = process.env.NODE_ENV !== 'production';
type DistributiveOmit<T, K extends string | number | symbol> = T extends any
? K extends keyof T
? Omit<T, K>
@@ -245,7 +243,7 @@ export const createComponent = <
}: Options<I, E>): ReactWebComponent<I, E> => {
const eventProps = new Set(Object.keys(events ?? {}));
if (DEV_MODE) {
if (BUILD_CONFIG.debug) {
for (const p of reservedReactProperties) {
if (p in elementClass.prototype && !(p in HTMLElement.prototype)) {
// Note, this effectively warns only for `ref` since the other

View File

@@ -1,3 +1,4 @@
import { getWorkerUrl } from '@affine/env/worker';
import { ListLayoutHandlerExtension } from '@blocksuite/affine/blocks/list';
import { ParagraphLayoutHandlerExtension } from '@blocksuite/affine/blocks/paragraph';
import {
@@ -6,15 +7,7 @@ import {
} from '@blocksuite/affine/gfx/turbo-renderer';
function createPainterWorker() {
const worker = new Worker(
/* webpackChunkName: "turbo-painter-entry" */ new URL(
'./turbo-painter-entry.worker.ts',
import.meta.url
),
{
type: 'module',
}
);
const worker = new Worker(getWorkerUrl('turbo-painter-entry.worker.js'));
return worker;
}

View File

@@ -1,5 +1,5 @@
import { mixpanel, sentry } from '@affine/track';
import { APP_SETTINGS_STORAGE_KEY } from '@toeverything/infra';
import { APP_SETTINGS_STORAGE_KEY } from '@toeverything/infra/atom';
mixpanel.init();
sentry.init();

View File

@@ -36,7 +36,7 @@ export const Captcha = () => {
return (
<Turnstile
className={style.captchaWrapper}
siteKey={process.env.CAPTCHA_SITE_KEY || '1x00000000000000000000AA'}
siteKey={BUILD_CONFIG.CAPTCHA_SITE_KEY || '1x00000000000000000000AA'}
onSuccess={handleTurnstileSuccess}
/>
);

View File

@@ -9,19 +9,24 @@ import { DebugLogger } from '@affine/debug';
import { apis } from '@affine/electron-api';
import { useI18n } from '@affine/i18n';
import { useService } from '@toeverything/infra';
import { useLayoutEffect } from 'react';
import { useLayoutEffect, useRef } from 'react';
const logger = new DebugLogger('ImportWorkspaceDialog');
export const ImportWorkspaceDialog = ({
close,
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['import-workspace']>) => {
const effectRef = useRef(false);
const t = useI18n();
const workspacesService = useService(WorkspacesService);
// TODO(@Peng): maybe refactor using xstate?
useLayoutEffect(() => {
let canceled = false;
if (effectRef.current) {
return;
}
effectRef.current = true;
// a hack for now
// when adding a workspace, we will immediately let user select a db file
// after it is done, it will effectively add a new workspace to app-data folder
@@ -32,7 +37,7 @@ export const ImportWorkspaceDialog = ({
}
logger.info('load db file');
const result = await apis.dialog.loadDBFile();
if (result.workspaceId && !canceled) {
if (result.workspaceId) {
_addLocalWorkspace(result.workspaceId);
workspacesService.list.revalidate();
close({
@@ -50,9 +55,6 @@ export const ImportWorkspaceDialog = ({
})().catch(err => {
console.error(err);
});
return () => {
canceled = true;
};
}, [close, t, workspacesService]);
return null;

View File

@@ -191,13 +191,9 @@ export const BackupSettingPanel = () => {
const t = useI18n();
const backupService = useService(BackupService);
const handlePageChange = useCallback(() => {
backupService.revalidate();
}, [backupService]);
useEffect(() => {
backupService.revalidate();
}, [backupService, handlePageChange]);
}, [backupService]);
const isLoading = useLiveData(backupService.isLoading$);
const backupWorkspaces = useLiveData(backupService.pageBackupWorkspaces$);

View File

@@ -1,3 +1,4 @@
import { getWorkerUrl } from '@affine/env/worker';
import { OpClient } from '@toeverything/infra/op';
import type { ClientOps } from './ops';
@@ -6,12 +7,7 @@ export class PDFRenderer extends OpClient<ClientOps> {
private readonly worker: Worker;
constructor() {
const worker = new Worker(
/* webpackChunkName: "pdf.worker" */ new URL(
'./worker.ts',
import.meta.url
)
);
const worker = new Worker(getWorkerUrl('pdf.worker.js'));
super(worker);
this.worker = worker;

View File

@@ -1,3 +1,4 @@
import { getWorkerUrl } from '@affine/env/worker';
import { OpClient } from '@toeverything/infra/op';
import type { WorkerOps } from './worker-ops';
@@ -9,12 +10,7 @@ export function getWorkspaceProfileWorker() {
return worker;
}
const rawWorker = new Worker(
new URL(
/* webpackChunkName: "workspace-profile-worker" */ './in-worker.ts',
import.meta.url
)
);
const rawWorker = new Worker(getWorkerUrl('workspace-profile.worker.js'));
worker = new OpClient<WorkerOps>(rawWorker);
return worker;

View File

@@ -23,8 +23,7 @@ export const schemeToChannel = {
export const channelToScheme = {
stable: 'affine',
canary:
process.env.NODE_ENV === 'development' ? 'affine-dev' : 'affine-canary',
canary: BUILD_CONFIG.debug ? 'affine-dev' : 'affine-canary',
beta: 'affine-beta',
internal: 'affine-internal',
} as Record<Channel, Scheme>;

View File

@@ -36,7 +36,7 @@ export const createIsland = () => {
Provider: ({ children }: React.PropsWithChildren) => {
const target = useLiveData(targetLiveData$);
useEffect(() => {
if (provided === true && process.env.NODE_ENV !== 'production') {
if (provided === true && BUILD_CONFIG.debug) {
throw new Error('Island should not be provided more than once');
}
provided = true;

View File

@@ -11,8 +11,8 @@ type Middleware = (
function createMixpanel() {
let mixpanel;
if (process.env.MIXPANEL_TOKEN) {
mixpanelBrowser.init(process.env.MIXPANEL_TOKEN || '', {
if (BUILD_CONFIG.MIXPANEL_TOKEN) {
mixpanelBrowser.init(BUILD_CONFIG.MIXPANEL_TOKEN || '', {
track_pageview: true,
persistence: 'localStorage',
api_host: 'https://telemetry.affine.run',

View File

@@ -14,9 +14,9 @@ function createSentry() {
if (!globalThis.SENTRY_RELEASE) {
// https://docs.sentry.io/platforms/javascript/guides/react/#configure
client = Sentry.init({
dsn: process.env.SENTRY_DSN,
dsn: BUILD_CONFIG.SENTRY_DSN,
debug: BUILD_CONFIG.debug ?? false,
environment: process.env.BUILD_TYPE ?? 'development',
environment: BUILD_CONFIG.appBuildType,
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect,