From 31dc1f5e00533e1bb4153266284b52f15cf1365d Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Wed, 13 Dec 2023 05:17:17 +0000 Subject: [PATCH] fix(electron): use dynamic load for exposed meta (#5251) There is high possibilities of circular dependencies when importing `exposed-meta` module. Change it to dynamic import to mitigate the issue.. --- .../frontend/electron/src/main/deep-link.ts | 12 ++++-- packages/frontend/electron/src/main/index.ts | 6 +-- .../frontend/electron/src/main/main-window.ts | 38 +++++++++++------ .../frontend/electron/src/main/ui/handlers.ts | 41 +++++++++---------- 4 files changed, 56 insertions(+), 41 deletions(-) diff --git a/packages/frontend/electron/src/main/deep-link.ts b/packages/frontend/electron/src/main/deep-link.ts index bc5edb05f..d9d263cbd 100644 --- a/packages/frontend/electron/src/main/deep-link.ts +++ b/packages/frontend/electron/src/main/deep-link.ts @@ -5,7 +5,7 @@ import { type App, type BrowserWindow, ipcMain } from 'electron'; import { buildType, CLOUD_BASE_URL, isDev } from './config'; import { logger } from './logger'; import { - getOrCreateWindow, + getMainWindow, handleOpenUrlInHiddenWindow, mainWindowOrigin, removeCookie, @@ -39,8 +39,12 @@ export function setupDeepLink(app: App) { // on windows & linux, we need to listen for the second-instance event app.on('second-instance', (event, commandLine) => { - getOrCreateWindow() + getMainWindow() .then(window => { + if (!window) { + logger.error('main window is not ready'); + return; + } window.show(); const url = commandLine.pop(); if (url?.startsWith(`${protocol}://`)) { @@ -66,9 +70,9 @@ async function handleAffineUrl(url: string) { } async function handleOauthJwt(url: string) { - if (url) { + const mainWindow = await getMainWindow(); + if (url && mainWindow) { try { - const mainWindow = await getOrCreateWindow(); mainWindow.show(); const urlObj = new URL(url); const token = urlObj.searchParams.get('token'); diff --git a/packages/frontend/electron/src/main/index.ts b/packages/frontend/electron/src/main/index.ts index 3a38caa3f..321c04d79 100644 --- a/packages/frontend/electron/src/main/index.ts +++ b/packages/frontend/electron/src/main/index.ts @@ -11,7 +11,7 @@ import { registerEvents } from './events'; import { registerHandlers } from './handlers'; import { ensureHelperProcess } from './helper-process'; import { logger } from './logger'; -import { getOrCreateWindow } from './main-window'; +import { initMainWindow as initMainWindow } from './main-window'; import { registerProtocol } from './protocol'; import { registerUpdater } from './updater'; @@ -56,7 +56,7 @@ app.on('window-all-closed', () => { * @see https://www.electronjs.org/docs/v14-x-y/api/app#event-activate-macos Event: 'activate' */ app.on('activate', () => { - getOrCreateWindow().catch(e => + initMainWindow().catch(e => console.error('Failed to restore or create window:', e) ); }); @@ -72,7 +72,7 @@ app .then(registerHandlers) .then(registerEvents) .then(ensureHelperProcess) - .then(getOrCreateWindow) + .then(initMainWindow) .then(createApplicationMenu) .then(registerUpdater) .catch(e => console.error('Failed create window:', e)); diff --git a/packages/frontend/electron/src/main/main-window.ts b/packages/frontend/electron/src/main/main-window.ts index c4234adfa..ad31168b6 100644 --- a/packages/frontend/electron/src/main/main-window.ts +++ b/packages/frontend/electron/src/main/main-window.ts @@ -5,10 +5,9 @@ import electronWindowState from 'electron-window-state'; import { join } from 'path'; import { isMacOS, isWindows } from '../shared/utils'; -import { getExposedMeta } from './exposed'; import { ensureHelperProcess } from './helper-process'; import { logger } from './logger'; -import { uiSubjects } from './ui'; +import { uiSubjects } from './ui/subject'; import { parseCookie } from './utils'; const IS_DEV: boolean = @@ -18,7 +17,19 @@ const DEV_TOOL = process.env.DEV_TOOL === 'true'; export const mainWindowOrigin = process.env.DEV_SERVER_URL || 'file://.'; -async function createWindow() { +// todo: not all window need all of the exposed meta +const getWindowAdditionalArguments = async () => { + const { getExposedMeta } = await import('./exposed'); + const mainExposedMeta = getExposedMeta(); + const helperProcessManager = await ensureHelperProcess(); + const helperExposedMeta = await helperProcessManager.rpc?.getMeta(); + return [ + `--main-exposed-meta=` + JSON.stringify(mainExposedMeta), + `--helper-exposed-meta=` + JSON.stringify(helperExposedMeta), + ]; +}; + +async function createWindow(additionalArguments: string[]) { logger.info('create window'); const mainWindowState = electronWindowState({ defaultWidth: 1000, @@ -30,8 +41,6 @@ async function createWindow() { assert(helperExposedMeta, 'helperExposedMeta should be defined'); - const mainExposedMeta = getExposedMeta(); - const browserWindow = new BrowserWindow({ titleBarStyle: isMacOS() ? 'hiddenInset' @@ -56,10 +65,7 @@ async function createWindow() { spellcheck: false, // FIXME: enable? preload: join(__dirname, './preload.js'), // serialize exposed meta that to be used in preload - additionalArguments: [ - `--main-exposed-meta=` + JSON.stringify(mainExposedMeta), - `--helper-exposed-meta=` + JSON.stringify(helperExposedMeta), - ], + additionalArguments: additionalArguments, }, }); @@ -146,16 +152,24 @@ async function createWindow() { let browserWindow$: Promise | undefined; /** - * Restore existing BrowserWindow or Create new BrowserWindow + * Init main BrowserWindow. Will create a new window if it's not created yet. */ -export async function getOrCreateWindow() { +export async function initMainWindow() { if (!browserWindow$ || (await browserWindow$.then(w => w.isDestroyed()))) { - browserWindow$ = createWindow(); + const additionalArguments = await getWindowAdditionalArguments(); + browserWindow$ = createWindow(additionalArguments); } const mainWindow = await browserWindow$; return mainWindow; } +export async function getMainWindow() { + if (!browserWindow$) return; + const window = await browserWindow$; + if (window.isDestroyed()) return; + return window; +} + export async function handleOpenUrlInHiddenWindow(url: string) { const win = new BrowserWindow({ width: 1200, diff --git a/packages/frontend/electron/src/main/ui/handlers.ts b/packages/frontend/electron/src/main/ui/handlers.ts index 5e41a4625..f1e9096c5 100644 --- a/packages/frontend/electron/src/main/ui/handlers.ts +++ b/packages/frontend/electron/src/main/ui/handlers.ts @@ -1,8 +1,9 @@ -import { app, BrowserWindow, nativeTheme } from 'electron'; +import { app, nativeTheme } from 'electron'; import { getLinkPreview } from 'link-preview-js'; import { isMacOS } from '../../shared/utils'; import { logger } from '../logger'; +import { getMainWindow } from '../main-window'; import type { NamespaceHandlers } from '../type'; import { getChallengeResponse } from './challenge'; import { getGoogleOauthCode } from './google-auth'; @@ -13,32 +14,28 @@ export const uiHandlers = { }, handleSidebarVisibilityChange: async (_, visible: boolean) => { if (isMacOS()) { - const windows = BrowserWindow.getAllWindows(); - windows.forEach(w => { - // hide window buttons when sidebar is not visible - w.setWindowButtonVisibility(visible); - }); + const window = await getMainWindow(); + window?.setWindowButtonVisibility(visible); } }, handleMinimizeApp: async () => { - const windows = BrowserWindow.getAllWindows(); - windows.forEach(w => { - w.minimize(); - }); + const window = await getMainWindow(); + window?.minimize(); }, handleMaximizeApp: async () => { - const windows = BrowserWindow.getAllWindows(); - windows.forEach(w => { - // allow unmaximize when in full screen mode - if (w.isFullScreen()) { - w.setFullScreen(false); - w.unmaximize(); - } else if (w.isMaximized()) { - w.unmaximize(); - } else { - w.maximize(); - } - }); + const window = await getMainWindow(); + if (!window) { + return; + } + // allow unmaximize when in full screen mode + if (window.isFullScreen()) { + window.setFullScreen(false); + window.unmaximize(); + } else if (window.isMaximized()) { + window.unmaximize(); + } else { + window.maximize(); + } }, handleCloseApp: async () => { app.quit();