electron-forge-resource-plugin v1.0.0-alpha.8
Electron Forge Resource Plugin
This is a plugin for Electron Forge.
Purpose
Use this if you have:
- An Electron application built using Electron Forge, and
- A resource, whose path is needed by your application, and which isn't built by Electron Forge
For example:
- I have a .NET executable which I want to invoke --
it is built using
dotnet, not by Electron Forge, and it exists outside the application's normalsrcdirectory. - As well as executables, you could also use this for building documentation; media files; etc.
This lets you specify:
- The resource's path
- How to build it, and when to rebuild it
- Whether to package either only the specified file, or the whole directory in which it is contained
The plugin will then:
- Integrate with the Electron Forge build
- Rebuild the resource when needed
- Hook the Packager Config to package the resource
- Define the resource path as an environment variable when the application is built -- this environment variable varies, depending on whether the application is run locally or is packaged
How to use it
To use this plugin:
Include it as a development tool dependency of your project, for example using
npm install -D electron-forge-resource-pluginConfigure it by adding to the
config.pluginsarray of yourforge.config.ts- Use the new symbol in your application
Configure it in forge.config.ts
Add a new element to the config.plugins array of your forge.config.ts, for example:
new ResourcePlugin({
env: "CORE_EXE",
path: "./src.dotnet/bin/Release/net5.0/Core.exe",
build: {
command: "dotnet.exe build ./src.dotnet/Core.csproj --verbosity normal --configuration Release",
sources: "./src.dotnet/",
},
package: {
dirname: "core",
},
verbose: true,
});The above configuration, which is shown as an example, is copied from the dotnet branch of this project:
See the examples.new folder for a complete example of the configuration files.
Use the path in your application
Your main application can now read the value of the symbol, for example:
declare const CORE_EXE: string;
log(`CORE_EXE is ${CORE_EXE}`);This is like how Electron Forge defines
_WEBPACK_ENTRY values.
Configuration
This is the configuration interface as it's declared in the source code.
export interface ResourcePluginConfig {
env: string;
path: string;
build?: {
command: string;
sources?: string | string[] | { always: boolean };
};
package?: {
dirname?: string;
copydir?: boolean;
};
verbose?: boolean;
}To configure the plugin you pass this data to the plugin's constructor in your forge.config.ts
for example as shown above.
env
The name of the environment variable which the plugin will define.
- This should match the name which you pass to the
DefinePlugininwebpack.plugins.js, and use in your application.
path
The path to the resource (a file), when the application is started locally or packaged.
- The hook will throw an exception, if the specified path is non-existent and the
build.commandis undefined.
build.command
Optional: the command to build the resource.
- If defined, this command will be run using child_process.exec.
build.sources
Optional: the source from which the resource is built.
- If defined, this will rerun the
build.commandwhen the the contents ofbuild.sourcesare more recent that the file specified by thepath. - If
build.sourcesis undefined, then by default thebuild.commandis run only whenpathdoes not already exist. - The
build.sourcescan specify one or more files and/or directories. - Or the
build.sourcescan specify{ always: boolean }to specify that thebuild.commandshould be run every time.
package.dirname
Optional: the name of the subdirectory in the packaged resources directory
package.copydir
Optional: whether to package only the file specified by path, or package the whole directory which contains that file.
- If
package.copydiris undefined, then the default istrueifpackage.dirnameis defined, otherwisefalse.
verbose
Optional: enables the log method which writes progress messages to console.log which is helpful for debugging.
To use this option you must also set the DEBUG environment variable to include electron-forge -- because otherwise
the output is overwritten by the listr2 package, which Electron Forge scripts use to write their progress messages.
Set that environment variable before the scripts are run, for example on Windows by editing package.json as follow:
"scripts": {
"start": "set DEBUG=electron-forge&& electron-forge start",Packaging a directory
When the resource is an executable and the application is started locally, it only needs the path of the executable,
for example:
./src.dotnet/bin/Release/net5.0/Core.exe
When the application is packaged, the package must also include the executable's dependencies, i.e. the whole directory in which the file is contained:
./src.dotnet/bin/Release/net5.0/*.*
You can configure this scenario using the optional package.dirname and package.copydir entries.
| dirname | copydir | Meaning |
|---|---|---|
| undefined | undefined | Only the resource file is packaged:./resources/Core.exe |
| defined | undefined | The whole directory is copied into the specified subdirectory:./resources/core/*.* |
| undefined | = true | The whole directory is copied with its name unaltered:./resources/net5.0/*.* |
| defined | = false | Only the file is copied into the specified subdirectory:./resources/core/Core.exe |
Notes
Using hooks instead of a plugin
Instead of writing or using a plugin, it's possible to configure the build using "Hooks" e.g. as follows:
// https://www.electronforge.io/configuration#hooks
// https://stackoverflow.com/questions/64097951/electron-forge-how-to-specify-hooks
// https://github.com/electron-userland/electron-forge/issues/197
const execFileSync = require("child_process").execFileSync;
module.exports = {
generateAssets: async (forgeConfig, platform, arch) => {
console.log("\r\nWe should generate some assets here\r\n");
execFileSync("dotnet.exe", [
"build",
"./src.dotnet/Core.csproj",
"--verbosity",
"normal",
"--configuration",
"Release",
]);
console.log("\r\nAssets generated\r\n");
},
};The benefit of a plugin like this one, instead of hooks, is that a plugin is easily configurable and therefore reusable.
Error message Multiple plugins tried to take control of the start command, please remove one of them
When you install this plugin into an Electron Forge project, you may get an error like the following when you
run the npm run start comment:
An unhandled rejection has occurred inside Forge:
Error: Multiple plugins tried to take control of the start command, please remove one of them
--> resource, webpack
Electron Forge was terminated.The reason for this error message is:
- This plugin is a subclass of the Electron Forge
PluginBaseclass, and therefore defines a version of that class as a dependency - The
PluginBaseclass is also used by other plugins including the Webpack plugin - If this plugin depends on a newer version of the
PluginBaseclass than is already used in your project, then it's installed with its own private copy of thePluginBaseclass - Having two installed instances of the
PluginBaseclass triggers this error
To fix it, ensure that the version of Electron Forge used by your project is the same or later than the version used by this plugin -- if not, update the dependencies of your project to use a newer version.
Older configuration
The resource plugin is able to define the new symbol automatically, but only
if the Webpack configuration is imported (i.e. instantiated) as JavaScript objects in the forge.config.ts file.
In either of the following cases it cannot do this automatically:
- Electron forge configuration is defined as JSON in
package.jsoninstead of as JavaScript inforge.config.ts - The Webpack Plugin configuration references Webpack configurations as filenames, which are loaded
by the Webpack Plugin instead of being imported into
forge.config.tsbefore the plugins' hook methods are called
In these cases you must edit a Webpack configuration file manually:
see the examples.old folder for details.
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago