diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 6c863978c7..4c962ac294 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -49,6 +49,7 @@ jobs: with: cname: js.electronforge.io defaultBranch: main + docsPath: api-docs noCommit: true showUnderscoreFiles: true env: diff --git a/.gitignore b/.gitignore index 4b8ac00ec4..ecbc6b8b58 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,8 @@ .nyc_output *.lcov /coverage +api-docs dist -docs doc node_modules lerna-debug.log diff --git a/.oxlintrc.json b/.oxlintrc.json index 6b38f2aa11..0071cfbcac 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -49,8 +49,8 @@ ], "ignorePatterns": [ "**/.claude/**", + "api-docs/", "dist", - "docs/", "node_modules", "*.d.ts", "packages/*/*/doc", diff --git a/docs/_partials/static-file-auto-updates.mdx b/docs/_partials/static-file-auto-updates.mdx new file mode 100644 index 0000000000..6ca7b37480 --- /dev/null +++ b/docs/_partials/static-file-auto-updates.mdx @@ -0,0 +1,7 @@ +:::tip +**Static file auto-updates with DMG distributions** + +The [Squirrel.Mac](https://github.com/Squirrel/Squirrel.mac) implementation behind Electron's `autoUpdater` module on macOS supports static file auto-updates from the ZIP artifacts uploaded to your cloud storage [Publishers](../config/publishers/index.md). + +If you want to distribute a DMG that supports static file auto-updates, make sure to also make a [ZIP](../config/makers/zip.md) target and follow the [Auto updating from S3](../config/publishers/s3.mdx#auto-updating-from-s3) instructions to configure updates. +::: diff --git a/docs/advanced/auto-update.md b/docs/advanced/auto-update.md new file mode 100644 index 0000000000..51c27f7bbd --- /dev/null +++ b/docs/advanced/auto-update.md @@ -0,0 +1,35 @@ +--- +description: Set up automatic updates for your Electron application +--- + +# Auto Update + +Setting up Auto Updates in your app with Electron Forge is mostly the same process [as described in the Electron docs](https://electronjs.org/docs/tutorial/updates). Forge enhances your workflow by publishing your app to the right place for you. There are three main ways you can do auto updates. + +:::warning +Note that having a [signed](../guides/code-signing/code-signing-macos.md) application is a pre-requisite for using auto updates on macOS. +::: + +## Open source apps: update.electronjs.org + +Open source apps hosted on GitHub can use a free auto update service from the Electron team, [update.electronjs.org](auto-update.md#open-source-apps-updateelectronjsorg). To use this module with Forge, set up the [GitHub Publisher](../config/publishers/github.md) and add the [`update-electron-app`](https://github.com/electron/update-electron-app) module to your app. + +This setup is going to be around 2 lines of code and a few lines of configuration. It is by far the easiest way to set up auto updates if you're an open source app. + +## Hosting updates on static storage providers + +If you are using any of Forge's built-in Publishers that upload your artifacts to static storage, they each have a documentation section on how to configure your app to auto update using those uploaded artifacts. Check out each of the options: + +* [Amazon S3](../config/publishers/s3.mdx#auto-updating-from-s3) +* Google Cloud Storage _(Coming Soon)_ + +## Hosting your own update server + +If you're not open source or you want slightly more control over your update service (like percentage based rollouts, or more release channels) you can host your own update server such as [`nucleus`](https://github.com/atlassian/nucleus) or [`nuts`](https://github.com/GitbookIO/nuts). See the full list of known Electron update servers in the [Electron's Updating Applications docs](https://electronjs.org/docs/tutorial/updates#deploying-an-update-server). + +Each update server will have their own configuration for your actual app, but publishing should be done from Forge for most of them: + +* `nucleus` - Use the [Nucleus](../config/publishers/nucleus.md) publish target +* `nuts` - Use the [GitHub](../config/publishers/github.md) publish target +* `electron-release-server` - Use the [Electron Release Server](../config/publishers/electron-release-server.md) publish target +* `hazel` - Use the [GitHub](../config/publishers/github.md) publish target diff --git a/docs/advanced/debugging.md b/docs/advanced/debugging.md new file mode 100644 index 0000000000..b6353022e7 --- /dev/null +++ b/docs/advanced/debugging.md @@ -0,0 +1,64 @@ +# Debugging + +In Electron apps, the main and renderer processes have different debugging mechanisms: + +* Renderer processes can be debugged using Chromium DevTools. +* The main process can be debugged via the `--inspect` and `--inspect-brk` command line flags. + +This guide goes over Forge-specific ways of debugging the main process through the command line or with a code editor. + +:::info +Each section in this guide assumes your `package.json` has a `"start": "electron-forge start"` script. +::: + +For more general information on debugging Electron apps, see the [main Electron docs on Application Debugging](https://www.electronjs.org/docs/latest/tutorial/application-debugging#renderer-process). + +## Debugging on the command line + +You can specify the `--inspect-electron` flag when running `electron-forge start`. Internally, this will activate the [Electron `--inspect`flag](http://electronjs.org/docs/tutorial/debugging-main-process#--inspectport), and the main process will listen for a debugging client on port 5858. + +```bash +npm run start -- --inspect-electron +``` + +Once your app is active, open [`chrome://inspect`](chrome://inspect) in any Chromium-based browser to attach a debugger to the main process of your app. + +:::info +To add a breakpoint at the first line of execution when debugging, you can use Forge's `--inspect-brk-electron` flag instead. +::: + +## Debugging with VS Code + +To debug the main process through VS Code, add the following [Node.js launch configuration](https://code.visualstudio.com/docs/nodejs/nodejs-debugging): + +```json5 title=".vscode/launch.json" +{ + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Electron Main", + "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.sh", + "windows": { + "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.cmd" + }, + // runtimeArgs will be passed directly to your Electron application + "runtimeArgs": [ + "foo", + "bar" + ], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal" + } + ] +} +``` + +Once this configuration is added, launch the app via VS Code's Run and Debug view to start debugging. + +## Debugging with WebStorm or Other Jetbrains IDEs + +1. Access the `Run > Debug...` menu and select the `Edit Configurations...` option to open the `Run/Debug Configurations` window. +2. Click on the `Add new configuration` button (the `+` icon) in the upper-left corner and select the `npm` template. +3. In the `Scripts` dropdown menu, select `start`. +4. Click on `Debug` to start debugging your app. diff --git a/docs/advanced/extending-electron-forge/index.md b/docs/advanced/extending-electron-forge/index.md new file mode 100644 index 0000000000..a0196671c5 --- /dev/null +++ b/docs/advanced/extending-electron-forge/index.md @@ -0,0 +1,9 @@ +# Extending Electron Forge + +Electron Forge is designed to be easily extendable by third parties with whatever build logic you need. The build flow for Electron Forge is split into two main sections, `make` and `publish`, and you can define custom targets for each of those commands. For everything else we have a Plugin API which allows you to hook into pretty much any part of Forge's standard build process and do whatever you want. + +To briefly explain some terms: + +* `maker`: A tool that takes a packaged Electron application and outputs a certain kind of distributable +* `publisher`: A tool that takes distributables and "publishes" \(normally just uploads\) them somewhere \(for example, GitHub releases\) +* `plugin`: A tool that hooks into Forge's internals and can inject logic into your build process diff --git a/docs/advanced/extending-electron-forge/writing-makers.md b/docs/advanced/extending-electron-forge/writing-makers.md new file mode 100644 index 0000000000..877bec06c5 --- /dev/null +++ b/docs/advanced/extending-electron-forge/writing-makers.md @@ -0,0 +1,46 @@ +# Writing Makers + +An Electron Forge Maker has to export a single class that extends our base maker. The base maker can be depended on by installing`@electron-forge/maker-base`. + +The `MakerBase` class has some helper methods for your convenience. Check out the interface of [`MakerBase`](https://js.electronforge.io/classes/_electron_forge_maker_base.MakerBase.html) for more advanced API details. + +| Method | Description | +| :--- | :--- | +| `ensureDirectory(path)` | Ensures the directory exists and is forced to be empty. This is a destructive operation. | +| `ensureFile(path)` | Ensures the path to the file exists and the file does not exist, if the file exists it is deleted and the path created. | +| `isInstalled(moduleName)` | Checks if the given module is installed, used for testing if optional dependencies are installed or not. | + +Your maker **must** implement two methods: + +### `isSupportedOnCurrentPlatform(): boolean` + +This method must synchronously return a boolean indicating whether or not this maker can run on the current platform. Normally this is just a `process.platform` check but it can be a deeper check for dependencies like `fake-root` or other required external build tools. + +If the issue is a missing dependency you should log out a **helpful** error message telling the developer exactly what is missing and if possible how to get it. + +```javascript +export default class MyMaker extends MakerBase { + isSupportedOnCurrentPlatform () { + return process.platform === 'linux' && this.isFakeRootInstalled(); + } + + isFakeRootInstalled () { /* ... */ } +} +``` + +### `make(options: MakerOptions): Promise` + +Makers must implement this method and return an array of **absolute** paths to the artifacts this maker generated. If an error occurs, reject the promise and Electron Forge will stop the `make` process. + +The `config` for the maker will be available on `this.config`. + +The options object is documented in [`MakerOptions`](https://js.electronforge.io/interfaces/_electron_forge_maker_base.MakerOptions.html). + +```javascript +export default class MyMaker extends MakerBase { + async make (opts) { + const pathToMagicInstaller = await makeMagicInstaller(opts.dir); + return [pathToMagicInstaller]; + } +} +``` diff --git a/docs/advanced/extending-electron-forge/writing-plugins.md b/docs/advanced/extending-electron-forge/writing-plugins.md new file mode 100644 index 0000000000..e77148da0f --- /dev/null +++ b/docs/advanced/extending-electron-forge/writing-plugins.md @@ -0,0 +1,44 @@ +# Writing Plugins + +An Electron Forge Plugin has to export a single class that extends our base plugin. The base plugin can be depended on by installing`@electron-forge/plugin-base`. It can implement two methods, neither are required. + +### `getHooks(): ForgeMultiHookMap` + +If implemented this method will be once during plugin initialization inside Forge, this method is called only once and shouldn't result in any side effects being executed. You must return an object in a similar format to `forgeConfig.hooks`. i.e. an object map between hook names and an array of hook functions. + +The possible hook names and the parameters passed to the hook function you return are documented over in the [Configuration](../../config/configuration.mdx) section of the docs. + +```javascript +export default class MyPlugin extends PluginBase { + getHooks () { + return { + prePackage: [this.prePackage] + }; + } + + prePackage () { + console.log('running prePackage hook'); + } +} +``` + +### `startLogic(startOpts: StartOptions): Promise` + +If implemented, this method will be called every time the user runs `electron-forge start`, if you return a `ChildProcess` you can override the built in start logic and Electron Forge will not spawn it's own process, rather it will watch the one you returned. If you return `false` forge will spawn Electron itself but you could still run custom logic such as started compilation for code or downloading certain binaries before the app starts. + +Please note that overriding the start logic here only works in **development** if you want to change how an app runs once packaged you will need to use a build hook to inject code into the packaged app. + +:::info +`StartOptions`is explained further [in the API docs](https://js.electronforge.io/interfaces/\_electron\_forge\_shared\_types.StartOptions.html). +::: + +```javascript +export default class MyPlugin extends Pluginbase { + async startLogic (opts) { + await this.compileMainProcess(); + return null; + } + + compileMainProcess () { /* ... */ } +} +``` diff --git a/docs/advanced/extending-electron-forge/writing-publishers.md b/docs/advanced/extending-electron-forge/writing-publishers.md new file mode 100644 index 0000000000..283765f59c --- /dev/null +++ b/docs/advanced/extending-electron-forge/writing-publishers.md @@ -0,0 +1,28 @@ +# Writing Publishers + +An Electron Forge Publisher has to export a single class that extends the base publisher. The base plugin can be depended on by installing`@electron-forge/publisher-base`. + +Check out the interface of [`PublisherBase`](https://js.electronforge.io/modules/_electron_forge_publisher_base.html) for more advanced API details. + +The publisher **must** implement one method: + +### `publish(options: PublisherOptions): Promise` + +Publishers must implement this method to publish the artifacts returned from make calls. If any errors occur you must throw them, failing silently or simply logging will not propagate issues up to Forge. + +Please note for a given version, publish will be called multiple times, once for each set of "platform" and "arch". This means if you are publishing `darwin` and `win32` artifacts to somewhere like GitHub on the first publish call, you will have to create the version on GitHub and the second call will just be appending files to the existing version. Your `publish` implementation will not be aware that another call is coming, however it must just be able to handle this case. + +The `config` for the publisher will be available on `this.config`. + +The options object is documented in [`PublisherOptions`](https://js.electronforge.io/interfaces/_electron_forge_publisher_base.PublisherOptions.html). + +```javascript +export default class MyPublisher extends PublisherBase { + async publish (opts) { + for (const result of opts.makeResults) { + await createVersionIfNotExists(); + await uploadDistributable(result); + } + } +} +``` diff --git a/docs/advanced/extending-electron-forge/writing-templates.md b/docs/advanced/extending-electron-forge/writing-templates.md new file mode 100644 index 0000000000..999226d896 --- /dev/null +++ b/docs/advanced/extending-electron-forge/writing-templates.md @@ -0,0 +1,14 @@ +--- +description: How to write custom templates for Electron Forge. +--- + +# Writing Templates + +Templates in Electron Forge implement the `ForgeTemplate` interface, namely: + +* `requiredForgeVersion` _(required)_ - the semantic version range of Electron Forge versions that this template supports. For example, `^6.0.0-beta.1` +* `dependencies` _(optional)_ - a list of package identifiers that you pass to a package manager (which may include a version range) to add to the `dependencies` field in `package.json`. For example, `jquery` or `jquery@^3.0.0` +* `devDependencies` _(optional)_ - a list of package identifiers that you pass to a package manager (which may include a version range) to add to the `devDependencies` field in `package.json`. For example, `eslint` or `eslint@^7.0.0` +* `initializeTemplate` _(optional)_ - an `async` function that allows the template to perform custom actions, for example copying files from a `tmpl` folder into the new app. The exact function signature is defined in the shared types package. + +To use the custom template, run the [init](../../cli.md#init) command and point the template at the file that contains the `ForgeTemplate` implementation. diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 0000000000..e22e168a36 --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,226 @@ +--- +description: How to use the command line interface (CLI) commands for Electron Forge +--- + +# CLI + +## Overview + +Forge's CLI is the main way to run Electron Forge commands. It consists of a thin wrapper for its core API. Configuration for these commands is done through your [Forge configuration](config/configuration.mdx) object. + +If you want to use the core API programmatically, see the [Programmatic usage](cli.md#programmatic-usage) section below. + +:::info +Forge's CLI uses comma-separated value strings to pass multiple arguments into a single flag. Depending on your terminal, these comma-separated values may need to be enclosed in quotation marks. +::: + +## Installation + +To use the Forge CLI, install the `@electron-forge/cli` module into your project as a devDependency. If you're using the `create-electron-app` script, this module will already be installed for you. + +```bash +npm install --save-dev @electron-forge/cli +``` + +## Bootstrap commands + +These commands help you get started with Forge. If you're just getting started with Electron Forge, we recommend you follow the [Getting Started](index.md) or [Importing an Existing Project](import-existing-project.md) guides. + +:::info +By default, Electron Forge will use `yarn` if it's available on your system when bootstrapping your application.\ +\ +To run Forge commands with a specific package manager, use the `NODE_INSTALLER` environment variable. + +```sh {1} +NODE_INSTALLER=npm npx create-electron-app my-app-dir +``` + +::: + +### Init + +:::info +We recommend using the `create-electron-app` script (which uses this command) to get started rather than running Init directly. +::: + +This command will initialize a new Forge-powered application in the given directory (defaults to `.`, the current directory). + +Please note if you want to use a non-builtin template, it must be installed globally before running the `init` command. + +#### Options + +All flags are optional. + +| Flag | Value | Description | +| ----------------- | ------------- | ---------------------------------------------------------- | +| `--template` | Template Name | Name of the template to use to make this new app | +| `--copy-ci-files` | N/A | Set if you want to copy templated CI files _(coming soon)_ | + +#### Usage + +```bash +npx electron-forge init --template=webpack +``` + +### Import + +This command will attempt to take an existing Electron app and make it compatible with Forge. Normally, this just creates a base Electron Forge configuration and adds the required dependencies. + +#### Options + +There are no options for the Import command. + +#### Usage + +```bash +npx electron-forge import +``` + +## Build commands + +The Package, Make, and Publish commands are the three main steps of the Electron Forge build pipeline. Each step relies on the output of the previous one, so they are cascading by default (e.g. running `publish` will first run `package` then `make`. + +:::info +For more conceptual details, see the [Build Lifecycle](core-concepts/build-lifecycle.md) guide. +::: + +### Package + +This command will package your application into a platform-specific executable bundle and put the result in a folder. Please note that this does not make a distributable format. To make proper distributables, please use the Make command. + +#### Options + +All flags are optional. + +| Flag | Value | Description | +| ------------ | ------------------------ | -------------------------------------------------------------- | +| `--arch` | Architecture, e.g. `x64` | Target architecture to package for. Defaults to the host arch. | +| `--platform` | Platform, e.g. `mas` | Target platform to package for. Defaults to the host platform. | + +#### Usage + +```bash +# By default, the package command corresponds to a package npm script: +npm run package -- --arch="ia32" +# If there is no package script: +npx electron-forge package --arch="ia32" +``` + +:::warning + +#### **Packaging requires `node_modules` to be on disk** + +When packaging your Electron app, Forge crawls your project's `node_modules` folder to collect dependencies to bundle. Its module resolution algorithm is naive and doesn't take into account symlinked dependencies nor Yarn's Plug'n'Play (PnP) format. + +* If you are using Yarn >=2, please use the `nodeLinker: node-modules` install mode. +* If you are using pnpm, please set `node-linker=hoisted` in your project's `.npmrc` configuration. + +::: + +### Make + +This command will make distributables for your application based on your Forge config and the parameters you pass in. + +If you do not need to repackage your application between Make runs, use the `--skip-package` flag. + +#### Options + +All flags are optional. + +| Flag | Value | Description | +| ---------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--arch` | Architecture, e.g. `x64` | Target architecture to make for. Defaults to the arch that you're running on (the "host" arch). Allowed values are: "ia32", "x64", "armv7l", "arm64", "universal", or "mips64el". Multiple values should be comma-separated. | +| `--platform` | Platform, e.g. `mas` | Target platform to make for, please note you normally can only target platform X from platform X. This defaults to the platform you're running on (the "host" platform). | +| `--targets` | Comma separated list of maker names | Override your make targets for this run. The maker name is the full node module name, e.g. `@electron-forge/maker-deb`. By default, the make targets used are the ones available and configured for the given platform. | +| `--skip-package` | N/A | Set if you want to skip the packaging step, useful if you are running sequential makes and want to save time. By default, packaging is **not** skipped. | + +#### Usage + +Basic usage: + +```bash +# By default, the make command corresponds to a make npm script: +npm run make -- --arch="ia32" +# If there is no make script: +npx electron-forge make --arch="ia32" +``` + +Building for ia32 and x64 architectures: + +```bash +npm run make -- --arch="ia32,x64" +``` + +### Publish + +This command will attempt to package, make, and publish the Forge application to the publish targets defined in your Forge config. + +If you want to verify artifacts from the Make step before publishing, you can use the Dry Run options explained below. + +#### Options + +All flags are optional. + +| Flag | Value | Description | +| ---------------- | --------------------------------------- | ------------------------------------------------------------------------ | +| `--target` | Comma separated list of publisher names | Override your publish targets for this run | +| `--dry-run` | N/A | Triggers a publish dry run which saves state and doesn't upload anything | +| `--from-dry-run` | N/A | Attempts to publish artifacts from any dry runs saved on disk | + +#### Usage + +```bash {1} +# By default, the publish command corresponds to a publish npm script: +npm run publish -- --from-dry-run +# If there is no publish script: +npx electron-forge publish -- --from-dry-run +``` + +## Dev commands + +### Start + +This command will launch your app in dev mode with the `electron` binary in the given directory (defaults to `.`). + +If you type `rs` (and hit enter) in the same terminal where you ran the start command, the running app will be terminated and restarted. + +Forge plugins can override this command to run custom development logic. For example, the [Webpack Plugin](config/plugins/webpack.mdx) runs a webpack-dev-server instance to provide live reloading and HMR. + +#### Options + +All flags are optional. + +| Flag | Value | Description | +| -------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| `--app-path` | Path to your app from the working directory | Override the path to the Electron app to launch (defaults to `.`) | +| `--enable-logging` | N/A | Enable advanced logging. This will log internal Electron things | +| `--run-as-node` | N/A | Run the Electron app as a Node.JS script | +| `--inspect-electron` | N/A | Triggers inspect mode on Electron to allow debugging the main process | +| `--` | extra arguments | Any additional arguments to pass to Electron or the app itself. For example: `-- --my-app-argument` | + +#### Usage + +```bash +# By default, the start command corresponds to a start npm script: +npm start --enable-logging +# if there is no start script +npx electron-forge start --enable-logging +``` + +## Programmatic usage + +The Forge CLI should suit most use cases, but we do expose the `@electron-forge/core` package for programmatic command usage. + +```javascript +const { api } = require('@electron-forge/core'); + +const main = async () => { + await api.package({ + // add package command options here + }); +}; + +main(); +``` + +For more information, see the [API documentation](https://js.electronforge.io/classes/_electron_forge_core.ForgeAPI.html). diff --git a/docs/config/configuration.mdx b/docs/config/configuration.mdx new file mode 100644 index 0000000000..9f9e404b00 --- /dev/null +++ b/docs/config/configuration.mdx @@ -0,0 +1,222 @@ +--- +description: How to configure Electron Forge +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +Electron Forge configuration is centralized in a single configuration object. You can specify this config in your package.json on the `config.forge` property. This property can be in one of two forms: + +* An object containing your entire Forge configuration. +* A relative path pointing at a JavaScript file that exports your config. + +If you do not have `config.forge` set in your package.json file, Forge will attempt to find a `forge.config.js` file in your project root. + + + + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: {}, + makers: [ + { + name: '@electron-forge/maker-zip' + } + ] +}; +``` + + + + + +```json +{ + "name": "my-app", + "version": "0.0.1", + "config": { + "forge": { + "packagerConfig": {}, + "makers": [ + { + "name": "@electron-forge/maker-zip" + } + ] + } + } +} +``` + + + + +:::info +We recommend using JavaScript for your config file since it enables conditional logic within your configuration. +::: + +## Configuration options + + + + +```javascript +module.exports = { + packagerConfig: { /* ... */ }, + rebuildConfig: { /* ... */ }, + makers: [], + publishers: [], + plugins: [], + hooks: { /* ... */ }, + buildIdentifier: 'my-build', + outDir: 'desired/outpath' +}; +``` + + + + + +```json +// Only the relevant section of package.json is shown, for brevity. +{ + "config": { + "forge": { + "packagerConfig": { ... }, + "rebuildConfig": { ... }, + "makers": [ ... ], + "publishers": [ ... ], + "plugins": [ ... ], + "hooks": { ... }, + "buildIdentifier": "my-build", + "outDir": "desired/outpath" + } + } +} +``` + + + + +:::tip +All properties in your Forge configuration are optional. Initializing your project with one of the built-in templates will include some default recommended config options. +::: + +### Electron Packager config + +The top level property `packagerConfig` on the configuration object maps directly to the options sent to [`@electron/packager`](https://github.com/electron/packager) during the [Package](../cli.md#package) step of Electron Forge's build process + +This configuration allows you customize how `@electron/packager` bundles your Electron-based application source code into a packaged application ready for distribution. + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: { + name: 'My Electron App', + asar: true, + osxSign: {}, + appCategoryType: 'public.app-category.developer-tools' + } +}; +``` + +The options you can put in this object are documented in the [Electron Packager API docs](https://electron.github.io/packager/main/interfaces/Options.html). + +:::info +You can not override the `dir`, `arch`, `platform`, `out` or `electronVersion` options as they are set by Electron Forge internally. + +If you want to specify a platform/architecture combination for any build command (Package, Make, or Publish), you can specify `--arch` and `--platform` flags using the Forge CLI (e.g. `npm run make --arch=arm64`). + +See the [Build commands](../cli.md#build-commands) documentation for more details. +::: + +### Electron Rebuild config + +The top level property `rebuildConfig` on the configuration object maps directly to the options sent to [`@electron/rebuild`](https://github.com/electron/rebuild) during both the [Package](../cli.md#package) and [Start](../cli.md#start) commands in Electron Forge. + +This configuration allows you to customize how Electron Forge rebuilds your project's [native Node.js modules](https://www.electronjs.org/docs/latest/tutorial/using-native-node-modules) against the Node.js version bundled in your app's Electron version. + +```javascript title="forge.config.js" +module.exports = { + rebuildConfig: { + force: true + } +}; +``` + +The options you can put in this object are documented in the [Electron Rebuild API docs](https://github.com/electron/electron-rebuild#how-can-i-integrate-this-into-grunt--gulp--whatever). + +:::info +The required `buildPath` and `electronVersion` options for `@electron/rebuild` are preconfigured by Forge. The optional `arch` option will also be overridden by Forge internally. +::: + +### Makers + +The top-level `makers` property on the configuration object is an array of maker configurations. Each maker will generate a distributable artifact for your packaged application in the [Make](../cli.md#make) step (e.g. [Squirrel.Windows](makers/squirrel.windows.md) on Windows or [DMG](makers/dmg.mdx) on macOS). + +Check out the [Makers](makers/index.mdx) documentation for all official makers and their config options, and the[Writing Makers](../advanced/extending-electron-forge/writing-makers.md) guide for implementing your own Make step build targets. + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'] + } + ] +}; +``` + +### Publishers + +The top level property `publishers` on the configuration object is an array of publisher configurations. Each publisher provides a publish target for your distributable (e.g. [GitHub](publishers/github.md) or [S3](publishers/s3.mdx)). + +Check out the [Publishers](publishers/index.md) documentation for all official publishers and their config options, and the [Writing Publishers](../advanced/extending-electron-forge/writing-publishers.md) guide for implementing your own custom Publish targets. + +```javascript title="forge.config.js" +module.exports = { + publishers: [ + { + name: '@electron-forge/publisher-github', + config: { + repository: { + owner: 'electron', + name: 'fiddle' + }, + draft: true, + prerelease: false, + generateReleaseNotes: true + } + } + ] +}; +``` + +### Plugins + +The top level property `plugins` on the configuration object is an array of plugin configurations. Electron Forge plugins can hook into any point in its lifecycle and provide additional functionality (e.g. the [Webpack Plugin](plugins/webpack.mdx) will integrate webpack bundling into the build lifecycle, and the [Electronegativity Plugin](plugins/electronegativity.md) will identify security anti-patterns in your app). + +Check out the [Plugins](plugins/index.md) documentation for all possible plugins and their config options, and the [Writing Plugins](../advanced/extending-electron-forge/writing-plugins.md) guide for implementing your own custom Forge plugins. + +### Hooks + +The top level property `hooks` on the configuration object is an object containing hooks that can be used to insert custom logic during the [Build Lifecycle](../core-concepts/build-lifecycle.md). + +Check out the [Hooks](hooks.md) documentation for all possible hooks and their config options. + +### Build identifiers + +This property can be used to identify different build configurations. Normally, this property is set to the channel the build will release to, or some other unique identifier. For example, common values are `prod` and `beta`. This identifier can be used in conjunction with the `fromBuildIdentifier` function to generate release channel or environment specific configuration. For example: + +```javascript title="forge.config.js" +const { utils: { fromBuildIdentifier } } = require('@electron-forge/core'); + +module.exports = { + buildIdentifier: process.env.IS_BETA ? 'beta' : 'prod', + packagerConfig: { + appBundleId: fromBuildIdentifier({ beta: 'com.beta.app', prod: 'com.app' }) + } +}; +``` + +In this example the `appBundleId` option passed to Electron Packager will be selected based on the `buildIdentifier` based on whether you are building for `prod` or `beta`. This allows you to make shared configs incredibly easily as only the values that change need to be wrapped with this function. diff --git a/docs/config/hooks.md b/docs/config/hooks.md new file mode 100644 index 0000000000..a323cf105f --- /dev/null +++ b/docs/config/hooks.md @@ -0,0 +1,216 @@ +--- +description: Specify custom build logic with asynchronous callback functions +--- + +# Hooks + +In Electron Forge, hooks are asynchronous callback functions that allow you to insert your own logic at different points in the development or build process. + +Each hook function comes with the Forge configuration object as a first parameter. + +:::warning +Any writes to `stdout` and `stderr` from within a hook function will be printed in the console after the Forge build completes, and will only be visible with the `DEBUG` or `CI` environment variables set to some truthy value. +::: + +:::info +To read more about the different stages in Forge's build process, please refer to the [Build Lifecycle](../core-concepts/build-lifecycle.md) documentation. +::: + +## Simple hooks + +In Electron Forge, most hooks are **simple hooks**, which perform side effects during the build lifecycle without directly affecting subsequent steps in the build. + +### **`generateAssets`** + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html) - Forge configuration object + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture +* **Returns: `Promise`** + +`generateAssets()` is invoked before Forge's **`start`** or **`package`** commands. + +You can use this hook to generate any static files or resources your app requires on runtime but aren't in the source code. + +For instance, you could use this hook to generate a license file containing the license of all your dependencies. + +### `preStart` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html) - Forge configuration object +* **Returns: `Promise`** + +`preStart()` is invoked before Forge's **`start`** command launches the app in dev mode. + +You can use this hook to run prepatory logic before your app launches. + +```javascript title="forge.config.js" +module.exports = { + hooks: { + preStart: async (forgeConfig) => { + console.log(`Starting up app on platform: ${process.platform}`); + } + } +}; +``` + +### `postStart` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html) - Forge configuration object + * **`appProcess:`**[**`ChildProcess`**](https://nodejs.org/api/child_process.html#class-childprocess) **-** Node.js child process instance +* **Returns: `Promise`** + +`postStart()` is called after Forge's **`start`** command launches the app in dev mode. + +You can use this hook to attach listeners to the spawned child process. + +```javascript title="forge.config.js" +module.exports = { + hooks: { + postStart: async (forgeConfig, appProcess) => { + console.log(`Spawned child pid: ${appProcess.pid}`); + } + } +}; +``` + +### `prePackage` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html) - Forge configuration object + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture +* **Returns: `Promise`** + +`prePackage()` is called before Forge runs Electron Packager in the **`package`** step . + +### `packageAfterCopy` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html) - Forge configuration object + * **`buildPath: string`**- the app's temporary folder path + * **`electronVersion: string`**- the app's Electron version + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture +* **Returns: `Promise`** + +`packageAfterCopy()` is called inside the [`afterCopy`](https://electron.github.io/packager/main/interfaces/Options.html#afterCopy) hook of Electron Packager. + +During Forge's **`package`** step, Electron Packager copies your app's build directory to a temporary folder. + +The `afterCopy` hook runs after this copy step. + +### `packageAfterPrune` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object + * **`buildPath: string`**- the app's temporary folder path + * **`electronVersion: string`**- the app's Electron version + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture +* **Returns: `Promise`** + +`packageAfterPrune()` is called inside the [`afterPrune`](https://electron.github.io/packager/main/interfaces/Options.html#afterPrune) hook of Electron Packager. + +During Forge's **`package`** step, Electron Packager prunes non-production `node_modules` dependencies from the temporary folder your app is copied to. This step minimizes the size of your app's production bundle. + +The `afterPrune` hook runs after this prune step. + +:::info +`packageAfterPrune()` will have no effect if your `packagerOptions.prune` option is set to `false`. +::: + +### `packageAfterExtract` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object + * **`buildPath: string`**- the Electron binary's temporary folder path + * **`electronVersion: string`**- the app's Electron version + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture +* **Returns: `Promise`** + +`packageAfterExtract()` is called inside the [`afterExtract`](https://electron.github.io/packager/main/interfaces/Options.html#afterExtract) hook of Electron Packager. + +During Forge's **`package`** step, Electron Packager extracts your Electron binary into a temporary folder. + +The `afterExtract` hook runs after this extract step. + +### `postPackage` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object + * **`packageResult: Object`** + * **`platform: string`** - Operating system platform + * **`arch: string`** - CPU architecture + * **`outputPaths: string[]`** - filesystem paths for package output +* **Returns: `Promise`** + +\ +`postPackage()` is called after Forge's **`package`** step has successfully completed. + +For example: + +```javascript title="forge.config.js" +module.exports = { + hooks: { + postPackage: async (forgeConfig, options) => { + console.info('Packages built at:', options.outputPaths); + } + } +}; +``` + +### `preMake` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object +* **Returns: `Promise`** + +`preMake()` is called before the **`make`** step runs. + +## Mutating hooks + +In Electron Forge, **mutating hooks** are a special kind of hook that return the same type of value as their second parameter. + +The returned value will replace the original parameter's value for subsequent steps in the Forge lifecycle. + +### `postMake` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object + * **`makeResults:`**[**`MakeResult`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ForgeMakeResult.html)**`[]`** +* **Returns: `Promise<`**[**`MakeResult`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ForgeMakeResult.html)**`[] | void>`** + +`postMake()`is called after Forge's **`make`** step has successfully completed. + +It is passed an array of [`MakeResult`](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ForgeMakeResult.html) objects that are output from the `make` step. If you wish to mutate the array of Make results, you can return a new array of [`MakeResult`](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ForgeMakeResult.html) objects that Electron Forge can use for future steps. + +### `readPackageJson` + +* **Arguments:** + * **`config:`**[**`ResolvedForgeConfig`**](https://js.electronforge.io/interfaces/_electron_forge_shared_types.ResolvedForgeConfig.html)- Forge configuration object + * **`packageJson: Record`** - Full package.json object +* **Returns: `Promise | void>`** + +`readPackageJson()` is called every time Forge attempts to read your `package.json` file. + +The full package.json object is passed in as a parameter. If you want to modify that object in any way, you must do so and return the new value for Forge to use. + +This is useful to set things like the package.json `version` field at runtime. + +```javascript title="forge.config.js" +module.exports = { + hooks: { + readPackageJson: async (forgeConfig, packageJson) => { + packageJson.version = '4.0.0'; + return packageJson; + } + } +}; +``` + +:::warning +**Note:** this hook will not change the name or version used by Electron Packager to customize your app metadata, as that is read prior to this hook being called (during Electron Packager's `afterCopy` hooks). +::: diff --git a/docs/config/makers/appx.md b/docs/config/makers/appx.md new file mode 100644 index 0000000000..0684c1b36e --- /dev/null +++ b/docs/config/makers/appx.md @@ -0,0 +1,44 @@ +--- +description: >- + Create a package for the Microsoft Store for your Electron app, using Electron + Forge. +--- + +# AppX + +The AppX target builds `.appx` packages which are designed to target the [Microsoft Store](https://apps.microsoft.com/home). + +## Requirements + +You can only build the AppX target on Windows 10 or 11 machines with the [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) installed. Check the [`electron-windows-store` docs](https://github.com/electron-userland/electron-windows-store) for more information on platform requirements. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-appx +``` + +## Usage + +To use `@electron-forge/maker-appx`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-appx', + config: { + publisher: 'CN=developmentca', + devCert: 'C:\\devcert.pfx', + certPass: 'abcd' + } + } + ] +}; +``` + +Configuration options are documented in [`MakerAppXConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_appx.MakerAppXConfig.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-windows-store*` environment variable. diff --git a/docs/config/makers/deb.md b/docs/config/makers/deb.md new file mode 100644 index 0000000000..6f1bb220f4 --- /dev/null +++ b/docs/config/makers/deb.md @@ -0,0 +1,45 @@ +--- +description: >- + Create a package for Debian-based Linux distributions for your Electron app, + using Electron Forge. +--- + +# deb + +The deb target builds [`.deb` packages](https://www.debian.org/doc/manuals/debian-faq/pkg-basics.en.html), which are the standard package format for Debian-based Linux distributions such as [Ubuntu](https://ubuntu.com/). + +## Requirements + +You can only build the deb target on Linux or macOS machines with the [`fakeroot`](https://wiki.debian.org/FakeRoot) and [`dpkg`](https://wiki.debian.org/dpkg) packages installed. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-deb +``` + +## Usage + +To use `@electron-forge/maker-deb`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-deb', + config: { + options: { + maintainer: 'Joe Bloggs', + homepage: 'https://example.com' + } + } + } + ] +}; +``` + +Configuration options are documented in [`MakerDebConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_deb.MakerDebConfig.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-installer-deb*` environment variable. diff --git a/docs/config/makers/dmg.mdx b/docs/config/makers/dmg.mdx new file mode 100644 index 0000000000..9b6bb90c17 --- /dev/null +++ b/docs/config/makers/dmg.mdx @@ -0,0 +1,45 @@ +--- +description: Generate a DMG with Electron Forge to distribute your Electron app on macOS. +--- + +import StaticFileAutoUpdates from '../../_partials/static-file-auto-updates.mdx'; + +# DMG + +The DMG target builds Apple Disk Image (`.dmg`) files, which are the standard format for sharing macOS apps. The DMG acts like a ZIP file, but provides an easy way for users to take the app and put it in the `/Applications` directory. + + + +## Requirements + +You can only build the DMG target on macOS machines. + +## Installation + +```sh +npm install --save-dev @electron-forge/maker-dmg +``` + +## Usage + +To use `@electron-forge/maker-dmg`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-dmg', + config: { + background: './assets/dmg-background.png', + format: 'ULFO' + } + } + ] +}; +``` + +Configuration options are documented in [`MakerDMGConfig`](https://js.electronforge.io/classes/_electron_forge_maker_dmg.MakerDMG.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-installer-dmg*` environment variable. diff --git a/docs/config/makers/flatpak.md b/docs/config/makers/flatpak.md new file mode 100644 index 0000000000..d3aba655c6 --- /dev/null +++ b/docs/config/makers/flatpak.md @@ -0,0 +1,57 @@ +--- +description: Create a Flatpak app for your Electron app using Electron Forge. +--- + +# Flatpak + +[Flatpak](https://flatpak.org/) is a packaging format for Linux distributions that allows for sandboxed installation of applications in isolation from the rest of their system. In contrast, typical [deb](deb.md) or [RPM](rpm.md) installation methods are not sandboxed. + +## Requirements + +You can only build the Flatpak target if you have the following installed on your system: + +* [`flatpak`](https://docs.flatpak.org/en/latest/flatpak-command-reference.html#flatpak) +* [`flatpak-builder`](https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html#flatpak-builder) +* `eu-strip` _(usually part of the_ [_`elfutils`_](https://sourceware.org/elfutils/) _package)_ + +You will also need to add the Flathub remote repository to `flatpak` to access runtimes necessary to build your application: + +```sh +flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo +``` + +:::info +Flathub provides separate [installation instructions](https://flathub.org/setup) for each supported Linux distribution. Please refer to their documentation for additional information. +::: + +## Installation + +```sh +npm install --save-dev @electron-forge/maker-flatpak +``` + +## Usage + +To use `@electron-forge/maker-flatpak`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript +module.exports = { + makers: [ + { + name: '@electron-forge/maker-flatpak', + config: { + options: { + categories: ['Video'], + mimeType: ['video/h264'] + } + } + } + ] +}; +``` + +Configuration options are documented in [`MakerFlatpakConfig`](https://js.electronforge.io/interfaces/_electron_forge_maker_flatpak.MakerFlatpakConfig.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-installer-flatpak*` environment variable. diff --git a/docs/config/makers/index.mdx b/docs/config/makers/index.mdx new file mode 100644 index 0000000000..197f93922c --- /dev/null +++ b/docs/config/makers/index.mdx @@ -0,0 +1,68 @@ +--- +description: >- + Generate platform specific distributables for Electron apps using Electron + Forge. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Makers + +Makers are Electron Forge's way of taking your packaged application and generating platform-specific distributable formats like [DMG](dmg.mdx), [AppX](appx.md), or [Flatpak](flatpak.md) files (amongst others). + +Each maker has to be configured in the `makers` section of your Forge configuration. For example: + + + + +```javascript +module.exports = { + makers: [ + { + name: '@electron-forge/maker-zip', + platforms: ['darwin', 'linux'], + config: { + // the config can be an object + } + }, + { + name: '@electron-forge/maker-dmg', + config: (arch) => ({ + // it can also be a function taking the currently built arch + // as a parameter and returning a config object, e.g. + }) + } + ] +}; +``` + + + + + +```json +// Only showing the relevant configuration for brevity +{ + "config": { + "forge": { + "makers": [ + { + "name": "@electron-forge/maker-zip", + "platforms": ["darwin", "linux"], // optional + "config": { + // Config here + } + } + ] + } + } +} +``` + + + + +:::info +If a Maker supports multiple platforms, you may specify which platforms you want to target. Note that all Makers have logical defaults for the `platforms` value so you normally don't need to specify that property. +::: diff --git a/docs/config/makers/msix.md b/docs/config/makers/msix.md new file mode 100644 index 0000000000..a1a7902c8a --- /dev/null +++ b/docs/config/makers/msix.md @@ -0,0 +1,57 @@ +--- +description: >- + Create a MSIX package that can be shipped as a direct download or to the Microsoft Store for your Electron app, using Electron + Forge. +--- + +# MSIX + +:::info + +MSIX support was added in Electron Forge v7.10 and is currently **experimental**. Breaking changes to the configuration may be introduced between releases. + +::: + +The [MSIX](https://learn.microsoft.com/en-us/windows/msix/overview) target builds `.msix` packages, which can be directly distributed to end user or to the [Microsoft Store](https://apps.microsoft.com/home). + +## Requirements + +You can only build the MSIX target on Windows 10 or 11 machines with the [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) installed. Check the [`electron-windows-msix` docs](https://github.com/bitdisaster/electron-windows-msix) for more information on platform requirements. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-msix +``` + +## Usage + +To use `@electron-forge/maker-msix`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-msix', + config: { + manifestVariables: { + publisher: 'Electron Dev' + }, + windowsSignOptions: { + certificateFile: 'C:\\devcert.pfx', + certificatePassword: '122345' + } + } + } + ] +}; +``` + +Configuration options are documented in [`MakerMSIXConfig`](https://js.electronforge.io/types/_electron_forge_maker_msix.MakerMSIXConfig.html). + +For advanced code-signing use-cases, this maker utilizes @electron/windows-sign via the `windowsSignOptions` property. see the [windows-sign](https://github.com/electron/windows-sign/blob/main/README.md) README for more details. + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-windows-msix*` environment variable +or set the `logLevel` to `debug` in the maker config. diff --git a/docs/config/makers/pkg.mdx b/docs/config/makers/pkg.mdx new file mode 100644 index 0000000000..08c4b4870e --- /dev/null +++ b/docs/config/makers/pkg.mdx @@ -0,0 +1,92 @@ +--- +description: Create a .pkg file for your Electron app on macOS using Electron Forge. +--- + +# pkg + +The pkg target builds a `.pkg` installer for macOS. These are used to upload your application to the Mac App Store (MAS), or can be used as an alternate distribution method to users outside of the app store. + +
+ +

Installation wizard when opening the .pkg installer file

+
+ +This format is often referred to as a **flat package installers** for historical purposes. Prior to Mac OS X Leopard (10.5), installation packages were organized in hierarchical directories. OS X Leopard introduced a new flat package format that is used for modern `.pkg` installers. + +The flat installer package format is sparsely documented by Apple. If you want to learn more about its specification, there are a few userland articles available: + +* [Flat Package Format - The missing documentation](http://s.sudre.free.fr/Stuff/Ivanhoe/FLAT.html) (Stéphane Sudre) +* [The Flat Package - Examining a newer package format](https://preserve.mactech.com/articles/mactech/Vol.26/26.02/TheFlatPackage/index.html) (MacTech) + +## Requirements + +You can only build the pkg target on macOS machines while targeting the `darwin` or `mas` platforms. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-pkg +``` + +## Usage + +To use `@electron-forge/maker-pkg`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-pkg', + config: { + keychain: 'my-secret-ci-keychain' + // other configuration options + } + } + ] +}; +``` + +All configuration options are optional, and options are documented in the API docs for [`MakerPKGConfig`](https://js.electronforge.io/interfaces/_electron_forge_maker_pkg.MakerPKGConfig.html). + +### Adding installation scripts + +With the pkg maker, you can add either a `preinstall` or `postinstall` bash script that runs before and after your app is installed, respectively. + +Both `preinstall` and `postinstall` scripts need to: + +* have execution permissions +* be extension-less +* be located in the same folder in your filesystem + +For example, they can live in a folder in your project called `scripts`. + +```text +my-app +├─── forge.config.js +└─── scripts +    ├── postinstall +    └── preinstall +``` + +Then, configure the Maker point its `scripts` property to the `./scripts` folder. + +```javascript title="forge.config.js" {1,8} +const path = require('node:path'); + +module.exports = { + makers: [ + { + name: '@electron-forge/maker-pkg', + config: { + scripts: path.join(__dirname, 'scripts') + } + } + ] +}; +``` + +## Debugging + +All logs for your flat package installer can be found in macOS installation logs, which are stored in `/var/log/install.log`. They are also accessible within the [Console.app](https://support.apple.com/en-ca/guide/console/welcome/mac) utility. + +For advanced debug logging for this maker, add the `DEBUG=electron-osx-sign*` environment variable. diff --git a/docs/config/makers/rpm.md b/docs/config/makers/rpm.md new file mode 100644 index 0000000000..6c437e9f36 --- /dev/null +++ b/docs/config/makers/rpm.md @@ -0,0 +1,56 @@ +--- +description: >- + Create an RPM package for RedHat-based Linux distributions for your Electron + app, using Electron Forge. +--- + +# RPM + +The RPM target builds `.rpm` files, which is the standard package format for Red Hat-based Linux distributions such as [Fedora](https://fedoraproject.org/) and [Red Hat Enterprise Linux](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux) (RHEL). + +## Requirements + +You can only build the RPM target on Linux machines with the `rpm` or `rpm-build` packages installed. + +On Fedora you can do something like this: + +```shell +sudo dnf install rpm-build +``` + +While on Debian or Ubuntu you'll need to do this: + +```shell +sudo apt-get install rpm +``` + +## Installation + +```shell +npm install --save-dev @electron-forge/maker-rpm +``` + +## Usage + +To use `@electron-forge/maker-rpm`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-rpm', + config: { + options: { + homepage: 'http://example.com' + } + } + } + ] +}; +``` + +Configuration options are documented in [`MakerRpmConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_rpm.MakerRpmConfig.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-installer-redhat*` environment variable. diff --git a/docs/config/makers/snapcraft.md b/docs/config/makers/snapcraft.md new file mode 100644 index 0000000000..45fc99d9ab --- /dev/null +++ b/docs/config/makers/snapcraft.md @@ -0,0 +1,45 @@ +--- +description: Create a Snap package for your Electron app using Electron Forge. +--- + +# Snapcraft + +The [Snapcraft](https://snapcraft.io/) target builds `.snap` files, which is the packaging format created and sponsored by Canonical, the company behind Ubuntu. It is a sandboxed package format that lets users of various Linux distributions install your application in an isolated environment on their machine. + +## Requirements + +You can only build the Snapcraft target on Linux systems with the [`snapcraft`](https://snapcraft.io/) package installed. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-snap +``` + +## Usage + +To use `@electron-forge/maker-snap`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-snap', + config: { + features: { + audio: true, + mpris: 'com.example.mpris', + webgl: true + }, + summary: 'Pretty Awesome' + } + } + ] +}; +``` + +Configuration options are documented in [`MakerSnapConfig`](https://js.electronforge.io/types/_electron_forge_maker_snap.MakerSnapConfig.html). + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-installer-snap*` environment variable. diff --git a/docs/config/makers/squirrel.windows.md b/docs/config/makers/squirrel.windows.md new file mode 100644 index 0000000000..12c29d26d8 --- /dev/null +++ b/docs/config/makers/squirrel.windows.md @@ -0,0 +1,140 @@ +--- +description: Create a Windows installer for your Electron app using Electron Forge. +--- + +# Squirrel.Windows + +The Squirrel.Windows target builds your application using the [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows) framework. It generates three files: + +| File | Description | +| --- | --- | +| `{appName} Setup.exe` | The main executable installer for your application | +| `{appName}-full.nupkg` | The NuGet package file used for updates | +| `RELEASES` | Metadata file used to check if an update is available | + +Squirrel.Windows is a no-prompt, no-hassle, no-admin method of installing Windows applications, and is therefore the most user friendly you can get. + +## Requirements + +You can only build the Squirrel.Windows target on a Windows machine or on a Linux machine with [`mono`](https://www.mono-project.com/) and [`wine`](https://www.winehq.org/) installed. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-squirrel +``` + +## Usage + +Add this module to the [makers](index.mdx) section of your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: { + certificateFile: './cert.pfx', + certificatePassword: process.env.CERTIFICATE_PASSWORD + } + } + ] +}; +``` + +The Squirrel.Windows maker inherits all of its config options from the [`electron-winstaller`](https://github.com/electron/windows-installer) module, _except_ for `appDirectory` and `outputDirectory`, which are set by the maker. + +Complete configuration options are documented in the [`MakerSquirrelConfig`](https://js.electronforge.io/types/_electron_forge_maker_squirrel.MakerSquirrelConfig.html) types. + +### Mandatory metadata + +Squirrel.Windows requires mandatory package metadata to satisfy the [`.nuspec`](https://learn.microsoft.com/en-us/nuget/reference/nuspec) manifest format. There are two ways to specify this information in Electron Forge. + +#### In package.json + +By default, the Squirrel.Windows maker fetches the `author` and `description` fields in the project's package.json file. + +```jsonc title="package.json" +{ + // ... + "author": "Alice and Bob", + "description": "An example Electron app" + // ... +} +``` + +#### In your Forge config + +Alternatively, you can also override these values directly in your Squirrel.Windows maker config. + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: { + authors: 'Alice and Bob', + description: 'An example Electron app' + } + } + ] +}; +``` + +:::warning +Note that the Forge config field is **"authors"** while the package.json field is called **"author".** +::: + +### Handling startup events + +When first running your app, updating it, and uninstalling it, Squirrel.Windows will spawn your app an additional time with some special arguments. You can read more about these arguments on the [`electron-winstaller`](https://github.com/electron/windows-installer) README. + +The easiest way to handle these arguments and stop your app launching multiple times during these events is to use the [`electron-squirrel-startup`](https://github.com/mongodb-js/electron-squirrel-startup) module as one of the first things your app does. + +```javascript title="main.js" +const { app } = require('electron'); + +// run this as early in the main process as possible +if (require('electron-squirrel-startup')) app.quit(); +``` + +### Spaces in the app name + +Squirrel.Windows can behave unexpectedly when application names contain spaces. You can use the following setup in this case, which works well: + +```json5 title="package.json" +{ + // Hyphenated version + "name": "app-name", + // The app name with spaces (will be shown to your users) + "productName": "App Name", + // ... +} +``` + +```typescript title="forge.config.ts" +const config: ForgeConfig = { + makers: [ + new MakerSquirrel({ + // CamelCase version without spaces + name: "AppName", + // ... + }), + ], + // ... +} +``` + +Additionally, you'll need to set the App User Model ID from your main process like this: + +```typescript title="main.ts" +app.setAppUserModelId("com.squirrel.AppName.AppName"); +``` + +Squirrel.Windows will use the `productName` from your `package.json` for any user-facing strings and for the name of your `Setup.exe`. + +It will use the camel-cased `name` from the `MakerSquirrel` config for the NuGet package name. NuGet package names cannot contain spaces. + +## Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-windows-installer*` environment variable. diff --git a/docs/config/makers/wix-msi.md b/docs/config/makers/wix-msi.md new file mode 100644 index 0000000000..c710ce87ea --- /dev/null +++ b/docs/config/makers/wix-msi.md @@ -0,0 +1,49 @@ +--- +description: Create an MSI file for your Electron app on Windows using Electron Forge. +--- + +# WiX MSI + +The WiX MSI target builds `.msi` files, which are "traditional" Windows installer files. + +:::warning +We generally recommend using the [Squirrel.Windows](squirrel.windows.md) target over using this one. These MSI files are a worse user experience for installation but sometimes it is necessary to build MSI files to appease large-scale enterprise companies with internal application distribution policies. +::: + +## Requirements + +You can only build the WiX MSI target on machines with [WiX Toolset v3](https://wixtoolset.org/docs/wix3/) installed. We recommend pinning your installation of WiX Toolset to a specific version. You can install WiX Toolset on Windows via [Chocolatey](https://chocolatey.org/). + +```bash +choco install wixtoolset --version=3.14.0 +``` + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-wix +``` + +## Usage + +To use `@electron-forge/maker-wix`, add it to the `makers` array in your [Forge configuration](../configuration.mdx): + +```javascript +module.exports = { + makers: [ + { + name: '@electron-forge/maker-wix', + config: { + language: 1033, + manufacturer: 'My Awesome Company' + } + } + ] +}; +``` + +Configuration options are documented in [`MakerWixConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_wix.MakerWixConfig.html). + +### Debugging + +For advanced debug logging for this maker, add the `DEBUG=electron-wix-msi*` environment variable. diff --git a/docs/config/makers/zip.md b/docs/config/makers/zip.md new file mode 100644 index 0000000000..febdbf2300 --- /dev/null +++ b/docs/config/makers/zip.md @@ -0,0 +1,71 @@ +--- +description: Create a ZIP archive for your Electron app using Electron Forge. +--- + +# ZIP + +The ZIP target builds basic [.zip archives](https://en.wikipedia.org/wiki/ZIP\_\(file\_format\)) containing your packaged application. There are no platform-specific dependencies for using this maker and it will run on any platform. + +## Installation + +```bash +npm install --save-dev @electron-forge/maker-zip +``` + +## Usage + +To use `@electron-forge/maker-zip`, add it to the `makers` array in your Forge configuration. + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-zip' + } + ] +}; +``` + +All configuration options are optional, and options are documented in the API docs for [MakerZIPConfig](https://js.electronforge.io/interfaces/\_electron\_forge\_maker\_zip.MakerZIPConfig.html). + +### Static file auto-updates (macOS) + +On macOS, the ZIP maker can be configured to generate update manifests to use with Electron's [autoUpdater](https://electronjs.org/docs/latest/api/auto-updater) module. + +```javascript title="forge.config.js" +module.exports = { + makers: [ + { + name: '@electron-forge/maker-zip', + config: (arch) => ({ + macUpdateManifestBaseUrl: `https://my-bucket.s3.amazonaws.com/my-app-updates/darwin/${arch}` + }) + } + ] +}; +``` + +`macUpdateManifestBaseUrl` should be a path to an object storage bucket where you are storing your release assets. This bucket needs to be organized in folders by platform, then architecture. + +The first time you run `make` with this parameter configured, an architecture-specific `RELEASES.json` manifest will be generated. For example, if you are building v1.2.1 of `my-app` for arm64 (Apple Silicon): + +```json title="forge.config.js" +{ + "currentRelease": "1.2.1", + "releases": [ + { + "version": "1.2.1", + "updateTo": { + "version": "1.2.1", + "pub_date": "2013-09-18T12:29:53+01:00", + "name": "my-app v1.2.1", + "url": "https://my-bucket.s3.amazonaws.com/my-app-updates/darwin/arm64/my-app-1.2.1-darwin-arm64.zip" + } + } + ] +} +``` + +Once this asset is uploaded to the bucket, subsequent runs will read from the existing manifest at `https://my-bucket.s3.amazonaws.com/my-app-updates/darwin/arm64/RELEASES.json` and modify it to update the `currentRelease` property to the next version that is built. + +For end-to-end instructions on this process, including how to publish assets to S3 and set up the autoUpdater to read the `RELEASES.json` manifest, see the [Auto updating from S3](../publishers/s3.mdx#auto-updating-from-s3) guide. diff --git a/docs/config/plugins/auto-unpack-natives.md b/docs/config/plugins/auto-unpack-natives.md new file mode 100644 index 0000000000..ecf7d083ee --- /dev/null +++ b/docs/config/plugins/auto-unpack-natives.md @@ -0,0 +1,37 @@ +--- +description: >- + Reduce loading times and disk consumption by unpacking native Node modules + from your Forge app's ASAR archive. +--- + +# Auto Unpack Native Modules Plugin + +This plugin will automatically add all native Node modules in your `node_modules` folder to the [`asar.unpack`](https://electron.github.io/packager/main/interfaces/Options.html#asar) config option in your [`packagerConfig`](../configuration.mdx#electron-packager-config). If your app uses native Node modules, you should probably use this to reduce loading times and disk consumption on your users' machines. + +## Installation + +```shell +npm install --save-dev @electron-forge/plugin-auto-unpack-natives +``` + +## Usage + +You must add this plugin to your [`plugins`](../configuration.mdx#plugins) array in your Forge configuration. There are currently no configuration options available for this plugin. + +:::info +Asar archives are disabled by default with Electron Packager. Make sure you set your `packagerConfig.asar` value accordingly. This option also supports advanced configuration if you pass it an object. See the [API documentation for this option](https://js.electronforge.io/modules/_electron_forge_shared_types.InternalOptions.html#CreateOptions) for more information. +::: + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: { + asar: true // or an object containing your asar options + }, + plugins: [ + { + name: '@electron-forge/plugin-auto-unpack-natives', + config: {} + } + ] +}; +``` diff --git a/docs/config/plugins/electronegativity.md b/docs/config/plugins/electronegativity.md new file mode 100644 index 0000000000..76c9c833a1 --- /dev/null +++ b/docs/config/plugins/electronegativity.md @@ -0,0 +1,36 @@ +--- +description: >- + Check for misconfigurations and security anti-patterns with the + Electronegativity tool. +--- + +# Electronegativity Plugin + +The Electronegativity plugin integrates Doyensec's [Electronegativity tool](https://github.com/doyensec/electronegativity#electronegativity) into the Electron Forge workflow. After packaging your Electron app, it identifies any known misconfigurations and security anti-patterns. + +## Installation + +```shell +npm install --save-dev @electron-forge/plugin-electronegativity +``` + +## Usage + +Add this plugin to the [`plugins`](../configuration.mdx#plugins) array in your Forge configuration. All [programmatic options for Electronegativity](https://github.com/doyensec/electronegativity#programmatically), except for `input` and `electronVersion`. + +### Example + +```javascript title="forge.config.js" +module.exports = { + // ... + plugins: [ + { + name: '@electron-forge/plugin-electronegativity', + config: { + isSarif: true + } + } + ] + // ... +}; +``` diff --git a/docs/config/plugins/fuses.mdx b/docs/config/plugins/fuses.mdx new file mode 100644 index 0000000000..e9248aaa32 --- /dev/null +++ b/docs/config/plugins/fuses.mdx @@ -0,0 +1,84 @@ +--- +description: Toggle Electron functionality at package-time with Electron Fuses. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Fuses Plugin + +> Added in version 6.1.0 + +This plugin allows flipping [Electron Fuses](https://www.electronjs.org/docs/latest/tutorial/fuses) when packaging your app with Electron Forge. Fuses are bits in the Electron binary that allow certain features to be enabled/disabled when your app is packaged. In most cases, if you want to change how Electron works internally, you have to grab the source files, make any changes you need, and compile it yourself, which is a major task. + +Fuses are meant to simplify this process for a subset of common features: instead of compiling your own Electron binary, you can modify the existing pre-built binary at package-time using Fuses so that these features are enabled/disabled in your packaged app. + +For example, by default, you can run your Electron app as a normal Node.js process if you have the `ELECTRON_RUN_AS_NODE` environment variable set to `1`. If you don't want users to be able to do this, you can disable this behavior by setting the [RunAsNode](https://www.electronjs.org/docs/latest/tutorial/fuses#runasnode) fuse to `false` at package-time. If your app is code-signed, users can't change any Fuses you have flipped, as the operating system would detect that the binary has changed and prevent the app from running. + +For an updated list of the features that can be enabled/disabled using Fuses, please refer to the [official Fuses tutorial](https://www.electronjs.org/docs/latest/tutorial/fuses) and the [@electron/fuses docs](https://www.electronjs.org/docs/latest/tutorial/fuses). + +## Installation + +:::info +This plugin has a peer dependency on `@electron/fuses`, so don't forget to install it too! +::: + +```shell +npm install --save-dev @electron-forge/plugin-fuses @electron/fuses +``` + +## Usage + +You can use the `FusesPlugin` constructor just like the `flipFuses` function from `@electron/fuses`, except that the plugin already takes care of the Electron path for you, so you only need to provide the configuration object. + + + + +```js +const { FusesPlugin } = require('@electron-forge/plugin-fuses'); +const { FuseV1Options, FuseVersion } = require('@electron/fuses'); + +const forgeConfig = { + // ... + plugins: [ + new FusesPlugin({ + version: FuseVersion.V1, + [FuseV1Options.RunAsNode]: false + // ...any other options supported by @electron/fuses + }) + ] + // ... +}; + +module.exports = forgeConfig; +``` + + + + +The example above assumes you're using `@electron/fuses` v1.x, which is the latest major version as of the time of writing; however, this plugin should work with any version of `@electron/fuses`. For instance, if `@electron/fuses` v2.x is released and you want to use some new fuse that comes with it, you'll just need to upgrade your `@electron/fuses` package to v2.x and update your Forge configuration: + + + + +```js +const { FusesPlugin } = require('@electron-forge/plugin-fuses'); +const { FuseV2Options, FuseVersion } = require('@electron/fuses'); + +const forgeConfig = { + // ... + plugins: [ + new FusesPlugin({ + version: FuseVersion.V2, + [FuseV2Options.SomeV2OnlyFuse]: false + // ...any other options supported by @electron/fuses + }) + ] + // ... +}; + +module.exports = forgeConfig; +``` + + + diff --git a/docs/config/plugins/index.md b/docs/config/plugins/index.md new file mode 100644 index 0000000000..8d5cb70b5b --- /dev/null +++ b/docs/config/plugins/index.md @@ -0,0 +1,25 @@ +--- +description: Modules to extend Forge's core functionality +--- + +# Plugins + +Electron Forge has a plugin system which allows you to extend its core functionality. + +By default, Forge takes a vanilla JS application and packages, makes and publishes it (see the [Build Lifecycle](../../core-concepts/build-lifecycle.md) document for more details). Plugins can execute custom logic during any of the Forge [Hooks](../hooks.md) during the build process, and can also override the [Start](../../cli.md#start) command in development. + +:::info +If you want to write your own Forge plugin, check out the [Writing Plugins](../../advanced/extending-electron-forge/writing-plugins.md) guide. +::: + +## Bundler plugins + +- [Webpack Plugin](webpack.mdx) - Build your Electron app with webpack +- [Vite Plugin](vite.mdx) - Build your Electron app with Vite + +## Utility plugins + +- [Auto Unpack Native Modules Plugin](auto-unpack-natives.md) - Unpack native Node.js modules from your Forge app's ASAR archive. +- [Local Electron Plugin](local-electron.md) - Integrate a local build of Electron into your Forge app. +- [Fuses Plugin](fuses.mdx) - Toggle Electron functionality at package-time with Electron Fuses. +- [Electronegativity Plugin](electronegativity.md) - Check for misconfigurations and security anti-patterns with the Electronegativity tool. diff --git a/docs/config/plugins/local-electron.md b/docs/config/plugins/local-electron.md new file mode 100644 index 0000000000..987f2f0ece --- /dev/null +++ b/docs/config/plugins/local-electron.md @@ -0,0 +1,42 @@ +--- +description: Integrate a local build of Electron into your Forge app. +--- + +# Local Electron Plugin + +:::info +This plugin should only be used by people who are building Electron locally themselves. If you want to use a fork of Electron, check out the [environment variables](https://github.com/electron/get#usage) you can use to configure `@electron/get`. +::: + +This plugin allows you to both run and build your app using a **local** build of Electron. This can be incredibly useful if you want to test a feature or a bug fix in your app before making a PR up to the Electron repository. + +If you want to set up a local build of Electron, you should check out [Electron Build Tools](https://github.com/electron/build-tools). + +### Installation + +```bash +npm install --save-dev @electron-forge/plugin-local-electron +``` + +### Usage + +Once you have a working build of Electron, point the plugin's `electronPath` config option to the folder containing the built Electron binary. + +All possible configuration options are documented in [`LocalElectronPluginConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_plugin\_local\_electron.LocalElectronPluginConfig.html). + +```javascript title="forge.config.js" +{ + plugins: [ + { + name: '@electron-forge/plugin-local-electron', + config: { + electronPath: '/Users/me/projects/electron/out/Testing' + } + } + ] +} +``` + +:::info +Please note that the plugin only accepts **absolute paths**. You should use Node's [`path.resolve()`](https://nodejs.org/api/path.html#pathresolvepaths) to make things deterministic. +::: diff --git a/docs/config/plugins/vite.mdx b/docs/config/plugins/vite.mdx new file mode 100644 index 0000000000..7fb91f4893 --- /dev/null +++ b/docs/config/plugins/vite.mdx @@ -0,0 +1,193 @@ +--- +description: Transform and bundle code for your Electron Forge app with Vite. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Vite Plugin + +:::info +As of Electron Forge v7.5.0, Vite support for Electron Forge has been marked as **experimental** in order to reflect its stage in development and to provide maintainers with the ability to release fixes and improvements rapidly. Future minor releases may contain breaking changes, but migration steps will be listed in release notes.\ +\ +For more context, see the Electron Forge [v7.5.0 release notes](https://github.com/electron/forge/releases/tag/v7.5.0). +::: + +This plugin makes it easy to set up standard Vite tooling to compile both your main process code and your renderer process code. + +## Installation + +```shell +npm install --save-dev @electron-forge/plugin-vite +``` + +## Usage + +### Plugin configuration + +You must provide two Vite configuration files: one for the main process in `vite.main.config.js`, and one for the renderer process in `vite.renderer.config.js`. + +For example, this is the [configuration](../configuration.mdx) taken from Forge's [Vite template](../../templates/vite.md): + + + + +```javascript +module.exports = { + plugins: [ + { + name: '@electron-forge/plugin-vite', + config: { + // `build` can specify multiple entry builds, which can be + // Main process, Preload scripts, Worker process, etc. + build: [ + { + // `entry` is an alias for `build.lib.entry` + // in the corresponding file of `config`. + entry: 'src/main.js', + config: 'vite.main.config.mjs' + }, + { + entry: 'src/preload.js', + config: 'vite.preload.config.mjs' + } + ], + renderer: [ + { + name: 'main_window', + config: 'vite.renderer.config.mjs' + } + ] + } + } + ] +}; +``` + + + + + +```json +{ + // ... + "config": { + "forge": { + "plugins": [ + { + "name": "@electron-forge/plugin-vite", + "config": { + "build": [ + { + "entry": "src/main.js", + "config": "vite.main.config.mjs" + }, + { + "entry": "src/preload.js", + "config": "vite.preload.config.mjs" + } + ], + "renderer": [ + { + "name": "main_window", + "config": "vite.renderer.config.mjs" + } + ] + } + } + ] + } + } + // ... +} +``` + + + + +Config options will largely follow the same standards as non-Electron Vite projects. You can reference [Vite's documentation here](https://vitejs.dev/config/) for more examples of how to configure each of your entry point's config files. + +### Project files + +Vite's build config generates a separate entry for the main process and preload script, as well as each renderer process. + +Your `main` entry in your `package.json` file needs to point at `".vite/build/main"`, like so: + +```json title="package.json" +{ + "name": "my-vite-app", + "main": ".vite/build/main.js", + // ... +} +``` + +If using the Vite template, this should be automatically set up for you. + +## Advanced configuration + +### Build concurrency + +Under the hood, the Vite plugin spawns a separate Vite build for each target. These builds first run in parallel for all renderer targets, then for all main and preload targets. Vite can sometimes use a lot of memory, and having many builds simultaneously can cause Out of Memory issues (see [vitejs/vite#2433](https://github.com/vitejs/vite/issues/2433)). + +Starting from Forge v7.9.0, you can pass a boolean or integer value to the plugin's `concurrent` option to limit how many build jobs run at once to alleviate memory issues. + +```javascript title="forge.config.js" +module.exports = { + plugins: { + name: '@electron-forge/plugin-vite', + config: { + build: [/* ... */], + renderer: [/* ... */], + concurrent: false // accepts a boolean or positive integer + } + } +}; +``` + +### Native Node modules + +If you used the [Vite](../../templates/vite.md) template to create your application, native modules will mostly work out of the box. However, to avoid possible build issues, we recommend instructing Vite to load them as external packages: + +```javascript title="vite.main.config.js" +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + external: [ + 'serialport', + 'sqlite3' + ] + } + } +}); +``` + +### Hot Module Replacement (HMR) + +In order to use Vite's [Hot Module Replacement (HMR)](https://vitejs.dev/guide/features.html#hot-module-replacement), all `loadURL` paths need to reference the global variables that the Vite plugin will define for you: + +* The dev server will be suffixed with `_DEV_SERVER_URL` +* The static file path will be suffixed with `_VITE_NAME` + +In the case of the `main_window`, the global variables will be named `MAIN_WINDOW_VITE_DEV_SERVER_URL` and `MAIN_WINDOW_VITE_NAME`. An example of how to use them is given below: + +```javascript title="main.js" +const mainWindow = new BrowserWindow({ /* ... */ }); + +if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { + mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL); +} else { + mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)); +}; +``` + +:::info +If using TypeScript, the variables can be defined as such: + +```typescript title="main.js (Main Process)" {1} +declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string; +declare const MAIN_WINDOW_VITE_NAME: string; +``` + +::: diff --git a/docs/config/plugins/webpack.mdx b/docs/config/plugins/webpack.mdx new file mode 100644 index 0000000000..0b1de365d0 --- /dev/null +++ b/docs/config/plugins/webpack.mdx @@ -0,0 +1,445 @@ +--- +description: Transform and bundle code for your Electron Forge app with webpack. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Webpack Plugin + +This plugin makes it easy to set up standard [webpack](https://webpack.js.org/) tooling to compile both your main process code and your renderer process code, with built-in support for [Hot Module Replacement (HMR)](https://webpack.js.org/concepts/hot-module-replacement/) in the renderer process and support for multiple renderers. + +## Installation + +```shell +npm install --save-dev @electron-forge/plugin-webpack +``` + +## Usage + +### Plugin configuration + +You must provide two webpack configuration files: one for the main process in `mainConfig`, and one for the renderer process in `renderer.config`. The complete config options are available in the API docs under [`WebpackPluginConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_plugin\_webpack.WebpackPluginConfig.html). + +For example, this is the [configuration](../configuration.mdx) taken from Forge's [webpack template](../../templates/webpack-template.md): + + + + +```javascript +module.exports = { + // ... + plugins: [ + { + name: '@electron-forge/plugin-webpack', + config: { + mainConfig: './webpack.main.config.js', + renderer: { + config: './webpack.renderer.config.js', + entryPoints: [{ + name: 'main_window', + html: './src/renderer/index.html', + js: './src/renderer/index.js', + preload: { + js: './src/preload.js' + } + }] + } + } + } + ] + // ... +}; +``` + + + + + +```jsonc +{ + // ... + "config": { + "forge": { + "plugins": [ + { + "name": "@electron-forge/plugin-webpack", + "config": { + "mainConfig": "./webpack.main.config.js", + "renderer": { + "config": "./webpack.renderer.config.js", + "entryPoints": [{ + "name": "main_window", + "html": "./src/renderer/index.html", + "js": "./src/renderer/index.js", + "preload": { + "js": "./src/preload.js" + } + }] + } + } + } + ] + } + } + // ... +} +``` + + + + +### Project files + +This plugin generates a separate entry for the main process, as well as each renderer process and preload script. + +You need to do two things in your project files in order to make this plugin work. + +#### package.json + +First, your `main` entry in your `package.json` file needs to point at `"./.webpack/main"` like so: + +```jsonc title="package.json" +{ + "name": "my-app", + "main": "./.webpack/main", + // ... +} +``` + +#### Main process code + +Second, all `loadURL` and `preload` paths need to reference the magic global variables that this plugin will define for you. + +Each entry point has two globals defined based on the name assigned to your entry point: + +* The renderer's entry point will be suffixed with `_WEBPACK_ENTRY` +* The renderer's preload script will be suffixed with `_PRELOAD_WEBPACK_ENTRY` + +In the case of the `main_window` entry point in the earlier example, the global variables will be named `MAIN_WINDOW_WEBPACK_ENTRY` and `MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY`. An example of how to use them is given below: + +```javascript title="main.js" +const mainWindow = new BrowserWindow({ + webPreferences: { + preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY + } +}); + +mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); +``` + +These variables are only defined in the main process. If you need to use one of these paths in a renderer (e.g. to pass a preload script to a `` tag), you can pass the magic variable value with a synchronous IPC round trip. + + + + +```javascript title="main.js" +// make sure this listener is set before your renderer.js code is called +ipcMain.on('get-preload-path', (e) => { + e.returnValue = WINDOW_PRELOAD_WEBPACK_ENTRY; +}); +``` + + + + + +```javascript title="preload.js" +const { contextBridge, ipcRenderer } = require('electron'); + +contextBridge.exposeInMainWorld('electron', { + getPreloadPath: () => ipcRenderer.sendSync('get-preload-path') +}); +``` + + + + + +```javascript title="renderer.js" +const preloadPath = window.electron.getPreloadPath(); +``` + + + + +:::info +**Usage with TypeScript** + +If you're using the webpack plugin with TypeScript, you will need to manually declare these magic variables to avoid compiler errors. + +```typescript title="main.js (Main Process)" +declare const MAIN_WINDOW_WEBPACK_ENTRY: string; +declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string; +``` + +::: + +## Preload scripts + +You can attach a preload script to any window entry point by setting the `preload` key on that entry point, as shown in the [plugin configuration](#plugin-configuration) example above: + +```javascript +{ + name: 'main_window', + html: './src/renderer/index.html', + js: './src/renderer/index.js', + preload: { + js: './src/preload.js' + } +} +``` + +### Preload scripts are sandboxed by default + +:::warning +This is a behavior change from Forge 6. If you are upgrading from 6.x, read this section carefully. +::: + +Since [Electron 20](https://www.electronjs.org/blog/electron-20-0#renderers-sandboxed-by-default), renderer processes (and their preload scripts) are **sandboxed by default**. To match this, the webpack plugin compiles each preload script with the [`sandboxedPreload` webpack target](https://webpack.js.org/configuration/target/) by default. + +A sandboxed preload script runs in a restricted environment: it does **not** have access to Node.js APIs such as `require`, `process`, or Node core modules. It can still use the [polyfilled subset of Node](https://www.electronjs.org/docs/latest/tutorial/sandbox#preload-scripts) that Electron exposes to sandboxed preloads (for example `electron`, and a limited version of `process`), which is enough to set up a [`contextBridge`](https://www.electronjs.org/docs/latest/api/context-bridge). This is the recommended, secure default for most apps. + +If your preload script worked in Forge 6 by calling `require` or otherwise depending on full Node.js access, it will fail under the sandboxed default. You have two options for giving a preload full Node.js access. + +#### Option 1: Enable `nodeIntegration` on the window entry point + +The preload's webpack target is derived from the `nodeIntegration` value of the entry point it belongs to. When `nodeIntegration` is `true` (set either on the entry point or on `renderer.nodeIntegration`), the preload is compiled with the `electronPreload` target instead, which grants full Node.js access. + +```javascript title="Plugin configuration" +{ + name: 'main_window', + html: './src/renderer/index.html', + js: './src/renderer/index.js', + nodeIntegration: true, // preload is compiled with the `electronPreload` target + preload: { + js: './src/preload.js' + } +} +``` + +:::warning +Enabling `nodeIntegration` disables the sandbox for that window's renderer as well, which reduces the security of your application. Prefer keeping the sandbox enabled and exposing only what you need through the `contextBridge`. +::: + +#### Option 2: Use a preload-only entry point + +If you only need full Node.js access in the preload but want to keep it as a standalone entry (for example to attach it to a ``), you can declare a **preload-only entry point**. It takes a `name` and a `preload` object, and its `nodeIntegration` value controls the preload's webpack target independently of any window: + +```javascript title="Plugin configuration" +{ + name: 'main_window_preload', + nodeIntegration: true, + preload: { + js: './src/preload.js' + } +} +``` + +The generated global for this entry is derived from its `name` with the `_PRELOAD_WEBPACK_ENTRY` suffix — so the entry named `main_window_preload` above is exposed to the main process as `MAIN_WINDOW_PRELOAD_PRELOAD_WEBPACK_ENTRY`. + +## Advanced configuration + +### webpack-dev-server + +Forge's webpack plugin uses [`webpack-dev-server`](https://webpack.js.org/configuration/dev-server/) to help you quickly iterate on renderer process code in development mode. Running `electron-forge start` with the webpack plugin active will launch a dev server that is configurable through the plugin config. + +#### devServer + +In development mode, you can change most `webpack-dev-server` options by setting `devServer` in your Forge Webpack plugin configuration. + +```javascript title="Plugin configuration" +{ + name: '@electron-forge/plugin-webpack', + config: { + // other Webpack plugin config... + devServer: { + stats: 'verbose' + } + // ... + } +} +``` + +#### devContentSecurityPolicy + +In development mode, you can set a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) by setting `devContentSecurityPolicy` in your Forge Webpack plugin configuration. + +```javascript +{ + name: '@electron-forge/plugin-webpack', + config: { + // other Webpack plugin config... + devContentSecurityPolicy: 'default-src \'self\' \'unsafe-inline\' data:; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\' data:', + // other Webpack plugin config... + mainConfig: './webpack.main.config.js', + renderer: { + /* renderer config here, see above section */ + } + } +} +``` + +:::info +If you wish to use **source maps** in development, you'll need to set `'unsafe-eval'` for the [`script-src`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) directive. Using `'unsafe-eval'` will cause Electron itself to trigger a warning in the DevTools console about having that value enabled, which is usually fine so long as you **do not set that value in production**. +::: + +### Native Node modules + +If you used the [Webpack](../../templates/webpack-template.md) or [TypeScript + Webpack](../../templates/typescript-+-webpack-template.md) templates to create your application, native modules will mostly work out of the box. + +If you are setting up the plugin manually, you can make native modules work by adding the following two loaders to your `module.rules` configuration in your Webpack config. Ensure you install both [`node-loader`](https://www.npmjs.com/package/node-loader) and [`@vercel/webpack-asset-relocator-loader`](https://www.npmjs.com/package/@vercel/webpack-asset-relocator-loader) as development dependencies. + +```bash +npm install --save-dev node-loader @vercel/webpack-asset-relocator-loader@1.7.3 +``` + +:::warning +Electron Forge monkeypatches the asset relocator loader in order for it to work with Electron properly, so the version has been pinned to ensure compatibility. If you upgrade that version, you do so at your own risk. +::: + +```javascript title="webpack.main.config.js" +module.exports = { + module: { + rules: [ + { + // We're specifying native_modules in the test because the asset + // relocator loader generates a "fake" .node file which is really + // a cjs file. + test: /native_modules\/.+\.node$/, + use: 'node-loader' + }, + { + test: /\.(m?js|node)$/, + parser: { amd: false }, + use: { + loader: '@vercel/webpack-asset-relocator-loader', + options: { + outputAssetBase: 'native_modules' + } + } + } + ] + } +}; +``` + +If the asset relocator loader does not work for your native module, you may want to consider using webpack's [externals configuration](https://webpack.js.org/configuration/externals/). + +### Node integration + +#### Enabling Node integration in your app code + +In Electron, you can enable Node.js in the renderer process with [`BrowserWindow` constructor options](https://www.electronjs.org/docs/latest/api/browser-window). Renderers with the following options enabled will have a browser-like web environment with access to Node.js [`require`](https://nodejs.org/api/modules.html#requireid) and all of its core APIs: + +```javascript title="main.js (Main Process)" +const win = new BrowserWindow({ + webPreferences: { + contextIsolation: false, + nodeIntegration: true + } +}); +``` + +This creates a unique environment that requires additional webpack configuration. + +#### Setting the correct webpack target in your plugin config + +Webpack [targets](https://webpack.js.org/configuration/target/) have first-class support for various Electron environments. Forge's webpack plugin will set the compilation target for renderers based on the `nodeIntegration` option in the config: + +* When `nodeIntegration` is **true**, the `target` is `electron-renderer`. +* When `nodeIntegration` is **false**, the `target` is `web`. + +This option is **false** by default\*\*.\*\* You can set this option for all renderers via the `renderer.nodeIntegration` option, and you can override its value in each renderer you create in the `entryPoints` array. + +In the below configuration example, webpack will compile to the `electron-renderer` target for all entry points except for `media_player`, which will compile to the `web` target. + +```javascript title="Plugin configuration" +{ + name: '@electron-forge/plugin-webpack', + config: { + mainConfig: './webpack.main.config.js', + renderer: { + config: './webpack.renderer.config.js', + nodeIntegration: true, // Implies `target: 'electron-renderer'` for all entry points + entryPoints: [ + { + html: './src/app/app.html', + js: './src/app/app.tsx', + name: 'app' + }, + { + html: './src/mediaPlayer/index.html', + js: './src/mediaPlayer/index.tsx', + name: 'media_player', + nodeIntegration: false // Overrides the default nodeIntegration set above + } + ] + } + } +} +``` + +:::warning +It is important that you enable `nodeIntegration` in **both** in the main process code and the webpack plugin configuration. This option duplication is necessary because webpack targets are fixed upon compilation, but BrowserWindow's web preferences are determined on run time. +::: + +## Hot module replacement + +In development mode, all your renderer processes in development will have [Hot Module Replacement (HMR)](https://webpack.js.org/concepts/hot-module-replacement/) enabled by default thanks to `webpack-dev-server`. + +However, it is impossible for HMR to work inside preload scripts. However, webpack is constantly watching and recompiling those files so reload the renderer to get updates for preload scripts. + +For the main process, type `rs` in the console you launched `electron-forge` from and Forge will restart your app for you with the new main process code. + +### Hot reload caching + +When using Webpack 5 caching, asset permissions need to be maintained through their own cache, and the public path needs to be injected into the build. + +To insure these cases work out, make sure to run `initAssetCache` in the build, with the `options.outputAssetBase` argument: + +```javascript +const relocateLoader = require('@vercel/webpack-asset-relocator-loader'); +webpack({ + // ... + plugins: [ + { + apply (compiler) { + compiler.hooks.compilation.tap('webpack-asset-relocator-loader', compilation => { + relocateLoader.initAssetCache(compilation, outputAssetBase); + }); + } + } + ] +}); +``` + +### Hot Reloading for React + +If you're using React components, you may want to have HMR automatically pick up a change and reload the component without having to manually refresh the page. This is possible by installing [`react-hot-loader`](https://github.com/gaearon/react-hot-loader) to define which modules should be hot reloaded. + +Here's a usage example in TypeScript with `App` being the topmost component in a React component tree: + +```typescript +import { hot } from "react-hot-loader"; + +const App: FunctionComponent = () => ( +
+ ... +
+); + +export default hot(module)(App) +``` + +You can use this pattern in any other components depending on what you want to reload. For example, if you use the `hot()` HOC for an `AppBar` component and make a change to a child of `AppBar`, then the entire `AppBar` gets reloaded, but the higher-level `App` layout remains otherwise unchanged. In essence, a change will propagate up to the first `hot()` HOC found in a component tree. + +## What happens in production? + +In theory, you shouldn't need to care. In development, we spin up `webpack-dev-server` instances to power your renderer processes. In production, we just build the static files. + +Assuming you use the defined globals we explained in the above section, everything should work when your app is packaged. + +## How do I do virtual routing? + +If you want to use something like [`react-router`](https://github.com/ReactTraining/react-router) to do virtual routing in your app, you will need to ensure you use a history method that is not based on the browser history APIs. Browser history will work in development but not in production, as your code will be loaded from the filesystem, not a web server. In the `react-router` case, you should use the [`MemoryRouter`](https://reactrouter.com/en/main/router-components/memory-router) to make everything work. diff --git a/docs/config/publishers/bitbucket.md b/docs/config/publishers/bitbucket.md new file mode 100644 index 0000000000..b6c94d7116 --- /dev/null +++ b/docs/config/publishers/bitbucket.md @@ -0,0 +1,44 @@ +# Bitbucket + +The Bitbucket publish target allows you to publish your artifacts directly to Bitbucket where users will be able to download them. + +:::warning +This publish target is for [Bitbucket Cloud](https://bitbucket.org) only and will not work with self hosted Bitbucket Server instances. +::: + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-bitbucket +``` + +## Usage + +To use `@electron-forge/publisher-bitbucket`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-bitbucket', + config: { + repository: { + owner: 'myusername', + name: 'myreponame' + }, + auth: { + username: process.env.BITBUCKET_USERNAME, // string + appPassword: process.env.BITBUCKET_APP_PASSWORD // string + } + } + } + ] +}; +``` + +Full configuration options are documented in [`PublisherBitbucketConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_publisher\_bitbucket.PublisherBitbucketConfig.html). + +:::info +Your artifacts can be found under the `Downloads` tab of your Bitbucket repository. +::: diff --git a/docs/config/publishers/electron-release-server.md b/docs/config/publishers/electron-release-server.md new file mode 100644 index 0000000000..9c8fc27823 --- /dev/null +++ b/docs/config/publishers/electron-release-server.md @@ -0,0 +1,33 @@ +# Electron Release Server + +The Electron Release Server target publishes all your artifacts to a hosted instance of [Electron Release Server](https://github.com/ArekSredzki/electron-release-server). + +Please note that Electron Release Server is a community powered project and is not associated with Electron Forge or the Electron project directly. + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-electron-release-server +``` + +## Usage + +To use `@electron-forge/publisher-electron-release-server`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-electron-release-server', + config: { + baseUrl: 'https://update.server.com', + username: 'admin', + password: process.env.PASSWORD // string + } + } + ] +}; +``` + +Configuration options are documented in [`PublisherERSConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_publisher\_electron\_release\_server.PublisherERSConfig.html). diff --git a/docs/config/publishers/gcs.md b/docs/config/publishers/gcs.md new file mode 100644 index 0000000000..6b71a45828 --- /dev/null +++ b/docs/config/publishers/gcs.md @@ -0,0 +1,63 @@ +--- +description: Publishing your Electron app artifacts to a Google Cloud Storage bucket. +--- + +# Google Cloud Storage + +:::info +This Publisher was added in Electron Forge **v7.1.0**. +::: + +The Google Cloud Storage target publishes all your artifacts to a [Google Cloud Storage bucket](https://cloud.google.com/storage/docs). + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-gcs +``` + +## Usage + +To use `@electron-forge/publisher-gcs`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-gcs', + config: { + storageOptions: { + // add additional Storage constructor parameters here + projectId: 'my-project-id' + }, + bucket: 'my-bucket', + folder: 'custom-folder-name', + public: true + } + } + ] +}; +``` + +Additional configuration options are documented in [`PublisherGCSConfig`](http://js.electronforge.io/interfaces/\_electron\_forge\_publisher\_gcs.PublisherGCSConfig.html). + +To pass options into the Google Cloud Storage SDK's [Storage constructor](https://cloud.google.com/nodejs/docs/reference/storage/latest/storage/storageoptions), use the `config.storageOptions` parameter. + +### Output location + +When executed, the Publisher will publish to your GCS bucket under the following key: + +```text +${config.folder || version}/${artifactName} +``` + +:::warning +If you run publish twice with the same version on the same platform, it is possible for your old artifacts to get overwritten in Storage. It is your responsibility to ensure that you don't overwrite your own releases. +::: + +### Authentication + +Under the hood, the Google Cloud Storage Publisher uses the `@google-cloud/storage` SDK and its associated authentication options. + +We recommend following [Google's authentication documentation for client libraries](https://cloud.google.com/docs/authentication/client-libraries#node.js) to get authentication configured. diff --git a/docs/config/publishers/github.md b/docs/config/publishers/github.md new file mode 100644 index 0000000000..0f14a475b7 --- /dev/null +++ b/docs/config/publishers/github.md @@ -0,0 +1,63 @@ +# GitHub + +The GitHub Publisher uploads your artifacts to GitHub Releases, which allows your users to download the files straight from your repository. If your repository is open-source, you can use [update.electronjs.org](https://github.com/electron/update.electronjs.org) to get a free hosted update service (see [Auto updating from GitHub](github.md#auto-updating-from-github) below). + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-github +``` + +## Usage + +To use `@electron-forge/publisher-github`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-github', + config: { + repository: { + owner: 'me', + name: 'awesome-thing' + }, + prerelease: true + } + } + ] +}; +``` + +Configuration options are documented in [`PublisherGitHubConfig`](https://js.electronforge.io/interfaces/_electron_forge_publisher_github.PublisherGitHubConfig.html). + +### Authentication + +We recommend using the `process.env.GITHUB_TOKEN` environment variable to authenticate the GitHub Publisher. This token requires write permissions to your repository's contents to create new releases. + +:::info +If you are publishing your app with GitHub Actions, the `GITHUB_TOKEN` secret is pre-populated in every workflow. You will need to grant the necessary permissions via the `permissions` field at the top level of your workflow configuration. + +```yaml +permissions: + contents: write +``` + +See the [Controlling permissions for GITHUB\_TOKEN](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token) documentation for more information. +::: + +### Uploading to GitHub Enterprise instances + +You can use this target to publish to GitHub Enterprise using the host configuration options of `octokitOptions`. Check out the configuration options linked above. + +### Auto updating from GitHub + +Updating from a GitHub release for a **public** repository is as simple as adding the [`update-electron-app`](https://github.com/electron/update-electron-app) module to your app's main process. + +```javascript title="main.js" +const { updateElectronApp } = require('update-electron-app'); +updateElectronApp(); // additional configuration options available +``` + +If your GitHub release is in a private repository, you should check our [Auto Update](../../advanced/auto-update.md) guide for alternative solutions. diff --git a/docs/config/publishers/index.md b/docs/config/publishers/index.md new file mode 100644 index 0000000000..85ebd22646 --- /dev/null +++ b/docs/config/publishers/index.md @@ -0,0 +1,22 @@ +# Publishers + +Publishers are Electron Forge's way of taking the artifacts generated by the [`make` command](../makers/index.mdx) and sending them to a service somewhere for you to distribute or [use as updates](../../advanced/auto-update.md). This could be your update server or an S3 bucket. + +Each publisher has to be configured in the `publishers` section of your Forge configuration with which platforms to run for and the publisher specific config. For example: + +```javascript title="forge.config.js" +module.exports = { + publishers: [ + { + name: '@electron-forge/publisher-s3', + platforms: ['darwin', 'linux'], + config: { + bucket: 'my-bucket', + folder: 'my/key/prefix' + } + } + ] +}; +``` + +Please note that all publishers default to publishing all platforms, so you only need to specify the `platforms` key if you don't want that default. diff --git a/docs/config/publishers/nucleus.md b/docs/config/publishers/nucleus.md new file mode 100644 index 0000000000..2e3950b2f4 --- /dev/null +++ b/docs/config/publishers/nucleus.md @@ -0,0 +1,32 @@ +# Nucleus + +The Nucleus target publishes all your artifacts to an instance of Nucleus Update Server, this update service supports all three platforms. Check out the README at [`atlassian/nucleus`](https://github.com/atlassian/nucleus) for more information on this project. + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-nucleus +``` + +## Usage + +To use `@electron-forge/publisher-nucleus`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-nucleus', + config: { + host: 'https://my-nucleus.mysite.com', + appId: 1, + channelId: 'abcdefg', + token: process.env.TOKEN // string + } + } + ] +}; +``` + +Configuration options are documented in [`PublisherNucleusConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_publisher\_nucleus.PublisherNucleusConfig.html). diff --git a/docs/config/publishers/s3.mdx b/docs/config/publishers/s3.mdx new file mode 100644 index 0000000000..1631b1e5e1 --- /dev/null +++ b/docs/config/publishers/s3.mdx @@ -0,0 +1,124 @@ +--- +description: How to publish your distributable Electron app artifacts to Amazon S3 +--- + +import StaticFileAutoUpdates from '../../_partials/static-file-auto-updates.mdx'; + +# S3 + +The S3 target publishes your Make artifacts to an Amazon S3 bucket. + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-s3 +``` + +## Usage + +To use `@electron-forge/publisher-s3`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-s3', + config: { + bucket: 'my-bucket', + public: true + } + } + ] +}; +``` + +Configuration options are documented in [`PublisherS3Config`](https://js.electronforge.io/interfaces/_electron_forge_publisher_s3.PublisherS3Config.html). + +### Authentication + +It is recommended to follow the [Amazon AWS guide](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html) and set either a shared credentials guide or the proper environment variables. However, if that is not possible, the publisher config allows the setting of the `accessKeyId` and `secretAccessKey` configuration options. + +### Key management + +By default, the S3 publisher will upload its objects to the `{prefix}/{platform}/{arch}/{name}` key, where: + +* `{prefix}` is the value of the `config.folder` option (defaults to the `"name"` field in your package.json). +* `{platform}` is the target platform for the artifact you are publishing. +* `{arch}` is the target architecture for the artifact you are publishing. +* `{name}` is the file name of the artifact you are publishing. + +:::warning +If you run the Publish command multiple times on the same platform for the same version (e.g. simultaneously publishing `ia32` and `x64` Windows artifacts), your uploads can get overwritten in the S3 bucket. + +To avoid this problem, you can use the `keyResolver` option to generate the S3 key programmatically. + +```javascript title="forge.config.js" +{ + name: '@electron-forge/publisher-s3', + config: { + // ... + keyResolver: (filename, platform, arch) => { + return `some-prefix/${platform}/${arch}/${filename}` + } + // ... + } +} +``` + +::: + +### Auto updating from S3 + +You can configure Electron's built-in [`autoUpdater`](https://www.electronjs.org/docs/latest/api/auto-updater) module to use the artifacts published by the S3 publisher. This is a two-step process: + +First, you must configure the [S3](s3.mdx) publisher to publish your files into an auto-updater compatible layout and use the [ZIP](../makers/zip.md) maker (macOS) and the [Squirrel.Windows](../makers/squirrel.windows.md) maker (Windows) to build your application. + +```javascript title="forge.config.js" +module.exports = { + // ... + makers: [ + { + name: '@electron-forge/maker-zip', + config: (arch) => ({ + // Note that we must provide this S3 URL here + // in order to support smooth version transitions + // especially when using a CDN to front your updates + macUpdateManifestBaseUrl: `https://my-bucket.s3.amazonaws.com/my-app-updates/darwin/${arch}` + }) + }, + { + name: '@electron-forge/maker-squirrel', + config: (arch) => ({ + // Note that we must provide this S3 URL here + // in order to generate delta updates + remoteReleases: `https://my-bucket.s3.amazonaws.com/my-app-updates/win32/${arch}` + }) + } + ], + publishers: [ + { + name: '@electron-forge/publisher-s3', + config: { + bucket: 'my-bucket', + public: true + } + } + ] +}; +``` + +With Forge configured correctly, the second step is to configure the `autoUpdater` module inside your app's main process. The simplest form is shown below but you might want to hook additional events to show UI to your user or ask them if they want to update your app right now. + +```javascript title="main.js" +const { updateElectronApp, UpdateSourceType } = require('update-electron-app'); + +updateElectronApp({ + updateSource: { + type: UpdateSourceType.StaticStorage, + baseUrl: `https://my-bucket.s3.amazonaws.com/my-app-updates/${process.platform}/${process.arch}` + } +}); +``` + + diff --git a/docs/config/publishers/snapcraft.md b/docs/config/publishers/snapcraft.md new file mode 100644 index 0000000000..c549ad2135 --- /dev/null +++ b/docs/config/publishers/snapcraft.md @@ -0,0 +1,33 @@ +# Snapcraft + +The Snapcraft target publishes your `.snap` artifacts to the [Snap Store](https://snapcraft.io/store). All configuration of your package is done via the [Snapcraft](../makers/snapcraft.md) maker. + +## Requirements + +You can only publish to the Snap Store on Linux systems with the [`snapcraft`](https://snapcraft.io/) package installed. + +## Installation + +```bash +npm install --save-dev @electron-forge/publisher-snapcraft +``` + +## Usage + +To use `@electron-forge/publisher-snapcraft`, add it to the `publishers` array in your [Forge configuration](../configuration.mdx): + +```javascript title="forge.config.js" +module.exports = { + // ... + publishers: [ + { + name: '@electron-forge/publisher-snapcraft', + config: { + release: '[latest/edge, insider/stable]' + } + } + ] +}; +``` + +Configuration options are documented in [`PublisherSnapConfig`](https://js.electronforge.io/interfaces/\_electron\_forge\_publisher\_snapcraft.PublisherSnapcraftConfig.html). diff --git a/docs/config/typescript-configuration.md b/docs/config/typescript-configuration.md new file mode 100644 index 0000000000..cebf89fd26 --- /dev/null +++ b/docs/config/typescript-configuration.md @@ -0,0 +1,87 @@ +--- +description: Set up your Forge configuration to use TypeScript +--- + +# TypeScript Setup + +## Installation + +As of [Forge v7.8.1](https://github.com/electron/forge/releases/tag/v7.8.1), Electron Forge loads `forge.config.ts` files without any additional configuration using [`jiti`](https://github.com/unjs/jiti). + +:::warning +For older versions, follow the [Alternate file syntaxes](typescript-configuration.md#alternate-file-syntaxes) section below with the [`ts-node`](https://github.com/TypeStrong/ts-node) package. +::: + +## Configuration file + +Forge's TypeScript format is functionally identical to `forge.config.js`. Types can be imported from the [`@electron-forge/shared-types`](https://www.npmjs.com/package/@electron-forge/shared-types) package. + +```typescript title="forge.config.ts" +import type { ForgeConfig } from '@electron-forge/shared-types'; + +const config: ForgeConfig = { + packagerConfig: { + asar: true, + osxSign: {} + }, + makers: [ + { + name: '@electron-forge/maker-squirrel', + platforms: ['win32'], + config: { + authors: "Electron contributors" + } + }, + { + name: '@electron-forge/maker-zip', + platforms: ['darwin'], + config: {} + }, + { + name: '@electron-forge/maker-deb', + platforms: ['linux'], + config: {} + }, + ] +}; + +export default config; +``` + +## Using module constructor syntax + +When using a TypeScript configuration file, you may want to have stronger type validation around the individual options for each Maker, Publisher, or Plugin. + +To achieve this, you can import each module's constructor, which accepts its config object as the first parameter and the list of target platforms as the second parameter. + +For example, the below configuration is equivalent to the `makers` array from the example above: + +```typescript title="forge.config.ts" +import type { ForgeConfig } from '@electron-forge/shared-types'; +import { MakerDeb } from '@electron-forge/maker-deb'; +import { MakerSquirrel } from '@electron-forge/maker-squirrel'; +import { MakerZIP } from '@electron-forge/maker-zip'; + +const config: ForgeConfig = { + makers: [ + new MakerSquirrel({ + authors: 'Electron contributors' + }, ['win32']), + new MakerZIP({}, ['darwin']), + new MakerDeb({}, ['linux']), + new MakerRpm({}, ['linux']), + ] +}; + +export default config; +``` + +## Alternate file syntaxes + +Forge also supports configuration files in other languages that transpile down to JavaScript as long as a module loader for that language is installed locally in your project's `devDependencies`. For example, installing `coffeescript` enables Forge to read from a `forge.config.ts` file. + +These configuration files follow the same format as `forge.config.js`. + +:::info +The transpiler module you use needs to be compatible with [`interpret`](https://github.com/gulpjs/interpret) to work. +::: diff --git a/docs/core-concepts/build-lifecycle.md b/docs/core-concepts/build-lifecycle.md new file mode 100644 index 0000000000..7b8f5e518a --- /dev/null +++ b/docs/core-concepts/build-lifecycle.md @@ -0,0 +1,101 @@ +--- +description: How Forge takes your app code from development to distribution. +--- + +# Build Lifecycle + +Once your app is ready to be released, Electron Forge can handle the rest to make sure it gets into your users' hands. The complete build flow for Electron Forge can be broken down into three smaller steps: + +Each one of these steps is a separate command exposed through Forge's `electron-forge` command line interface, and is usually mapped to a script in your package.json file. + +:::info +**Cascading build steps** + +Running each of these tasks will also run the previous ones in the sequence (i.e. running the `electron-forge publish` script will first run `package` and `make` as prerequisite steps). +::: + +```mermaid +graph TB + dev["fa:fa-folder-open development Electron app"] --> package + package["fa:fa-box Package"] -->|executable app bundle| make + make["fa:fa-compact-disc Make"] -->|installers or archives| publish + publish["fa:fa-upload Publish"] -->|uploaded to cloud storage for distribution| cloud["fa:fa-cloud Users"] + make -.->|depends on| package + publish -.->|depends on| make +``` + +## Step 1: Package + +:::info +For command usage, see the [Package](../cli.md#package) CLI command documentation. +::: + +In the Package step, Forge uses [Electron Packager](https://github.com/electron/electron-packager) to package your app. This means creating an executable bundle for a target operating system (e.g. `.app` on macOS or `.exe` on Windows). + +This step also performs a few supporting tasks: + +* Handles [code signing and notarization](../guides/code-signing/code-signing-macos.md) on macOS. +* Rebuilds native node add-ons for your app's Electron version. +* Handles [Custom App Icons](../guides/create-and-add-icons.md) on Windows and macOS. + +By default, running the Package step will only create a packaged application for your machine's platform and architecture. + +:::info +**On bundling app code** + +Note that Forge does _not_ perform any bundling of your app code for production in the Package step without additional configuration. + +If you need to perform any custom JavaScript build tasks (e.g. module bundling with Parcel or webpack) for either renderer or main process code, see the [Using lifecycle hooks](build-lifecycle.md#using-lifecycle-hooks) section below. +::: + +:::tip +After the Package step, your packaged application will be available in the `/out/` directory. +::: + +## Step 2: Make + +:::info +For command usage, see the [Make](../cli.md#make) CLI command documentation. +::: + +Forge's **Make** step takes the bundled executable output from the previous Package step and creates "**distributables**" from it. Distributables refer to any output format that you want to distribute to users, whether it be an OS-specific installer (e.g. `.dmg` or `.msi`) or a simple compressed archive (e.g. `.zip`) of the bundle. + +You can choose which distributables you want to build by adding [Makers](../config/makers/index.mdx) to your Forge config. + +By default, running the Make step will only run Makers targeting your machine's platform and architecture. + +:::tip +After the Make step, distributable archives or installers are generated for your packaged app in the `/out/make/` folder of your project. +::: + +## Step 3: Publish + +:::info +For command usage, see the [Publish](../cli.md#publish) CLI command documentation. +::: + +Forge's **Publish** step takes the distributable build artifacts from the Make step and uploads for distribution to your app's end users (e.g. to GitHub Releases or AWS S3 static storage). Publishing is an optional step in the Electron Forge pipeline, since the artifacts from the Make step are already in their final format. + +You can choose which platforms you want to target by adding [Publishers](../config/publishers/index.md) to your Forge config. + +:::tip +After the Publish step, your app distributables will be available to download by users. +::: + +## Using lifecycle hooks + +Your Electron application might have custom build needs that aren't handled with the most basic Forge pipeline described above. To solve this issue, Electron Forge exposes callback hooks at various points in the build process. + +These hooks can be used to implement custom logic that your application needs. For instance, you can perform actions between the Package and Make steps with the `premake` hook. + +:::info +For a full list of Forge hooks and usage examples, see the [Hooks](../config/hooks.md) documentation. +::: + +If you want to share a specific sequence of build hook logic, you can modularize your hook code into a **plugin** instead. This is how Forge's [Webpack Plugin](../config/plugins/webpack.mdx) works, for instance. For more details on authoring custom plugins, see the [Writing Plugins](../advanced/extending-electron-forge/writing-plugins.md) guide. + +## Cross-platform build systems + +By default, Electron Forge will only build your app for the operating system it's running on. Targeting a different operating system (e.g. building a Windows app from macOS) has many caveats. + +If you don't have access to Windows, macOS, and Linux machines, we highly recommend creating a build pipeline on a Continuous Integration platform that supports all these platforms (e.g. CircleCI or GitHub Actions). For an example of CI builds in action, see [Electron Fiddle's CircleCI pipeline](https://github.com/electron/fiddle/blob/main/.circleci/config.yml). diff --git a/docs/core-concepts/why-electron-forge.md b/docs/core-concepts/why-electron-forge.md new file mode 100644 index 0000000000..fad2766891 --- /dev/null +++ b/docs/core-concepts/why-electron-forge.md @@ -0,0 +1,36 @@ +--- +description: An overview of Forge and its role in shipping Electron apps. +--- + +# Why Electron Forge + +## Motivation + +Application packaging and distribution has always been handled outside of the core Electron framework. In Electron's early days as a part of the [Atom editor](https://atom.io/), it was common for app developers to prepare their application for distribution by manually editing the Electron binary. + +Since then, the Electron community has developed a rich ecosystem of tools to handle every task for Electron app distribution, including: + +* Application packaging (`electron-packager`) +* Code signing (e.g. `@electron/osx-sign`) +* Creating platform-specific installers (e.g. `electron-winstaller` or `electron-installer-dmg`). +* Native Node.js module rebuilding (`electron-rebuild`) +* Universal macOS builds (`@electron/universal`) + +Although these single-purpose packages are mature and production-ready, application developers need to understand what each one does and write their own scripts to glue the packages together into a build pipeline. This process requires research and iteration, and can be confusing for folks who are new to Electron. + +## Value proposition + +Electron Forge is an all-in-one solution that unifies this fractured ecosystem. With Forge, you can create a build pipeline that brings your app from development to distribution with minimal configuration. + +Forge is also built with advanced use cases in mind—you can add any build logic you need with custom plugins, makers or publishers. For more details, see the [Extending Electron Forge](../advanced/extending-electron-forge/index.md) section of the docs. + +## Forge vs. Builder + +Electron Forge can be considered an alternative to [Electron Builder](https://electron.build/), which fulfills the same use-case for application building and publishing. + +The key difference in philosophy between the two projects is that Electron Forge focuses on combining existing first-party tools into a single build pipeline, while Builder rewrites its own in-house logic for most build tasks. + +We believe there are two main advantages to using Forge: + +1. **Forge receives new features for application building as soon as they are supported in Electron** (e.g. [ASAR integrity](https://electronjs.org/docs/latest/tutorial/asar-integrity) or [universal macOS builds](https://github.com/electron/universal)). These features are built with first-party Electron tooling in mind, so Forge receives them as soon as they are released. +2. **Forge's multi-package architecture makes it easier to understand and extend.** Since Forge is made up of many smaller packages with clear responsibilities, it is easier to follow the flow of the code. Also, its extensible API design means that you can write your own build logic separate from the provided configuration options for advanced use cases. diff --git a/docs/guides/code-signing/code-signing-macos.md b/docs/guides/code-signing/code-signing-macos.md new file mode 100644 index 0000000000..4ef230a551 --- /dev/null +++ b/docs/guides/code-signing/code-signing-macos.md @@ -0,0 +1,224 @@ +--- +description: >- + Code signing is a security technology that you use to certify that an app was + created by you. +--- + +# Signing a macOS app + +On macOS, there are two layers of security technology for application distribution: **code signing** and **notarization**. + +* **Code Signing** is the act of certifying the identity of the app's author and ensuring it was not tampered with before distribution. +* **Notarization** is an extra verification step where the app is sent to Apple servers for an automated malware scan. + +:::info +From macOS 10.15 (Catalina) onwards, your application needs to be **both code signed and notarized** to run on a user's machine without disabling additional operating system security checks. + +The exception is for Mac App Store (MAS) apps, where notarization is not required because the MAS submission process involves a similar automated check. +::: + +## Prerequisites + +### Installing Xcode + +[Xcode](https://developer.apple.com/xcode/) is Apple's integrated development environment (IDE) for development on macOS, iOS, and other platforms. + +Although Electron does not integrate tightly with the IDE itself, Xcode is a helpful tool for installing code signing certificates (see next section) and is **required** for notarization. + +### Obtaining signing certificates + +Code signing certificates for macOS apps can only be obtained through Apple by purchasing a membership to the [Apple Developer Program](https://developer.apple.com/programs/). + +To sign Electron apps, you may require two separate certificates: + +* The **Developer ID Installer** certificate is for apps distributed to the Mac App Store. +* The **Developer ID Application** certificate is for apps distributed outside the Mac App Store. + +Once you have an Apple Developer Program membership, you first need to install them onto your machine. We recommend [loading them through Xcode](https://help.apple.com/xcode/mac/current/#/dev3a05256b8). + +:::tip +**Verifying your certificate is installed** + +Once you have installed your certificate, you can check available code signing certificates in your terminal using the following shell command: + +```shell +security find-identity -p codesigning -v +``` + +::: + +## Configuring Forge + +In Electron Forge, macOS apps are signed and notarized at the **Package** step by the `electron-packager` library. There is a separate option within your Forge `packagerConfig` for each one of these settings. + +### osxSign options + +:::info +Under the hood, Electron Forge uses the [`@electron/osx-sign`](https://github.com/electron/osx-sign) tool to sign your macOS application. +::: + +To enable code signing on macOS, ensure that `packagerConfig.osxSign` exists in your Forge configuration. + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: { + osxSign: {} // object must exist even if empty + } +}; +``` + +The `osxSign` config comes with defaults that work out of the box in most cases, so we recommend you start with an empty configuration object. + +For a full list of configuration options, see the [`OsxSignOptions`](https://js.electronforge.io/modules/\_electron\_forge\_shared\_types.InternalOptions.html#OsxSignOptions) type in the Forge API docs. For more detailed information on how to configure these options, see the [`@electron/osx-sign` documentation](https://github.com/electron/osx-sign). + +#### Customizing entitlements + +A common use case for modifying the default `osxSign` configuration is to customize its entitlements. In macOS, **entitlements** are privileges that grant apps certain capabilities (e.g. access to the camera, microphone, or USB devices). These are stored within the code signature in an app's executable file. + +By default, the `@electron/osx-sign` tool comes with a set of entitlements that should work on both MAS or direct distribution targets. See the complete set of default entitlement files [on GitHub](https://github.com/electron/osx-sign/tree/main/entitlements). + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + // ... + osxSign: { + optionsForFile: (filePath) => { + // Here, we keep it simple and return a single entitlements.plist file. + // You can use this callback to map different sets of entitlements + // to specific files in your packaged app. + return { + entitlements: 'path/to/entitlements.plist' + }; + } + } + } + // ... +}; +``` + +For further reading on entitlements, see the following pages in Apple developer documentation: + +* [Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) +* [Hardened Runtime](https://developer.apple.com/documentation/security/hardened\_runtime) + +### osxNotarize options + +:::info +Under the hood, Electron Forge uses the [`@electron/notarize`](https://github.com/electron/notarize) tool to notarize your macOS application. +::: + +The `notarytool` command has three authentication options, which are detailed below. Note that you will want to use a `forge.config.js` configuration so that you can load environment variables into your Forge config. + +:::danger +**Keep your authentication details private** + +You should never store authentication info in plaintext in your configuration. In the examples below, credentials are stored as environment variables and accessed via the Node.js [`process.env`](https://nodejs.org/dist/latest-v16.x/docs/api/process.html#processenv) object. +::: + +#### Option 1: Using an app-specific password + +You can generate an [app-specific password](https://support.apple.com/en-us/HT204397) from Apple to provide your credentials to `notarytool`. This password will need to be regenerated if you change your Apple ID password. + +There are two mandatory fields for `osxNotarize` if you are using this strategy: + +| Field | Type | Description | +| ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `appleId` | string | Apple ID associated with your Apple Developer account | +| `appleIdPassword` | string | App-specific password | +| `teamId` | string | The Apple Team ID you want to notarize under. You can find Team IDs for team you belong to by going to [`https://developer.apple.com/account/#/membership`](https://developer.apple.com/account/#/membership) | + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + // ... + osxNotarize: { + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_PASSWORD, + teamId: process.env.APPLE_TEAM_ID + } + } + // ... +}; +``` + +:::warning +Despite the name, `appleIdPassword` is **not** the password for your Apple ID account. +::: + +#### Option 2: Using an App Store Connect API key + +You can generate an App Store Connect API key to authenticate `notarytool` by going to the [App Store Connect access page](https://appstoreconnect.apple.com/access/integrations/api) and using the "Team Keys" tab. This API key will look something like `AuthKey_ABCD123456.p8` and can only be downloaded once. + +There are three mandatory fields for `osxNotarize` if you are using this strategy: + +| Field | Type | Description | +| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------ | +| `appleApiKey` | string | Filesystem path string to your API key file. | +| `appleApiKeyId` | string | 10-character alphanumeric ID string. In the previous `AuthKey_ABCD123456.p8` example, this would be `ABCD123456`. | +| `appleApiIssuer` | string | UUID that identifies the API key issuer. You will find this ID in the "Keys" tab where you generated your API key. | + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + // ... + osxNotarize: { + appleApiKey: process.env.APPLE_API_KEY, + appleApiKeyId: process.env.APPLE_API_KEY_ID, + appleApiIssuer: process.env.APPLE_API_ISSUER + } + } + // ... +}; +``` + +#### Option 3: Using a keychain + +Instead of providing environment variables to the Forge config passed to `notarytool`, you can choose to use a macOS [keychain](https://support.apple.com/en-ca/guide/keychain-access/welcome/mac) containing either set of credentials (either Option 1 or Option 2 above). + +You can do this directly in your terminal via the `notarytool store-credentials` command. For usage information, you can refer to the man page for `notarytool`: + +```bash +man notarytool +``` + +There are two available fields for `osxNotarize` if you are using this strategy: + +| Field | Type | Description | +| --------------------- | ------ | ------------------------------------------------------------------------------- | +| `keychainProfile` | string | Name of the keychain profile containing your notarization credentials. | +| `keychain` (optional) | string | Name of (or path to) the keychain containing the profile with your credentials. | + +Note that if you use `notarytool store-credentials`, the `keychain` parameter can be auto-detected. + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + // ... + osxNotarize: { + keychainProfile: 'my-keychain-profile' + } + } + // ... +}; +``` + +### Example configuration + +Below is a minimal Forge configuration for `osxSign` and `osxNotarize`. + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: { + osxSign: {}, + osxNotarize: { + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_PASSWORD, + teamId: process.env.APPLE_TEAM_ID + } + } +}; +``` diff --git a/docs/guides/code-signing/code-signing-windows.mdx b/docs/guides/code-signing/code-signing-windows.mdx new file mode 100644 index 0000000000..03b9e3a4c7 --- /dev/null +++ b/docs/guides/code-signing/code-signing-windows.mdx @@ -0,0 +1,180 @@ +--- +description: >- + Code signing is a security technology that you use to certify that an app was + created by you. +--- + +# Signing a Windows app + +## Using traditional certificates + +:::warning +Starting June 1, 2023 at 00:00 UTC, private keys for code signing certificates need to be stored on a hardware storage module compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent.\ +\ +In practice, this means that software-based OV certificates used in the steps below will no longer be available for purchase. For instructions on how to sign applications with newer token-based certificates, consult your Certificate Authority's documentation. +::: + +### Prerequisites + +#### Installing Visual Studio + +On Windows, apps are signed using [Sign Tool](https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe), which is included in Visual Studio. Install Visual Studio to get the signing utility (the free [Community Edition](https://visualstudio.microsoft.com/vs/community/) is enough). + +#### Acquiring a certificate + +You can get a [Windows Authenticode](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode) code signing certificate from many vendors. Prices vary, so it may be worth your time to shop around. Popular vendors include: + +* [digicert](https://www.digicert.com/dc/code-signing/microsoft-authenticode.htm) +* [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing) +* Amongst others, please shop around to find one that suits your needs! 😄 + +:::danger +**Keep your certificate password private** + +Your certificate password should be a **secret**. Do not share it publicly or commit it to your source code. +::: + +### Configuring Electron Forge + +On Windows, Electron apps are signed on the installer level at the **Make** step. + +Once you have a Personal Information Exchange (`.pfx`) file for your certificate, you can sign [Squirrel.Windows](../../config/makers/squirrel.windows.md) and [MSI](../../config/makers/wix-msi.md) installers in Electron Forge with the `certificateFile` and `certificatePassword` fields in their respective configuration objects. + +For example, if you are creating a Squirrel.Windows installer: + +```javascript title="forge.config.js" +module.exports = { + packagerConfig: {}, + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: { + certificateFile: './cert.pfx', + certificatePassword: process.env.CERTIFICATE_PASSWORD + } + } + ] +}; +``` + +## Using Azure Trusted Signing + +[Azure Trusted Signing](https://azure.microsoft.com/en-us/products/trusted-signing) is Microsoft's modern cloud-based alternative to EV certificates. It is the cheapest option for code signing on Windows, and it gets rid of SmartScreen warnings. + +As of October 2025, Azure Trusted Signing is available to US and Canada-based organizations with 3+ years of verifiable business history and to individual developers in the US and Canada. Microsoft is looking to make the program more widely available. If you're reading this at a later point, it could make sense to check if the eligibility criteria have changed. + +### Prerequisites {/* #prerequisites-trusted-signing */} + +First, create an Azure account and set up Azure Trusted Signing in your account as described [here](https://melatonin.dev/blog/code-signing-on-windows-with-azure-trusted-signing/). + +Then install the dependencies for local code signing as described [here](https://melatonin.dev/blog/code-signing-on-windows-with-azure-trusted-signing/#step-8-signing-locally). Also create the required `metadata.json` file in an arbitrary location on your computer. + +### Configuring Electron Forge {/* #configuring-forge-trusted-signing */} + +#### Installing npm dependencies + +In your project directory, do the following: + +1. Install the `dotenv-cli` package: `npm i -D dotenv-cli` +2. Update `@electron/windows-sign` to version 1.2.2 or later: `npm update @electron/windows-sign` + +#### Creating the `.env.trustedsigning` file + +Create a file `.env.trustedsigning` in your project root with the following content: + +```text title=".env.trustedsigning" +AZURE_CLIENT_ID='xxx' +AZURE_CLIENT_SECRET='xxx' +AZURE_TENANT_ID='xxx' +AZURE_METADATA_JSON='C:\path\to\metadata.json' +AZURE_CODE_SIGNING_DLIB='C:\path\to\bin\x64\Azure.CodeSigning.Dlib.dll' +SIGNTOOL_PATH='C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe' +``` + +Fill in the credentials for your Azure App Registration user into the first three variables. + +Adjust the other variables to be the absolute paths to the `metadata.json`, `Azure.CodeSigning.Dlib.dll` and `signtool.exe` files that you created or installed as part of the prerequisites. + +:::warning +Ensure that none of the paths have spaces in them. Otherwise, signing will fail. (`@electron/windows-sign` issue [#45](https://github.com/electron/windows-sign/issues/45) currently prevents quoting of paths with spaces.) +::: + +#### Adjusting your `.gitignore` + +Add `.env.trustedsigning` to your `.gitignore` file. You should never commit login credentials to version control. + +In addition, add `electron-windows-sign.log` to `.gitignore`. This file will be created automatically during the signing process. + +```gitignore title=".gitignore" +.env.trustedsigning +electron-windows-sign.log +``` + +#### Creating the `windowsSign.ts` file + +Create a file `windowsSign.ts` in your project root with the following content: + +```typescript title="windowsSign.ts" +import type { WindowsSignOptions } from "@electron/packager"; +import type { HASHES } from "@electron/windows-sign/dist/esm/types"; + +export const windowsSign: WindowsSignOptions = { + ...(process.env.SIGNTOOL_PATH + ? { signToolPath: process.env.SIGNTOOL_PATH } + : {}), + signWithParams: `/v /debug /dlib ${process.env.AZURE_CODE_SIGNING_DLIB} /dmdf ${process.env.AZURE_METADATA_JSON}`, + timestampServer: "http://timestamp.acs.microsoft.com", + hashes: ["sha256" as HASHES], +}; +``` + +:::info +If you are using JavaScript for your configuration instead of TypeScript, adjust the file accordingly. Name the file `windowsSign.js` and remove the type information. +::: + +Some notes: + +We specify the `/v` and `/debug` parameters even though they aren't technically required. This ensures that warnings are logged if timestamping fails. + +:::info +Set the environment variable `DEBUG` to `electron-windows-sign` to get verbose debug output while signing. +::: + +#### Adjusting your `forge.config.ts` + +In your `forge.config.ts`, add the following: + +```typescript title="forge.config.ts" +// Add import: +import { windowsSign } from "./windowsSign"; + +const config: ForgeConfig = { + packagerConfig: { + // Add this line: + windowsSign, + }, + makers: [ + new MakerSquirrel({ + // Add the following two lines: + // @ts-expect-error - incorrect types exported by MakerSquirrel + windowsSign, + }), + ], +}; +``` + +#### Updating your npm scripts + +{/* markdownlint-disable-next-line MD038 */} +When you call scripts such as `electron-forge make` or `electron-forge publish`, you will now have to prefix them with `dotenv -e .env.trustedsigning -- `. This loads the environment variables from the `.env.trustedsigning` file. + +For example, your npm scripts in your `package.json` might then look like this: + +```json title="package.json" +{ + "scripts": { + "make": "dotenv -e .env.trustedsigning -- electron-forge make", + "publish": "dotenv -e .env.trustedsigning -- electron-forge publish" + } +} +``` diff --git a/docs/guides/code-signing/index.md b/docs/guides/code-signing/index.md new file mode 100644 index 0000000000..6c871175dc --- /dev/null +++ b/docs/guides/code-signing/index.md @@ -0,0 +1,12 @@ +--- +description: Configure Code Signing with Electron Forge +--- + +# Code Signing + +Code signing is a security technology that you use to certify that an app was created by you. If you are building an Electron app that you intend to package and distribute, it should be code signed so it does not trigger any operating system security checks. This step is _highly recommended_ if you want to distribute your app publicly as code signing is an important security concept on both macOS and Windows. + +This guide is split into two separate pages because there is a separate process for each platform: + +- [Signing a macOS app](code-signing-macos.md) +- [Signing a Windows app](code-signing-windows.mdx) diff --git a/docs/guides/create-and-add-icons.md b/docs/guides/create-and-add-icons.md new file mode 100644 index 0000000000..bd1a899ff0 --- /dev/null +++ b/docs/guides/create-and-add-icons.md @@ -0,0 +1,206 @@ +--- +description: >- + The purpose of this guide is to walk through the process of generating and + setting an app icon, as well as setting installer and setup icons. +--- + +# Custom App Icons + +## Generating an icon + +Generating your icon can be done using various conversion tools found online. It is recommended to start with a 1024x1024px image before converting it to the formats required by each platform. + +### Supporting higher pixel densities + +On platforms that have high-DPI support (such as Apple Retina displays), you can append `@2x` after the image's base filename to mark it as a high resolution image. For example, if `icon.png` is a normal image with standard resolution, then `icon@2x.png` will be treated as a high resolution image that has double the DPI intensity. + +If you want to support different displays with different DPI densities at the same time, you can put images with different sizes in the same folder and use the filename without DPI suffixes. For example: + +```text +images/ +├── icon.png +├── icon@2x.png +└── icon@3x.png +``` + +:::info +The following suffixes for DPI are also supported: + +@1x, @1.25x, @1.33x, @1.4x, @1.5x, @1.8x, @2x, @2.5x, @3x, @4x, and @5x. +::: + +### Supported formats + +The recommended file formats and icon sizes for each platform are as follows: + +| Operating system | Format | Size / notes | +| ---------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| macOS | `.icns` (or `.icon`) | Use a 1024x1024 source image. Keep an `.icns` file for compatibility, and add an Icon Composer `.icon` file for macOS 26+. | +| Windows | `.ico` | 256x256 pixels | +| Linux | `.png` | 512x512 pixels | + +:::warning +On Windows, ensure that your `.ico` file is exported from an image editor that supports the format (such as [GIMP](https://www.gimp.org/)). Renaming a `.png` file into `.ico` will result in a `Fatal error: Unable to set icon` error. +::: + +:::info +`@electron/packager` supports macOS Icon Composer files as of [`@electron/packager` v18.4.0](https://github.com/electron/packager/releases/tag/v18.4.0). To support both macOS 26+ and earlier releases, provide both an `.icns` file and a `.icon` file. +::: + +## Setting the app icon + +### Windows + +Configuring the path to your icon can be done in your Forge configuration. + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + icon: '/path/to/icon' // no file extension required + } + // ... +}; +``` + +:::tip +When you provide a single icon path, Electron Packager will automatically add the correct platform extension, so appending `.ico` here is not required. +::: + +After the config has been updated, build your project to generate your executable with the Make command. + +### macOS + +If you only need the traditional macOS icon format, you can continue to provide a single `icon` path in `packagerConfig`: + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + icon: '/path/to/icon' // .icns will be inferred + } + // ... +}; +``` + +If you need one configuration that supports both macOS 26+ and earlier macOS releases, provide both an `.icns` file and an `.icon` file: + +```javascript title="forge.config.js" +module.exports = { + // ... + packagerConfig: { + icon: [ + '/path/to/icon.icns', + '/path/to/icon.icon' + ] + } + // ... +}; +``` + +Electron Packager will use the `.icns` file on macOS versions earlier than 26, and the `.icon` file on macOS 26 and later. + +:::warning +Packaging an `.icon` file currently requires macOS 26 or later and Xcode 26 or later because Electron Packager uses Apple's `actool` tool to compile the Icon Composer asset. +::: + +:::info +When you provide multiple macOS icon files, include the file extensions explicitly so Packager can distinguish the `.icns` and `.icon` inputs. +::: + +After the config has been updated, build your project to generate your executable with the Make command. + +### Linux + +Configuring the path to your icon must be done in both package.json as well as in Electron's main process. + +```javascript title="forge.config.js" {14} +module.exports = { + // ... + makers: [ + { + name: '@electron-forge/maker-deb', + config: { + options: { + icon: '/path/to/icon.png' + } + } + } + ] + // ... +}; +``` + +The icon must be additionally loaded when instantiating your [BrowserWindow](https://www.electronjs.org/docs/latest/api/browser-window#new-browserwindowoptions). + +```javascript title="main.js (Main Process)" {5} +const { BrowserWindow } = require('electron'); + +const win = new BrowserWindow({ + // ... + icon: '/path/to/icon.png' +}); +``` + +Once the path to the icon has been configured, build your project to generate your executable with `npm run make`. + +## Configuring installer icons + +Installers usually have icons! Don't forget to configure those in the Maker-specific config within the [Makers section of your Forge configuration](https://www.electronforge.io/config/makers). + +Here is an example of how that can be done: + +```javascript +// forge.config.js +module.exports = { + // ... + makers: [ + { + name: '@electron-forge/maker-squirrel', + config: { + // An URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). + iconUrl: 'https://url/to/icon.ico', + // The ICO file to use as the icon for the generated Setup.exe + setupIcon: '/path/to/icon.ico' + } + }, + { + // Path to a single image that will act as icon for the application + name: '@electron-forge/maker-deb', + config: { + options: { + icon: '/path/to/icon.png' + } + } + }, + { + // Path to the icon to use for the app in the DMG window + name: '@electron-forge/maker-dmg', + config: { + icon: '/path/to/icon.icns' + } + }, + { + name: '@electron-forge/maker-wix', + config: { + icon: '/path/to/icon.ico' + } + } + ] + // ... +}; +``` + +Once again, once you are done configuring your icons, don't forget to build your project with the Make command. + +## Troubleshooting + +Operating systems have an icon cache. Resetting the cache is recommended if the icon is not updated or still uses the default one. + +### Refreshing the icon cache (Windows) + +Windows caches all application icons in a hidden Icon Cache Database. If your Electron app's icon is not showing up, you may need to rebuild this cache. To invalidate the cache, use the system `ie4uinit.exe` utility: + +```sh +ie4uinit.exe -show +``` diff --git a/docs/guides/developing-with-wsl.md b/docs/guides/developing-with-wsl.md new file mode 100644 index 0000000000..090bfc4f9e --- /dev/null +++ b/docs/guides/developing-with-wsl.md @@ -0,0 +1,36 @@ +--- +description: 'Developing with Windows Subsystem for Linux, on Windows' +--- + +# Developing with WSL + +If you're using [Windows Subsystem for Linux \(WSL\)](https://docs.microsoft.com/en-us/windows/wsl/), there are some quirks to running Electron apps. Since you can run a mostly complete Linux distribution inside it, it justifiably declares itself as Linux when you're inside of it. However, as of February 2021 there is no support for running graphical apps compiled for Linux out of the box. Simply trying to run an Electron app in development that you've installed dependencies in WSL will try and fail to find an X11 server, and thus not launch. + +Fortunately, one of the features of WSL is that you can run Windows executables from a WSL terminal seamlessly. The caveat is that you'll need to reinstall Electron in order to pick up the prebuilt binaries for Windows instead of Linux. Inside a WSL terminal, assuming that you've installed Node.js for Linux, you can run: + +```bash +# If node_modules exists already that was installed in WSL: + +rm -r node_modules + +# then: + +npm install --platform=win32 + +# or: + +npm_config_platform=win32 npm install + +``` + +Then, start the Electron app in development mode as usual via `npm start`. + +For package/make/publish, you'll still need to specify the platform if you want to generate bundles/distributables for Windows. + +```bash +npm run make -- --platform=win32 +``` + +:::warning +Some of the dependencies of Electron Forge don't quite work with WSL, as they don't detect that they're running in WSL _\(instead of Linux\)_ and thus tries to run certain tooling provided as Windows executables in... Wine. We are actively working on making the dependent tooling WSL-aware. The workaround is to run package/make/publish outside of WSL. +::: diff --git a/docs/guides/framework-integration/index.md b/docs/guides/framework-integration/index.md new file mode 100644 index 0000000000..2b49b71db8 --- /dev/null +++ b/docs/guides/framework-integration/index.md @@ -0,0 +1,7 @@ +--- +description: Use various frontend frameworks with Electron Forge +--- + +# Framework Integration + +Since Electron uses Chromium under the hood, there's nothing particularly different about integrating your frontend framework of choice with Electron Forge as opposed to a web application, especially considering Forge's first-party Webpack support. diff --git a/docs/guides/framework-integration/parcel.md b/docs/guides/framework-integration/parcel.md new file mode 100644 index 0000000000..c2b2c2a837 --- /dev/null +++ b/docs/guides/framework-integration/parcel.md @@ -0,0 +1,10 @@ +--- +description: How to create an Electron app with the Parcel bundler and Electron Forge +hidden: true +--- + +# Parcel + +Unfortunately, Parcel 1 does not have the necessary integration points or native module support to be able to have its own plugin. However, if you wish to do the integration yourself, [Electron Fiddle](https://electronjs.org/fiddle) can be used [as a model for how to use Electron Forge in conjunction with Parcel 1](https://github.com/electron/fiddle/blob/v0.19.0/tools/parcel-build.js). + +We hope to work with the Parcel developers in the future as they work on [Electron support in Parcel 2](https://github.com/parcel-bundler/parcel/issues/2492). diff --git a/docs/guides/framework-integration/react-with-typescript.mdx b/docs/guides/framework-integration/react-with-typescript.mdx new file mode 100644 index 0000000000..2c1faf496a --- /dev/null +++ b/docs/guides/framework-integration/react-with-typescript.mdx @@ -0,0 +1,56 @@ +--- +description: How to create an Electron app with React, TypeScript, and Electron Forge +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# React with TypeScript + +Adding React support to the TypeScript + Webpack template is fairly straightforward and doesn't require a complicated boilerplate to get started. + +:::info +The following guide has been tested with React 18, TypeScript 4.3, and Webpack 5. +::: + +### Create the app and setup the TypeScript config + +Create the app with the [TypeScript + Webpack template](../../templates/typescript-+-webpack-template.md), then edit the newly created `tsconfig.json` to add the key-value entry [`"jsx": "react-jsx"`](https://www.typescriptlang.org/tsconfig#jsx) to the `"compilerOptions"` section. + +### Add the React dependencies + +Add the basic React packages to your `dependencies` and the corresponding types to your `devDependencies`: + +```bash +npm install --save react react-dom +npm install --save-dev @types/react @types/react-dom +``` + +### Integrate React code + +You should now be able to start writing and using React components in your Electron app. The following is a very minimal example of how to start to add React code: + + + + +```tsx +import React from 'react'; +import { createRoot } from 'react-dom/client'; + +const root = createRoot(document.body); +root.render(

Hello from React!

); +``` + +
+ + + +```typescript +// Add this to the end of the existing file +import './app'; +``` + + +
+ +For more about React, see [their documentation](https://react.dev/learn/add-react-to-an-existing-project). diff --git a/docs/guides/framework-integration/react.mdx b/docs/guides/framework-integration/react.mdx new file mode 100644 index 0000000000..bd25ad3a98 --- /dev/null +++ b/docs/guides/framework-integration/react.mdx @@ -0,0 +1,78 @@ +--- +description: How to create an Electron app with React and Electron Forge +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# React + +Adding React support to the Webpack template doesn't require a complicated boilerplate to get started. + +:::info +The following guide has been tested with React 18, Babel 7, and Webpack 5. +::: + +### Create the app and setup the Webpack config + +Create the app with the [Webpack template](../../templates/webpack-template.md). Add the following packages to your `devDependencies` so that JSX and other React features can be used properly: + +```bash +npm install --save-dev @babel/core @babel/preset-react babel-loader +``` + +Set up the [`babel-loader`](https://www.npmjs.com/package/babel-loader)module with the [React preset](https://babeljs.io/docs/en/babel-preset-react) in `webpack.rules.js`: + +```javascript title="webpack.rules.js" +module.exports = [ + // ... existing loader config ... + { + test: /\.jsx?$/, + use: { + loader: 'babel-loader', + options: { + exclude: /node_modules/, + presets: ['@babel/preset-react'] + } + } + } + // ... existing loader config ... +]; +``` + +### Add the React dependencies + +Add the basic React packages to your `dependencies`: + +```bash +npm install --save react react-dom +``` + +### Integrate React code + +You should now be able to start writing and using React components in your Electron app. The following is a very minimal example of how to start to add React code: + + + + +```jsx +import * as React from 'react'; +import { createRoot } from 'react-dom/client'; + +const root = createRoot(document.body); +root.render(

Hello from React!

); +``` + +
+ + + +```javascript +// Add this to the end of the existing file +import './app.jsx'; +``` + + +
+ +For more about React, see their [documentation](https://react.dev/learn/add-react-to-an-existing-project). diff --git a/docs/guides/framework-integration/vue-3.mdx b/docs/guides/framework-integration/vue-3.mdx new file mode 100644 index 0000000000..44f49ba3bf --- /dev/null +++ b/docs/guides/framework-integration/vue-3.mdx @@ -0,0 +1,105 @@ +--- +description: How to create an Electron app with Vue and Electron Forge +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Vue 3 + +Vue 3 can be added to Electron Forge's Vite template with a few setup steps. + +:::info + +The following guide has been tested with Vue 3 and Vite 4. + +::: + +## Setting up the app + +Create an Electron app using Electron Forge's [Vite](../../templates/vite.md) template. + +```bash +npx create-electron-app@latest my-vue-app --template=vite +``` + +## Adding dependencies + +Add the `vue` npm package to your `dependencies` and the `@vitejs/plugin-vue` package to your `devDependencies`: + +```bash +npm install vue +npm install --save-dev @vitejs/plugin-vue +``` + +## Integrating Vue 3 code + +You should now be able to start using Vue components in your Electron app. The following is a very minimal example of how to start to add Vue 3 code: + + + + +Replace the contents of `src/index.html` with a `
` element with the `#app` id attribute. + +```html + + + + + Hello World! + + +
+ + + +``` + + + + + +Add the contents from the template back to `src/App.vue`. + +```vue + + + +``` + + + + + +Mount `App.vue` into the DOM with Vue's `createApp` API. + +```javascript +import { createApp } from 'vue'; +import App from './App.vue'; + +createApp(App).mount('#app'); +``` + + + + + +Configure the Vue plugin for Vite.js. + +```javascript +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +// https://vitejs.dev/config +export default defineConfig({ + plugins: [vue()] +}); +``` + + + diff --git a/docs/import-existing-project.md b/docs/import-existing-project.md new file mode 100644 index 0000000000..c3fe0b7ccb --- /dev/null +++ b/docs/import-existing-project.md @@ -0,0 +1,155 @@ +--- +description: Import an existing Electron project to use Electron Forge. +layout: + title: + visible: true + description: + visible: true + tableOfContents: + visible: true + outline: + visible: true + pagination: + visible: true +--- + +# Importing an Existing Project + +If you already have an Electron app and want to try out Electron Forge, you can either use Forge's `import` script or manually configure Forge yourself. + +These steps will get you set up with a basic build pipeline that can create [Squirrel.Windows](config/makers/squirrel.windows.md) (Windows), [ZIP](config/makers/zip.md) (macOS), and [deb](config/makers/deb.md) (Linux) installers when running `electron-forge make`. + +## Using the import script + +Importing an existing Electron app into the Electron Forge workflow can be done automatically using Forge's `import` command. + +```shell +cd my-app +npm install --save-dev @electron-forge/cli +npm exec --package=@electron-forge/cli -c "electron-forge import" +``` + +This script will set up Forge to package your app and build installers for it. + +:::info +If you're already using other Electron tooling, it will try to automatically migrate the settings as much as possible, but some of it may need to be migrated manually. +::: + +## Setting up Forge manually + +If the import script does not work for some reason, you can also install Forge manually. To get identical behavior to the script, follow the steps below. + +### Installing dependencies + +First, install Forge's CLI and the target Makers as devDependencies in your project. + +```bash +cd my-app +npm install --save-dev @electron-forge/cli @electron-forge/maker-squirrel @electron-forge/maker-deb @electron-forge/maker-zip +``` + +### Configuring package.json + +To start using Forge, add a few command scripts to your package.json file: + +```json title="package.json" +{ + // ... + "scripts": { + "start": "electron-forge start", + "package": "electron-forge package", + "make": "electron-forge make", + "publish": "electron-forge publish" + } + // ... +} +``` + +Then, set up your Forge [Overview](config/configuration.mdx) in the `config.forge` field in package.json. + +```json title="package.json" +{ + // ... + "config": { + "forge": { + "packagerConfig": {}, + "makers": [ + { + "name": "@electron-forge/maker-squirrel", + "config": { + "name": "electron_quick_start" + } + }, + { + "name": "@electron-forge/maker-zip", + "platforms": [ + "darwin" + ] + }, + { + "name": "@electron-forge/maker-deb", + "config": {} + }, + { + "name": "@electron-forge/maker-rpm", + "config": {} + } + ] + } + } + // ... +} +``` + +In the above object, we configure each Maker that we installed into the `makers` array. We also create an empty `packagerConfig` object that you should edit to your app's packaging needs. + +### Adding Squirrel.Windows boilerplate + +When distributing a [Squirrel.Windows](config/makers/squirrel.windows.md) app, we recommend installing [`electron-squirrel-startup`](https://github.com/mongodb-js/electron-squirrel-startup) as a runtime dependency to handle Squirrel events. + +```bash +cd my-app +npm install electron-squirrel-startup +``` + +Then, add the following snippet as early as possible in the main process execution (before the `app.ready` event). + +```javascript title="main.js" +if (require('electron-squirrel-startup')) app.quit(); +``` + +### Optional: publishing your app + +You can also configure Forge to upload your release artifacts to a self-hosted release server such as [Electron Release Server](config/publishers/electron-release-server.md) or [Nucleus](config/publishers/nucleus.md), or cloud storage providers such as [S3](config/publishers/s3.mdx). + +For example, for the S3 Publisher: + +```bash +cd my-app +npm install --save-dev @electron-forge/publisher-s3 +``` + +```json title="package.json" +{ + // ... + "config": { + "forge": { + "packagerConfig": {}, + "makers": [ /* ... */], + "publishers": [ + { + "name": "@electron-forge/publisher-s3", + "platforms": ["darwin", "linux"], + "config": { + "bucket": "my-bucket", + "folder": "my/key/prefix" + } + } + ] + } + } + // ... +} +``` + +See the [Publishers](config/publishers/index.md) documentation for more information. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..d439b5696b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,100 @@ +--- +description: Quickly scaffold an Electron project with a full build pipeline +--- + +# Getting Started + +Electron Forge is an all-in-one tool for packaging and distributing Electron applications. It combines many single-purpose packages to create a full build pipeline that works out of the box, complete with code signing, installers, and artifact publishing. For advanced workflows, custom build logic can be added in the Forge lifecycle through its [Plugin API](config/plugins/index.md). Custom build and storage targets can be handled by creating your own [Makers](config/makers/index.mdx) and [Publishers](config/publishers/index.md). + +## Prerequisites + +* [Node.js](https://nodejs.org/) ≥ v16.4.0 +* [Git](https://git-scm.com/) +* A JavaScript package manager: + * [npm](https://www.npmjs.com/) + * [Yarn](https://yarnpkg.com/) + * [pnpm](https://pnpm.io/) (as of Forge v7.7.0) + +:::warning +**Packaging requires `node_modules` to be on disk** + +When packaging your Electron app, Forge crawls your project's `node_modules` folder to collect dependencies to bundle. Its module resolution algorithm is naive and doesn't take into account symlinked dependencies nor Yarn's Plug'n'Play (PnP) format. + +* If you are using Yarn >=2, please use the `nodeLinker: node-modules` install mode. +* If you are using pnpm, please set `node-linker=hoisted` in your project's `.npmrc` configuration. + +::: + +## Creating a new app + +To get started with Electron Forge, we first need to initialize a new project with `create-electron-app`. This script is a convenient wrapper around Forge's [Init](cli.md#init) command. + +```bash +npx create-electron-app@latest my-app +``` + +### Using templates + +Forge's initialization scripts can add additional template code with the `--template=[template-name]` flag. + +```bash +npx create-electron-app@latest my-app --template=webpack +``` + +There are currently four first-party templates: + +* `webpack` +* `webpack-typescript` +* `vite` +* `vite-typescript` + +All of these templates are built around plugins that bundle your JavaScript code for production and includes a dev server to provide a better developer experience. + +:::info +We highly recommend using these templates when initializing your app to take advantage of modern front-end JavaScript tooling. +::: + +To learn more about authoring your own templates for Electron Forge, check out the [Writing Templates](advanced/extending-electron-forge/writing-templates.md) guide! + +## Starting your app + +You should now have a directory called `my-app` with all the files you need for a basic Electron app. + +```bash +cd my-app +npm start +``` + +## Building distributables + +So you've got an **amazing** application there, and you want to package it all up and share it with the world. If you run the `make` script, Electron Forge will generate you platform specific distributables for you to share with everyone. For more information on what kind of distributables you can make, check out the [Makers](config/makers/index.mdx) documentation. + +```bash +npm run make +``` + +## Publishing your app + +Now you have distributables that you can share with your users. If you run the `publish` script, Electron Forge will then publish the platform-specific distributables for you, using the publishing method of your choice. For example, if you want to publish your assets to GitHub, you can install the GitHub publisher dependency using: + +```bash +npm install --save-dev @electron-forge/publisher-github +``` + +Once you have [configured the publisher according to the documentation](config/publishers/github.md), run the following command to upload your distributables: + +```bash +npm run publish +``` + +For more information on what publishers we currently support, check out the [Publishers](config/publishers/index.md) documentation. + +## Advanced Usage + +Once you've got a basic app starting, building and publishing, it's time to add your custom configuration, which can be done in the `forge.config.js` file. Configuration options are specified in the [Configuration Docs](https://www.electronforge.io/configuration). + +You can also check out the documentation on some of our more advanced features like: + +* [Adding plugins](config/plugins/index.md) +* [Debugging your app](advanced/debugging.md) +* [Writing your own makers, publishers and plugins](advanced/extending-electron-forge/index.md) diff --git a/docs/sidebars.ts b/docs/sidebars.ts new file mode 100644 index 0000000000..61a9e0a96e --- /dev/null +++ b/docs/sidebars.ts @@ -0,0 +1,148 @@ +import type { SidebarsConfig } from '@docusaurus/plugin-content-docs'; + +const sidebars: SidebarsConfig = { + docs: [ + 'index', + 'import-existing-project', + 'cli', + { + type: 'category', + label: 'Core Concepts', + collapsible: false, + items: [ + { + type: 'doc', + id: 'core-concepts/why-electron-forge', + label: 'Why Electron Forge?', + }, + 'core-concepts/build-lifecycle', + ], + }, + { + type: 'category', + label: 'Configuration', + collapsible: false, + items: [ + { + type: 'doc', + id: 'config/configuration', + label: 'Configuration Overview', + }, + 'config/typescript-configuration', + { + type: 'category', + label: 'Plugins', + link: { type: 'doc', id: 'config/plugins/index' }, + items: [ + 'config/plugins/webpack', + 'config/plugins/vite', + 'config/plugins/electronegativity', + 'config/plugins/auto-unpack-natives', + 'config/plugins/local-electron', + 'config/plugins/fuses', + ], + }, + { + type: 'category', + label: 'Makers', + link: { type: 'doc', id: 'config/makers/index' }, + items: [ + 'config/makers/appx', + 'config/makers/deb', + 'config/makers/dmg', + 'config/makers/flatpak', + 'config/makers/msix', + 'config/makers/pkg', + 'config/makers/rpm', + 'config/makers/snapcraft', + 'config/makers/squirrel.windows', + 'config/makers/wix-msi', + 'config/makers/zip', + ], + }, + { + type: 'category', + label: 'Publishers', + link: { type: 'doc', id: 'config/publishers/index' }, + items: [ + 'config/publishers/bitbucket', + 'config/publishers/electron-release-server', + 'config/publishers/github', + 'config/publishers/gcs', + 'config/publishers/nucleus', + 'config/publishers/s3', + 'config/publishers/snapcraft', + ], + }, + 'config/hooks', + ], + }, + { + type: 'category', + label: 'Built-in Templates', + collapsible: false, + items: [ + 'templates/webpack-template', + 'templates/typescript-+-webpack-template', + 'templates/vite', + 'templates/vite-+-typescript', + ], + }, + { + type: 'category', + label: 'Guides', + collapsible: false, + items: [ + { + type: 'category', + label: 'Code Signing', + link: { type: 'doc', id: 'guides/code-signing/index' }, + items: [ + 'guides/code-signing/code-signing-windows', + 'guides/code-signing/code-signing-macos', + ], + }, + 'guides/create-and-add-icons', + { + type: 'category', + label: 'Framework Integration', + link: { type: 'doc', id: 'guides/framework-integration/index' }, + items: [ + 'guides/framework-integration/parcel', + 'guides/framework-integration/react', + 'guides/framework-integration/react-with-typescript', + 'guides/framework-integration/vue-3', + ], + }, + 'guides/developing-with-wsl', + ], + }, + { + type: 'category', + label: 'Advanced', + collapsible: false, + items: [ + 'advanced/auto-update', + 'advanced/debugging', + { + type: 'category', + label: 'Extending Electron Forge', + link: { type: 'doc', id: 'advanced/extending-electron-forge/index' }, + items: [ + 'advanced/extending-electron-forge/writing-plugins', + 'advanced/extending-electron-forge/writing-templates', + 'advanced/extending-electron-forge/writing-makers', + 'advanced/extending-electron-forge/writing-publishers', + ], + }, + { + type: 'link', + label: 'API Docs', + href: 'https://js.electronforge.io/modules/_electron_forge_core.html', + }, + ], + }, + ], +}; + +export default sidebars; diff --git a/docs/static/img/Untitled-2022-08-26-1442 (2).png b/docs/static/img/Untitled-2022-08-26-1442 (2).png new file mode 100644 index 0000000000..4ee65b128a Binary files /dev/null and b/docs/static/img/Untitled-2022-08-26-1442 (2).png differ diff --git a/docs/static/img/Untitled-2022-08-26-1442.png b/docs/static/img/Untitled-2022-08-26-1442.png new file mode 100644 index 0000000000..e638aef734 Binary files /dev/null and b/docs/static/img/Untitled-2022-08-26-1442.png differ diff --git a/docs/static/img/Vitejs-logo.svg b/docs/static/img/Vitejs-logo.svg new file mode 100644 index 0000000000..de4aeddc12 --- /dev/null +++ b/docs/static/img/Vitejs-logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/docs/static/img/icon.png b/docs/static/img/icon.png new file mode 100644 index 0000000000..b74b839e2b Binary files /dev/null and b/docs/static/img/icon.png differ diff --git a/docs/static/img/image.png b/docs/static/img/image.png new file mode 100644 index 0000000000..d967d6fc6e Binary files /dev/null and b/docs/static/img/image.png differ diff --git a/docs/templates/typescript-+-webpack-template.md b/docs/templates/typescript-+-webpack-template.md new file mode 100644 index 0000000000..f95a4e0b67 --- /dev/null +++ b/docs/templates/typescript-+-webpack-template.md @@ -0,0 +1,17 @@ +--- +description: Create a new Electron app with webpack and TypeScript. +--- + +# Webpack + Typescript + +To get you up and running as fast as possible with [TypeScript](https://www.typescriptlang.org/) and [webpack](https://webpack.js.org/), we provide a template that makes use of the [`@electron-forge/plugin-webpack` module](../config/plugins/webpack.mdx) with sane TypeScript configuration defaults. + +```bash +npx create-electron-app@latest my-new-app --template=webpack-typescript +``` + +:::warning +There have been reports that using the Git Bash command line on Windows specifically with this template will prevent the Electron app from rendering (packaged apps are fine). We recommend that on Windows, you use CMD.exe, PowerShell, or [WSL2](../guides/developing-with-wsl.md). +::: + +Once you've initialized the template, you'll need to run `npm start` in the generated directory. See the [Webpack Plugin](../config/plugins/webpack.mdx) documentation for Electron Forge-specific configuration options. diff --git a/docs/templates/vite-+-typescript.md b/docs/templates/vite-+-typescript.md new file mode 100644 index 0000000000..43acea64eb --- /dev/null +++ b/docs/templates/vite-+-typescript.md @@ -0,0 +1,17 @@ +# Vite + TypeScript + +:::info +As of Electron Forge v7.5.0, Vite support for Electron Forge has been marked as **experimental** in order to reflect its stage in development and to provide maintainers with the ability to release fixes and improvements rapidly. Future minor releases may contain breaking changes, but migration steps will be listed in release notes.\ +\ +For more context, see the Electron Forge [v7.5.0 release notes](https://github.com/electron/forge/releases/tag/v7.5.0). +::: + +To get you up and running as fast as possible with [TypeScript](https://www.typescriptlang.org/) and [Vite](https://vitejs.dev/), we provide a template that makes use of the [`@electron-forge/plugin-vite` module](../config/plugins/vite.mdx) with sane TypeScript configuration defaults. + +```bash +npx create-electron-app@latest my-new-app --template=vite-typescript +``` + +Once you've initialized the template, you'll need to run `npm start` in the generated directory. + +See the [Vite Plugin](../config/plugins/vite.mdx) documentation for Electron Forge-specific configuration options. diff --git a/docs/templates/vite.md b/docs/templates/vite.md new file mode 100644 index 0000000000..9f1cb6740c --- /dev/null +++ b/docs/templates/vite.md @@ -0,0 +1,21 @@ +--- +description: Create a new Electron app with Vite. +--- + +# Vite + +:::info +As of Electron Forge v7.5.0, Vite support for Electron Forge has been marked as **experimental** in order to reflect its stage in development and to provide maintainers with the ability to release fixes and improvements rapidly. Future minor releases may contain breaking changes, but migration steps will be listed in release notes.\ +\ +For more context, see the Electron Forge [v7.5.0 release notes](https://github.com/electron/forge/releases/tag/v7.5.0). +::: + +To get you up and running as fast as possible with [Vite](https://vitejs.dev/), we provide a template that makes use of the [`@electron-forge/plugin-vite` module](../config/plugins/vite.mdx), plus some preset Vite configuration options. + +```bash +npx create-electron-app@latest my-new-app --template=vite +``` + +Once you've initialized the template, you'll need to run `npm start` in the generated directory. + +See the [Vite Plugin](../config/plugins/vite.mdx) documentation for Electron Forge-specific configuration options. diff --git a/docs/templates/webpack-template.md b/docs/templates/webpack-template.md new file mode 100644 index 0000000000..6760e24fca --- /dev/null +++ b/docs/templates/webpack-template.md @@ -0,0 +1,13 @@ +--- +description: Create a new Electron app with Webpack +--- + +# Webpack + +To get you up and running as fast as possible with the [webpack](https://webpack.js.org) bundler, we provide a template that makes use of the [`@electron-forge/plugin-webpack` module](../config/plugins/webpack.mdx), plus some preset webpack configuration options. This is by far the quickest way to getting a working webpack setup with Electron. + +```bash +npx create-electron-app@latest my-new-app --template=webpack +``` + +Once you've initialized the template, you'll need to run `npm start` in the generated directory. See the [Webpack Plugin](../config/plugins/webpack.mdx) documentation for Electron Forge-specific configuration options. diff --git a/typedoc.json b/typedoc.json index fb0b0085ad..6c65d6d50d 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,5 +1,6 @@ { "$schema": "https://typedoc.org/schema.json", + "out": "api-docs", "entryPointStrategy": "packages", "entryPoints": [ "packages/api/core",