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

pluggable-electron

v1.0.0

Published

A framework to create a plugin API in Electron apps

Downloads

95

Readme

Pluggable Electron

Pluggable Electron is a framework to build Electron apps that can be extended by other parties.

package-size stars license language vulnerabilities version electron coverage

Introduction

Pluggable Electron allows an Electron app to include extension points in the code. Plugin developers can then write extensions - in the form of npm packages - that can be inserted into these extension points.

The framework includes the tools necessary to manage the whole life cycle of plugins, for example writing, installing, uninstalling and updating plugins, and creating and triggering extension points.

The framework uses inversion of control and dependency inversion principles for this.

Framework process

❗Notice❗

As of version 0.6.0 the largest development effort seems to be done. I will try to keep the interface as steady as possible from now on but as always, changes can happen.

Version 0.6.0 has however included quite a number of breaking changes to ensure all the necessary interfaces and features are now included. For people migrating from an earlier version, please see the release notes for how to update your code.

Getting Started

To include Pluggable Electron, follow these simple steps:

Prerequisites

This package should be installed inside an Electron project. Please create that first.

Installation

Add Pluggable Electron in your project as a dependency to your project

npm install pluggable-electron

Usage

Below you will find a quick start guide on how to set Pluggable Electron up. A full guide can be found in the wiki

The framework is built around the concepts of Extension points and Plugins

Extension points

Extension points are added to your renderer code.

Execute extension point where you want to provide plugin developers with the possibility to extend your code. This can be done as a handover, parallel execution, or serial execution. These options are explained here.

// renderer/your-module.js
import { extensionPoints } from "pluggable-electron/renderer"

// ... Your business logic ...
const extendMenu = extensionPoints.execute('purchase_menu', purchaseMenu )
// extendMenu will contain the result of any extensions registered to purchase_menu

Registering extensions

To determine the extensions that need to be executed by an extension point, it needs to be possible for plugins to register to an extension. This is done by creating activation points which are the points where plugins are activated. On activation, a plugin can register functions or objects to extension points (see below). Creating an activation point requires the activation point manager to be set up.

There can be different strategies for activating the plugin, like:

  • Activating all plugins during startup - one point during the app startup for synchronous extensions and one after startup for async extensions
  • Activating the relevant plugins just before an extension point is triggered.

See the API for the activation point manager here.

// renderer/index.js
import { setup, activationPoints } from "pluggable-electron/renderer"

// Enable the activation points
setup({
  // Provide the import function
  importer: async (pluginPath) => import( /* webpackIgnore: true */ pluginPath)
})

// insert at any point
activationPoints.trigger( 'init' )
// but before related extension points are triggered.

Creating plugins

A plugin is an npm package with activation points added to the package.json.

// package.json
{
   ...
   "main": "index.js",
   "activationPoints": [
      "init"
   ]
   ...
}

The main file of this plugin should include a function for each of the activation points listed in the package.json. This function will be be triggered by the activation point and be passed an object containing a function to register extensions to extension points by default. An extension can be a callback or object returned to the register method.

// index.js
export function init (extensionPoints) {
   // Mock function for adding a menu item
   const yourCustomExtension = (varFromExtensionPoint) => {
      // your extension code here.
      // varFromExtensionPoint is provided as a parameter when the extension point is executed;
      // purchaseMenu in the example above.
   }

  // Register to purchase_menu extension point
  extensionPoints.register( 'purchase_menu', 'extension-name', yourCustomExtension )
}

Installing plugins

Plugins are managed in the main process but can be installed from the renderer or the main process. In this setup we will use the renderer. This requires the initialisation of the plugin facade in the renderer using a preload script. Doing everything from the main process is described in the API documentation.

Once installed, the plugins should be loaded on every startup.

// main.js
const pe = require( "pluggable-electron/main" )
...
app.whenReady().then(() => {
  //Initialise pluggable Electron
  pe.init({
      // Function to check from the main process that user wants to install a plugin for security
      confirmInstall: async plugins => {
        const answer = await dialog.showMessageBox({
          message: `Are you sure you want to install the plugins ${plugins.join(', ')}`,
          buttons: ['Ok', 'Cancel'],
          cancelId: 1,
        })
        return answer.response == 0
      },
      // Folder to save the plugins to
      pluginsPath: path.join(app.getPath('userData'), 'plugins')
    })
  ...
})
// preload.js
const useFacade = require("pluggable-electron/preload")
useFacade()
// renderer/your-install-module.js
import { plugins } from 'pluggable-electron/renderer'

// Get plugin file from input and install
document.getElementById( 'install-file-input' ).addEventListener( 'change', (e) =>
   plugins.install( [e.target.files[0].path] )
)
//  renderer/index.js
import { setup, plugins, activationPoints } from "pluggable-electron/renderer"

// Enable the activation points
setup({
  importer: async (pluginPath) => import( /* webpackIgnore: true */ pluginPath)
})

// Get plugins that have been installed previously
// and register them with their activation points
plugins.registerActive()

// insert at any point after the plugins have been registered
activationPoints.trigger( 'init' )

End result

Now the yourCustomExtension function in the plugin will be executed when the execution point purchase_menu is triggered.

Further functionality

Pluggable Electron provides a host of functions to support the full plugin lifecycle and some alternative workflows. A more detailed description of the full lifecycle, as well as a detailed API documentation can be found in the wiki.

Demo

A demo project using Pluggable Electron can be found here: https://github.com/dutchigor/pluggable-electron-demo. Also check out the with-vue branch to see an example with Vite and Vue. This example contains a few catches to be aware of when using packaged frontend framework so I recommend checking this out for any such framework.

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open-source community such an amazing place to be, learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Release Notes

See Changelog

License

Distributed under the MIT License. See LICENSE for more information.

Contact

This project is maintained by Igor Honhoff. Feel free to contact me at [email protected] Project Link: https://github.com/dutchigor/pluggable-electron