diff --git a/apps/edit-docs/src/edit-demo.ts b/apps/edit-docs/src/edit-demo.ts index 162467ae6..a51e48e73 100644 --- a/apps/edit-docs/src/edit-demo.ts +++ b/apps/edit-docs/src/edit-demo.ts @@ -7,11 +7,14 @@ import { join } from "path"; const DEMO_ZIP_PATH = join(__dirname, "../../server/src/assets/db/demo.zip"); async function main() { + const initializedPromise = startElectron(() => { + // Wait for the import to be finished and the application to be loaded before we listen to changes. + setTimeout(() => registerHandlers(), 10_000); + }); + await initializeTranslations(); await initializeDatabase(false); - - await startElectron(); - await registerHandlers(); + initializedPromise.resolve(); } async function registerHandlers() { diff --git a/apps/edit-docs/src/edit-docs.ts b/apps/edit-docs/src/edit-docs.ts index 889e2f55c..7266ad323 100644 --- a/apps/edit-docs/src/edit-docs.ts +++ b/apps/edit-docs/src/edit-docs.ts @@ -6,16 +6,13 @@ import { initializeTranslations } from "@triliumnext/server/src/services/i18n.js import archiver, { type Archiver } from "archiver"; import type { WriteStream } from "fs"; import debounce from "@triliumnext/client/src/services/debounce.js"; -import { extractZip, initializeDatabase } from "./utils.js"; +import { extractZip, initializeDatabase, startElectron } from "./utils.js"; import cls from "@triliumnext/server/src/services/cls.js"; import type { AdvancedExportOptions } from "@triliumnext/server/src/services/export/zip.js"; import TaskContext from "@triliumnext/server/src/services/task_context.js"; -import { deferred } from "@triliumnext/server/src/services/utils.js"; import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js"; import { resolve } from "path"; import type NoteMeta from "@triliumnext/server/src/services/meta/note_meta.js"; -import electron from "electron"; -import windowService from "@triliumnext/server/src/services/window.js"; interface NoteMapping { rootNoteId: string; @@ -56,18 +53,7 @@ const NOTE_MAPPINGS: NoteMapping[] = [ ]; async function main() { - const initializedPromise = deferred(); - electron.app.on("ready", async () => { - await initializedPromise; - - console.log("Electron is ready!"); - - // Start the server. - await import("@triliumnext/server/src/main.js"); - - // Create the main window. - await windowService.createMainWindow(electron.app); - + const initializedPromise = startElectron(() => { // Wait for the import to be finished and the application to be loaded before we listen to changes. setTimeout(() => registerHandlers(), 10_000); }); diff --git a/apps/edit-docs/src/utils.ts b/apps/edit-docs/src/utils.ts index 8c7758f62..fc11eb8fb 100644 --- a/apps/edit-docs/src/utils.ts +++ b/apps/edit-docs/src/utils.ts @@ -2,6 +2,9 @@ import cls from "@triliumnext/server/src/services/cls.js"; import fs from "fs/promises"; import fsExtra from "fs-extra"; import path from "path"; +import electron from "electron"; +import { deferred, type DeferredPromise } from "@triliumnext/server/src/services/utils.js"; +import windowService from "@triliumnext/server/src/services/window.js"; export function initializeDatabase(skipDemoDb: boolean) { return new Promise(async (resolve) => { @@ -15,8 +18,30 @@ export function initializeDatabase(skipDemoDb: boolean) { }); } -export async function startElectron() { - await import("@triliumnext/desktop/src/electron-main.js"); +/** + * Electron has a behaviour in which the "ready" event must have a listener attached before it gets to initialize. + * If async tasks are awaited before the "ready" event is bound, then the window will never shown. + * This method works around by creating a deferred promise. It will immediately bind to the "ready" event and wait for that promise to be resolved externally. + * + * @param callback a method to be called after the server and Electron is initialized. + * @returns the deferred promise that must be resolved externally before the Electron app is started. + */ +export function startElectron(callback: () => void): DeferredPromise { + const initializedPromise = deferred(); + electron.app.on("ready", async () => { + await initializedPromise; + + console.log("Electron is ready!"); + + // Start the server. + await import("@triliumnext/server/src/main.js"); + + // Create the main window. + await windowService.createMainWindow(electron.app); + + callback(); + }); + return initializedPromise; } export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set) {