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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: improve forge configuration DX #2963

Merged
merged 3 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 15 additions & 11 deletions packages/api/core/src/api/make.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { asyncOra } from '@electron-forge/async-ora';
import chalk from 'chalk';
import { getHostArch } from '@electron/get';
import { IForgeResolvableMaker, ForgeConfig, ForgeArch, ForgePlatform, ForgeMakeResult } from '@electron-forge/shared-types';
import { IForgeResolvableMaker, ForgeConfig, ForgeArch, ForgePlatform, ForgeMakeResult, ForgeConfigMaker } from '@electron-forge/shared-types';
import MakerBase from '@electron-forge/maker-base';
import fs from 'fs-extra';
import path from 'path';
Expand All @@ -26,14 +26,13 @@ class MakerImpl extends MakerBase<any> {
defaultPlatforms = [];
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type MakeTarget = IForgeResolvableMaker | MakerBase<any> | string;
type MakeTargets = ForgeConfigMaker[] | string[];

function generateTargets(forgeConfig: ForgeConfig, overrideTargets?: MakeTarget[]) {
function generateTargets(forgeConfig: ForgeConfig, overrideTargets?: MakeTargets) {
if (overrideTargets) {
return overrideTargets.map((target) => {
if (typeof target === 'string') {
return forgeConfig.makers.find((maker) => (maker as IForgeResolvableMaker).name === target) || { name: target };
return forgeConfig.makers.find((maker) => (maker as IForgeResolvableMaker).name === target) || ({ name: target } as IForgeResolvableMaker);
}

return target;
Expand All @@ -42,6 +41,12 @@ function generateTargets(forgeConfig: ForgeConfig, overrideTargets?: MakeTarget[
return forgeConfig.makers;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isElectronForgeMaker(target: MakerBase<any> | unknown): target is MakerBase<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (target as MakerBase<any>).__isElectronForgeMaker;
}

export interface MakeOptions {
/**
* The path to the app from which distrubutables are generated
Expand All @@ -58,7 +63,7 @@ export interface MakeOptions {
/**
* An array of make targets to override your forge config
*/
overrideTargets?: MakeTarget[];
overrideTargets?: MakeTargets;
/**
* The target architecture
*/
Expand Down Expand Up @@ -110,14 +115,13 @@ export default async ({

let targetId = 0;
for (const target of targets) {
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
let maker: MakerBase<any>;
if ((target as MakerBase<any>).__isElectronForgeMaker) {
maker = target as MakerBase<any>;
/* eslint-enable @typescript-eslint/no-explicit-any */
if (isElectronForgeMaker(target)) {
maker = target;
if (!maker.platforms.includes(actualTargetPlatform)) continue;
} else {
const resolvableTarget: IForgeResolvableMaker = target as IForgeResolvableMaker;
const resolvableTarget = target as IForgeResolvableMaker;
// non-false falsy values should be 'true'
if (resolvableTarget.enabled === false) continue;

Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/src/api/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export default async ({
done();
},
async (buildPath, electronVersion, pPlatform, pArch, done) => {
await rebuildHook(buildPath, electronVersion, pPlatform, pArch, forgeConfig.electronRebuildConfig);
await rebuildHook(buildPath, electronVersion, pPlatform, pArch, forgeConfig.rebuildConfig);
packagerSpinner = ora('Packaging Application').start();
done();
},
Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/src/api/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface PublishOptions {
* The publish targets, by default pulled from forge config, set this prop to
* override that list
*/
publishTargets?: ForgeConfigPublisher[];
publishTargets?: ForgeConfigPublisher[] | string[];
/**
* Options object to passed through to make()
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/src/api/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default async ({
const platform = process.env.npm_config_platform || process.platform;
const arch = process.env.npm_config_arch || process.arch;

await rebuild(dir, await getElectronVersion(dir, packageJSON), platform as ForgePlatform, arch as ForgeArch, forgeConfig.electronRebuildConfig);
await rebuild(dir, await getElectronVersion(dir, packageJSON), platform as ForgePlatform, arch as ForgeArch, forgeConfig.rebuildConfig);

await runHook(forgeConfig, 'generateAssets', platform, arch);

Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/src/util/forge-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default async (dir: string): Promise<ForgeConfig> => {
throw new Error('Expected packageJSON.config.forge to be an object or point to a requirable JS file');
}
const defaultForgeConfig = {
electronRebuildConfig: {},
rebuildConfig: {},
packagerConfig: {},
makers: [],
publishers: [],
Expand Down
15 changes: 10 additions & 5 deletions packages/api/core/src/util/plugin-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,35 @@ import requireSearch from './require-search';

const d = debug('electron-forge:plugins');

function isForgePlugin(plugin: IForgePlugin | unknown): plugin is IForgePlugin {
return (plugin as IForgePlugin).__isElectronForgePlugin;
}

export default class PluginInterface implements IForgePluginInterface {
private plugins: IForgePlugin[];

private config: ForgeConfig;

constructor(dir: string, forgeConfig: ForgeConfig) {
this.plugins = forgeConfig.plugins.map((plugin) => {
if ((plugin as IForgePlugin).__isElectronForgePlugin) {
if (isForgePlugin(plugin)) {
return plugin;
}

if (Array.isArray(plugin)) {
const [pluginName, opts = {}] = plugin;
if (typeof plugin === 'object' && 'name' in plugin && 'config' in plugin) {
const { name: pluginName, config: opts } = plugin;
if (typeof pluginName !== 'string') {
throw new Error(`Expected plugin[0] to be a string but found ${pluginName}`);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Plugin = requireSearch<any>(dir, [pluginName]);
if (!Plugin) {
throw new Error(`Could not find module with name: ${plugin[0]}. Make sure it's listed in the devDependencies of your package.json`);
throw new Error(`Could not find module with name: ${pluginName}. Make sure it's listed in the devDependencies of your package.json`);
}
return new Plugin(opts);
}
throw new Error(`Expected plugin to either be a plugin instance or [string, object] but found ${plugin}`);

throw new Error(`Expected plugin to either be a plugin instance or a { name, config } object but found ${plugin}`);
});
// TODO: fix hack
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/src/util/upgrade-forge-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export default function upgradeForgeConfig(forge5Config: Forge5Config): ForgeCon
forgeConfig.packagerConfig = forge5Config.electronPackagerConfig;
}
if (forge5Config.electronRebuildConfig) {
forgeConfig.electronRebuildConfig = forge5Config.electronRebuildConfig;
forgeConfig.rebuildConfig = forge5Config.electronRebuildConfig;
}
forgeConfig.makers = generateForgeMakerConfig(forge5Config);
forgeConfig.publishers = generateForgePublisherConfig(forge5Config);
Expand Down
17 changes: 10 additions & 7 deletions packages/api/core/test/fast/forge-config_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import findConfig, {

const defaults = {
packagerConfig: {},
electronRebuildConfig: {},
rebuildConfig: {},
makers: [],
publishers: [],
plugins: [],
Expand Down Expand Up @@ -220,12 +220,15 @@ describe('forge-config', () => {
config: {
forge: {
makers: [
{
name: '@electron-forge/maker-test',
config: {
name: 'will be overwritten',
},
},
// {
// name: '@electron-forge/maker-test',
// config: {
// name: 'will be overwritten',
// },
// },
// new MakerZip({
// name: 'will be overwritten',
// }),
],
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/test/fast/publish_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('publish', () => {
publisherSpy = stub();
voidStub = stub();
nowhereStub = stub();
publishers = ['@electron-forge/publisher-test'];
publishers = [{ name: '@electron-forge/publisher-test' }];
const fakePublisher = (stub: SinonStub, name = 'default') =>
class _FakePublisher {
private publish: SinonStub;
Expand Down
2 changes: 1 addition & 1 deletion packages/api/core/test/fast/read-package-json_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { readRawPackageJson, readMutatedPackageJson } from '../../src/util/read-

const emptyForgeConfig: Partial<ForgeConfig> = {
packagerConfig: {},
electronRebuildConfig: {},
rebuildConfig: {},
makers: [],
publishers: [],
plugins: [],
Expand Down
4 changes: 2 additions & 2 deletions packages/api/core/test/fast/upgrade-forge-config_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('upgradeForgeConfig', () => {
const oldConfig = { electronRebuildConfig: { ...rebuildConfig } };

const newConfig = upgradeForgeConfig(oldConfig);
expect(newConfig.electronRebuildConfig).to.deep.equal(rebuildConfig);
expect(newConfig.rebuildConfig).to.deep.equal(rebuildConfig);
});

it('converts maker config', () => {
Expand Down Expand Up @@ -116,7 +116,7 @@ describe('updateUpgradedForgeDevDeps', () => {
config: {
forge: {
packagerConfig: {},
electronRebuildConfig: {},
rebuildConfig: {},
makers: [],
publishers: [],
plugins: [],
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/webpack/src/WebpackPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
await utils.getElectronVersion(this.projectDir, await fs.readJson(path.join(this.projectDir, 'package.json'))),
platform,
arch,
config.electronRebuildConfig
config.rebuildConfig
);
await this.compileMain();
await this.compileRenderers();
Expand Down
22 changes: 16 additions & 6 deletions packages/utils/types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChildProcess } from 'child_process';
import { ArchOption, Options, TargetPlatform } from 'electron-packager';
import { ArchOption, Options as ElectronPackagerOptions, TargetPlatform } from 'electron-packager';
import { RebuildOptions } from 'electron-rebuild';

export type ElectronProcess = ChildProcess & { restarted: boolean };
Expand All @@ -9,13 +9,18 @@ export type ForgeArch = ArchOption;
// Why: hooks have any number/kind of args/return values
/* eslint-disable @typescript-eslint/no-explicit-any */
export type ForgeHookFn = (forgeConfig: ForgeConfig, ...args: any[]) => Promise<any>;
export type ForgeConfigPublisher = IForgeResolvablePublisher | IForgePublisher | string;
export type ForgeConfigPublisher = IForgeResolvablePublisher | IForgePublisher;
export type ForgeConfigMaker = IForgeResolvableMaker | IForgeMaker;
export type ForgeConfigPlugin = IForgeResolvablePlugin | IForgePlugin;
export interface IForgePluginInterface {
triggerHook(hookName: string, hookArgs: any[]): Promise<void>;
triggerMutatingHook<T>(hookName: string, item: T): Promise<any>;
overrideStartLogic(opts: StartOptions): Promise<StartResult>;
}
/* eslint-enable @typescript-eslint/no-explicit-any */

export type ForgeRebuildOptions = Omit<RebuildOptions, 'buildPath' | 'electronVersion' | 'arch'>;
export type ForgePackagerOptions = Omit<ElectronPackagerOptions, 'dir' | 'arch' | 'platform' | 'out' | 'electronVersion'>;
export interface ForgeConfig {
/**
* A string to uniquely identify artifacts of this build, will be appended
Expand All @@ -34,10 +39,10 @@ export interface ForgeConfig {
/**
* An array of Forge plugins or a tuple consisting of [pluginName, pluginOptions]
*/
plugins: (IForgePlugin | [string, Record<string, unknown>])[];
electronRebuildConfig: Partial<RebuildOptions>;
packagerConfig: Partial<Options>;
makers: (IForgeResolvableMaker | IForgeMaker)[];
plugins: ForgeConfigPlugin[];
rebuildConfig: ForgeRebuildOptions;
packagerConfig: ForgePackagerOptions;
makers: ForgeConfigMaker[];
publishers: ForgeConfigPublisher[];
}
export interface ForgeMakeResult {
Expand All @@ -59,6 +64,11 @@ export interface ForgeMakeResult {
arch: ForgeArch;
}

export interface IForgeResolvablePlugin {
name: string;
config?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
}

export interface IForgePlugin {
/** @internal */
__isElectronForgePlugin: boolean;
Expand Down