Skip to content
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
35 changes: 35 additions & 0 deletions packages/api/cli/src/electron-forge-bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { initializeProxy } from '@electron/get';
import { api, BundleOptions } from '@electron-forge/core';
import { program } from 'commander';

import './util/terminate';
import packageJSON from '../package.json';

import { resolveWorkingDir } from './util/resolve-working-dir';

program
.version(packageJSON.version, '-V, --version', 'Output the current version')
.helpOption('-h, --help', 'Output usage information')
.argument(
'[dir]',
'Directory to run the command in. (default: current directory)',
)
.option('-a, --arch [arch]', 'Target build architecture')
.option('-p, --platform [platform]', 'Target build platform')
.action(async (dir) => {
const workingDir = resolveWorkingDir(dir);

const options = program.opts();

initializeProxy();

const bundleOpts: BundleOptions = {
dir: workingDir,
interactive: true,
};
if (options.arch) bundleOpts.arch = options.arch;
if (options.platform) bundleOpts.platform = options.platform;

await api.bundle(bundleOpts);
})
.parse(process.argv);
4 changes: 4 additions & 0 deletions packages/api/cli/src/electron-forge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ program
'Start the current Electron application in development mode.',
)
.command('package', 'Package the current Electron application.')
.command(
'bundle',
'Bundle the current Electron application source code for production.',
)
.command(
'make',
'Generate distributables for the current Electron application.',
Expand Down
170 changes: 170 additions & 0 deletions packages/api/core/src/api/bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import { getHostArch } from '@electron/get';
import {
ForgeArch,
ForgeListrTaskFn,
ForgePlatform,
ResolvedForgeConfig,
} from '@electron-forge/shared-types';
import { autoTrace, delayTraceTillSignal } from '@electron-forge/tracer';
import chalk from 'chalk';
import debug from 'debug';
import { Listr } from 'listr2';

import getForgeConfig from '../util/forge-config';
import { getHookListrTasks } from '../util/hook';
import { readMutatedPackageJson } from '../util/read-package-json';
import resolveDir from '../util/resolve-dir';

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

type BundleContext = {
dir: string;
forgeConfig: ResolvedForgeConfig;
packageJSON: any;

Check warning on line 23 in packages/api/core/src/api/bundle.ts

View workflow job for this annotation

GitHub Actions / lint-and-build

Unexpected any. Specify a different type
};

export interface BundleOptions {
/**
* The path to the app to bundle
*/
dir?: string;
/**
* Whether to use sensible defaults or prompt the user visually
*/
interactive?: boolean;
/**
* The target arch
*/
arch?: ForgeArch;
/**
* The target platform
*/
platform?: ForgePlatform;
}

export const listrBundle = (
childTrace: typeof autoTrace,
{
dir: providedDir = process.cwd(),
interactive = false,
arch = getHostArch() as ForgeArch,
platform = process.platform as ForgePlatform,
}: BundleOptions,
) => {
d('bundling with options', { providedDir, interactive, arch, platform });

const runner = new Listr<BundleContext>(
[
{
title: 'Preparing to bundle application',
task: childTrace<Parameters<ForgeListrTaskFn<BundleContext>>>(
{ name: 'bundle-prepare', category: '@electron-forge/core' },
async (_, ctx) => {
const resolvedDir = await resolveDir(providedDir);
if (!resolvedDir) {
throw new Error(
'Failed to locate compilable Electron application',
);
}
ctx.dir = resolvedDir;

ctx.forgeConfig = await getForgeConfig(resolvedDir);
ctx.packageJSON = await readMutatedPackageJson(
resolvedDir,
ctx.forgeConfig,
);

if (!ctx.packageJSON.main) {
throw new Error(
'packageJSON.main must be set to a valid entry point for your Electron app',
);
}
},
),
},
{
title: 'Running bundling hooks',
task: childTrace<Parameters<ForgeListrTaskFn<BundleContext>>>(
{ name: 'run-bundling-hooks', category: '@electron-forge/core' },
async (childTrace, { forgeConfig }, task) => {
return delayTraceTillSignal(
childTrace,
task.newListr([
{
title: `Running ${chalk.yellow('generateAssets')} hook`,
task: childTrace<Parameters<ForgeListrTaskFn>>(
{
name: 'run-generateAssets-hook',
category: '@electron-forge/core',
},
async (childTrace, _, task) => {
return delayTraceTillSignal(
childTrace,
task.newListr(
await getHookListrTasks(
childTrace,
forgeConfig,
'generateAssets',
platform,
arch,
),
),
'run',
);
},
),
},
{
title: `Running ${chalk.yellow('prePackage')} hook`,
task: childTrace<Parameters<ForgeListrTaskFn>>(
{
name: 'run-prePackage-hook',
category: '@electron-forge/core',
},
async (childTrace, _, task) => {
return delayTraceTillSignal(
childTrace,
task.newListr(
await getHookListrTasks(
childTrace,
forgeConfig,
'prePackage',
platform,
arch,
),
),
'run',
);
},
),
},
]),
'run',
);
},
),
},
],
{
concurrent: false,
silentRendererCondition: !interactive,
fallbackRendererCondition:
Boolean(process.env.DEBUG) || Boolean(process.env.CI),
rendererOptions: {
collapseSubtasks: false,
collapseErrors: false,
},
ctx: {} as BundleContext,
},
);

return runner;
};

export default autoTrace(
{ name: 'bundle()', category: '@electron-forge/core' },
async (childTrace, opts: BundleOptions): Promise<void> => {
const runner = listrBundle(childTrace, opts);
await runner.run();
},
);
11 changes: 11 additions & 0 deletions packages/api/core/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// eslint-disable-next-line n/no-missing-import
import ForgeUtils from '../util';

import bundle, { BundleOptions } from './bundle';
import _import, { ImportOptions } from './import';
import init, { InitOptions } from './init';
import make, { MakeOptions } from './make';
Expand All @@ -11,6 +12,15 @@
import start, { StartOptions } from './start';

export class ForgeAPI {
/**
* Bundle the current Electron application source code using the configured
* bundler plugin (e.g. webpack, vite). Runs generateAssets and prePackage
* hooks without running @electron/packager.

Check warning on line 18 in packages/api/core/src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint-and-build

tsdoc-characters-after-block-tag: The token "@electron" looks like a TSDoc tag but contains an invalid character "/"; if it is not a tag, use a backslash to escape the "@"
*/
bundle(opts: BundleOptions): Promise<void> {
return bundle(opts);
}

/**
* Attempt to import a given module directory to the Electron Forge standard.
*
Expand Down Expand Up @@ -63,6 +73,7 @@
const utils = new ForgeUtils();

export {
BundleOptions,
ForgeMakeResult,
ElectronProcess,
ForgeUtils,
Expand Down
Loading