A plugin for Electron Forge to build and package an external resource
MIT License
This is a plugin for Electron Forge.
Use this if you have:
For example:
dotnet
, not by Electron Forge, and it exists outside the application's normal src
directory.This lets you specify:
The plugin will then:
To use this plugin:
Include it as a development tool dependency of your project, for example using
npm install -D electron-forge-resource-plugin
Configure it by adding to the config.plugins
array of your forge.config.ts
Use the new symbol in your application
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.
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.
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.
DefinePlugin
in webpack.plugins.js
, and use in your application.path
The path to the resource (a file), when the application is started locally or packaged.
build.command
is undefined.build.command
Optional: the command to build the resource.
build.sources
Optional: the source from which the resource is built.
build.command
build.sources
are more recent that the file specified by the path
.build.sources
is undefined, then by default the build.command
is run only when path
does not already exist.build.sources
can specify one or more files and/or directories.build.sources
can specify { always: boolean }
to specify that the build.command
should 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.
package.copydir
is undefined, then the default is true
if package.dirname
is defined, otherwise false
.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",
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
|
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.
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:
PluginBase
class,PluginBase
class is also used by other plugins including the Webpack pluginPluginBase
class than is already used in your project,PluginBase
classPluginBase
class triggers this errorTo 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.
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:
package.json
instead of as JavaScript in forge.config.ts
forge.config.ts
before the plugins' hook methods are calledIn these cases you must edit a Webpack configuration file manually:
see the examples.old
folder for details.