diff --git a/packages/api/core/src/api/start.ts b/packages/api/core/src/api/start.ts index 3c30718fa9..be7380b3d7 100644 --- a/packages/api/core/src/api/start.ts +++ b/packages/api/core/src/api/start.ts @@ -112,6 +112,15 @@ export default autoTrace( } ), }, + { + title: `Running ${chalk.yellow('preStart')} hook`, + task: childTrace>>( + { name: 'run-preStart-hook', category: '@electron-forge/core' }, + async (childTrace, { forgeConfig }, task) => { + return delayTraceTillSignal(childTrace, task.newListr(await getHookListrTasks(childTrace, forgeConfig, 'preStart')), 'run'); + } + ), + }, ], listrOptions ); diff --git a/packages/plugin/local-electron/src/LocalElectronPlugin.ts b/packages/plugin/local-electron/src/LocalElectronPlugin.ts index 4995a19b47..98f09c21c8 100644 --- a/packages/plugin/local-electron/src/LocalElectronPlugin.ts +++ b/packages/plugin/local-electron/src/LocalElectronPlugin.ts @@ -11,7 +11,6 @@ export default class LocalElectronPlugin extends PluginBase { - if (this.enabled) { - this.checkPlatform(process.platform); - process.env.ELECTRON_OVERRIDE_DIST_PATH = this.config.electronPath; - } - return false; - } - getHooks(): ForgeHookMap { return { + preStart: this.preStart, packageAfterExtract: this.afterExtract, }; } @@ -49,6 +41,13 @@ export default class LocalElectronPlugin extends PluginBase = async () => { + if (this.enabled) { + this.checkPlatform(process.platform); + process.env.ELECTRON_OVERRIDE_DIST_PATH = this.config.electronPath; + } + }; + private afterExtract: ForgeHookFn<'packageAfterExtract'> = async (_config, buildPath, _electronVersion, platform, arch) => { if (!this.enabled) return; diff --git a/packages/plugin/local-electron/test/LocalElectronPlugin_spec.ts b/packages/plugin/local-electron/test/LocalElectronPlugin_spec.ts index df547f7691..ea1f90e2df 100644 --- a/packages/plugin/local-electron/test/LocalElectronPlugin_spec.ts +++ b/packages/plugin/local-electron/test/LocalElectronPlugin_spec.ts @@ -9,6 +9,8 @@ import { LocalElectronPlugin } from '../src/LocalElectronPlugin'; describe('LocalElectronPlugin', () => { describe('start logic', () => { + const fakeForgeConfig = {} as ResolvedForgeConfig; + before(() => { delete process.env.ELECTRON_OVERRIDE_DIST_PATH; }); @@ -20,31 +22,23 @@ describe('LocalElectronPlugin', () => { it('should set ELECTRON_OVERRIDE_DIST_PATH when enabled', async () => { expect(process.env.ELECTRON_OVERRIDE_DIST_PATH).to.equal(undefined); const p = new LocalElectronPlugin({ electronPath: 'test/foo' }); - await p.startLogic(); + await p.getHooks().preStart?.(fakeForgeConfig); expect(process.env.ELECTRON_OVERRIDE_DIST_PATH).to.equal('test/foo'); }); it('should not set ELECTRON_OVERRIDE_DIST_PATH when disabled', async () => { expect(process.env.ELECTRON_OVERRIDE_DIST_PATH).to.equal(undefined); const p = new LocalElectronPlugin({ enabled: false, electronPath: 'test/foo' }); - await p.startLogic(); + await p.getHooks().preStart?.(fakeForgeConfig); expect(process.env.ELECTRON_OVERRIDE_DIST_PATH).to.equal(undefined); }); it("should throw an error if platforms don't match", async () => { const p = new LocalElectronPlugin({ electronPath: 'test/bar', electronPlatform: 'wut' }); - await expect(p.startLogic()).to.eventually.be.rejectedWith( + await expect(p.getHooks().preStart?.(fakeForgeConfig)).to.eventually.be.rejectedWith( `Can not use local Electron version, required platform "${process.platform}" but local platform is "wut"` ); }); - - it('should always return false', async () => { - let p = new LocalElectronPlugin({ electronPath: 'test/bar' }); - expect(await p.startLogic()).to.equal(false); - - p = new LocalElectronPlugin({ enabled: false, electronPath: 'test/bar' }); - expect(await p.startLogic()).to.equal(false); - }); }); describe('hooks', () => { diff --git a/packages/plugin/vite/src/VitePlugin.ts b/packages/plugin/vite/src/VitePlugin.ts index 821e511f61..d6ce589409 100644 --- a/packages/plugin/vite/src/VitePlugin.ts +++ b/packages/plugin/vite/src/VitePlugin.ts @@ -11,7 +11,7 @@ import { onBuildDone } from './util/plugins'; import ViteConfigGenerator from './ViteConfig'; import type { VitePluginConfig } from './Config'; -import type { ForgeMultiHookMap, ResolvedForgeConfig, StartResult } from '@electron-forge/shared-types'; +import type { ForgeMultiHookMap, ResolvedForgeConfig } from '@electron-forge/shared-types'; import type { AddressInfo } from 'node:net'; // eslint-disable-next-line node/no-extraneous-import import type { RollupWatcher } from 'rollup'; @@ -56,6 +56,37 @@ export default class VitePlugin extends PluginBase { getHooks = (): ForgeMultiHookMap => { return { + preStart: [ + namedHookWithTaskFn<'preStart'>(async (task) => { + if (VitePlugin.alreadyStarted) return; + VitePlugin.alreadyStarted = true; + + await fs.remove(this.baseDir); + + return task?.newListr([ + { + title: 'Launching dev servers for renderer process code', + task: async () => { + await this.launchRendererDevServers(); + }, + rendererOptions: { + persistentOutput: true, + timer: { ...PRESET_TIMER }, + }, + }, + // The main process depends on the `server.port` of the renderer process, so the renderer process is run first. + { + title: 'Compiling main process code', + task: async () => { + await this.build(); + }, + rendererOptions: { + timer: { ...PRESET_TIMER }, + }, + }, + ]) as any; + }, 'Preparing vite bundles'), + ], prePackage: [ namedHookWithTaskFn<'prePackage'>(async () => { this.isProd = true; @@ -118,39 +149,6 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`); await fs.writeJson(path.resolve(buildPath, 'package.json'), pj, { spaces: 2 }); }; - startLogic = async (): Promise => { - if (VitePlugin.alreadyStarted) return false; - VitePlugin.alreadyStarted = true; - - await fs.remove(this.baseDir); - - return { - tasks: [ - { - title: 'Launching dev servers for renderer process code', - task: async () => { - await this.launchRendererDevServers(); - }, - rendererOptions: { - persistentOutput: true, - timer: { ...PRESET_TIMER }, - }, - }, - // The main process depends on the `server.port` of the renderer process, so the renderer process is run first. - { - title: 'Compiling main process code', - task: async () => { - await this.build(); - }, - rendererOptions: { - timer: { ...PRESET_TIMER }, - }, - }, - ], - result: false, - }; - }; - // Main process, Preload scripts and Worker process, etc. build = async (): Promise => { const configs = await this.configGenerator.getBuildConfig(); diff --git a/packages/plugin/webpack/src/WebpackPlugin.ts b/packages/plugin/webpack/src/WebpackPlugin.ts index ef28e0692d..c2381abf21 100644 --- a/packages/plugin/webpack/src/WebpackPlugin.ts +++ b/packages/plugin/webpack/src/WebpackPlugin.ts @@ -5,7 +5,7 @@ import { pipeline } from 'stream/promises'; import { getElectronVersion, listrCompatibleRebuildHook } from '@electron-forge/core-utils'; import { namedHookWithTaskFn, PluginBase } from '@electron-forge/plugin-base'; -import { ForgeMultiHookMap, ListrTask, ResolvedForgeConfig, StartResult } from '@electron-forge/shared-types'; +import { ForgeMultiHookMap, ListrTask, ResolvedForgeConfig } from '@electron-forge/shared-types'; import Logger, { Tab } from '@electron-forge/web-multi-logger'; import chalk from 'chalk'; import debug from 'debug'; @@ -70,7 +70,6 @@ export default class WebpackPlugin extends PluginBase { } } - this.startLogic = this.startLogic.bind(this); this.getHooks = this.getHooks.bind(this); } @@ -158,6 +157,41 @@ export default class WebpackPlugin extends PluginBase { getHooks(): ForgeMultiHookMap { return { + preStart: [ + namedHookWithTaskFn<'preStart'>(async (task) => { + if (this.alreadyStarted) return false; + this.alreadyStarted = true; + + await fs.remove(this.baseDir); + + const logger = new Logger(this.loggerPort); + this.loggers.push(logger); + await logger.start(); + + return task?.newListr([ + { + title: 'Compiling main process code', + task: async () => { + await this.compileMain(true, logger); + }, + rendererOptions: { + timer: { ...PRESET_TIMER }, + }, + }, + { + title: 'Launching dev servers for renderer process code', + task: async (_, task) => { + await this.launchRendererDevServers(logger); + task.output = `Output Available: ${chalk.cyan(`http://localhost:${this.loggerPort}`)}\n`; + }, + rendererOptions: { + persistentOutput: true, + timer: { ...PRESET_TIMER }, + }, + }, + ]) as any; + }, 'Preparing webpack bundles'), + ], prePackage: [ namedHookWithTaskFn<'prePackage'>(async (task, config, platform, arch) => { if (!task) { @@ -563,43 +597,6 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`); } private alreadyStarted = false; - - async startLogic(): Promise { - if (this.alreadyStarted) return false; - this.alreadyStarted = true; - - await fs.remove(this.baseDir); - - const logger = new Logger(this.loggerPort); - this.loggers.push(logger); - await logger.start(); - - return { - tasks: [ - { - title: 'Compiling main process code', - task: async () => { - await this.compileMain(true, logger); - }, - rendererOptions: { - timer: { ...PRESET_TIMER }, - }, - }, - { - title: 'Launching dev servers for renderer process code', - task: async (_, task) => { - await this.launchRendererDevServers(logger); - task.output = `Output Available: ${chalk.cyan(`http://localhost:${this.loggerPort}`)}\n`; - }, - rendererOptions: { - persistentOutput: true, - timer: { ...PRESET_TIMER }, - }, - }, - ], - result: false, - }; - } } export { WebpackPlugin, WebpackPluginConfig }; diff --git a/packages/utils/types/src/index.ts b/packages/utils/types/src/index.ts index dd1a988cd4..6c1f36db17 100644 --- a/packages/utils/types/src/index.ts +++ b/packages/utils/types/src/index.ts @@ -26,6 +26,7 @@ export type ForgeConfigPlugin = IForgeResolvablePlugin | IForgePlugin; export interface ForgeSimpleHookSignatures { generateAssets: [platform: ForgePlatform, version: ForgeArch]; + preStart: []; postStart: [appProcess: ElectronProcess]; prePackage: [platform: ForgePlatform, version: ForgeArch]; packageAfterCopy: [buildPath: string, electronVersion: string, platform: ForgePlatform, arch: ForgeArch];