npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

electron-forge-resource-plugin

v1.0.0-alpha.8

Published

Plugin for Electron Forge to build and package an external resource

Downloads

1

Readme

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 normal src directory.
  • 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:

  1. Include it as a development tool dependency of your project, for example using

    npm install -D electron-forge-resource-plugin
  2. Configure it by adding to the config.plugins array of your forge.config.ts

  3. 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 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.

  • The hook will throw an exception, if the specified path is non-existent and the build.command is undefined.

build.command

Optional: the command to build the resource.

build.sources

Optional: the source from which the resource is built.

  • If defined, this will rerun the build.command when the the contents of build.sources are more recent that the file specified by the path.
  • If build.sources is undefined, then by default the build.command is run only when path does not already exist.
  • The build.sources can specify one or more files and/or directories.
  • Or the 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.

  • If 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",

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 PluginBase class, and therefore defines a version of that class as a dependency
  • The PluginBase class is also used by other plugins including the Webpack plugin
  • If this plugin depends on a newer version of the PluginBase class than is already used in your project, then it's installed with its own private copy of the PluginBase class
  • Having two installed instances of the PluginBase class 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.json instead of as JavaScript in forge.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.ts before the plugins' hook methods are called

In these cases you must edit a Webpack configuration file manually: see the examples.old folder for details.