Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add preStart hook and port existing startLogic impls #3720

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/api/core/src/api/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ export default autoTrace(
}
),
},
{
title: `Running ${chalk.yellow('preStart')} hook`,
task: childTrace<Parameters<ForgeListrTaskFn<StartContext>>>(
{ name: 'run-preStart-hook', category: '@electron-forge/core' },
async (childTrace, { forgeConfig }, task) => {
return delayTraceTillSignal(childTrace, task.newListr(await getHookListrTasks(childTrace, forgeConfig, 'preStart')), 'run');
}
),
},
],
listrOptions
);
Expand Down
17 changes: 8 additions & 9 deletions packages/plugin/local-electron/src/LocalElectronPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export default class LocalElectronPlugin extends PluginBase<LocalElectronPluginC
super(c);

this.getHooks = this.getHooks.bind(this);
this.startLogic = this.startLogic.bind(this);
}

get enabled(): boolean {
Expand All @@ -21,16 +20,9 @@ export default class LocalElectronPlugin extends PluginBase<LocalElectronPluginC
return this.config.enabled;
}

async startLogic(): Promise<false> {
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,
};
}
Expand All @@ -49,6 +41,13 @@ export default class LocalElectronPlugin extends PluginBase<LocalElectronPluginC
}
};

private preStart: ForgeHookFn<'preStart'> = 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;

Expand Down
16 changes: 5 additions & 11 deletions packages/plugin/local-electron/test/LocalElectronPlugin_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand All @@ -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', () => {
Expand Down
66 changes: 32 additions & 34 deletions packages/plugin/vite/src/VitePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -56,6 +56,37 @@ export default class VitePlugin extends PluginBase<VitePluginConfig> {

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;
Expand Down Expand Up @@ -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<StartResult> => {
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<void> => {
const configs = await this.configGenerator.getBuildConfig();
Expand Down
75 changes: 36 additions & 39 deletions packages/plugin/webpack/src/WebpackPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -70,7 +70,6 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
}
}

this.startLogic = this.startLogic.bind(this);
this.getHooks = this.getHooks.bind(this);
}

Expand Down Expand Up @@ -158,6 +157,41 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {

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) {
Expand Down Expand Up @@ -563,43 +597,6 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`);
}

private alreadyStarted = false;

async startLogic(): Promise<StartResult> {
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 };
1 change: 1 addition & 0 deletions packages/utils/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down