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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@remix-project/plugin-electron

v0.3.44

Published

How to use the plugin:

Readme

Plugin electon

How to use the plugin:

In electron you

  1. add the base plugin to a basic engine in electron: ElectronBasePlugin

  2. define the clients: ElectronBasePluginClient

  3. In Remix you add a simple plugin: ElectronPlugin

  4. You configer the preload script array to hold your plugin, see example below. If you don't do that you won't be able to call the plugin.

The base plugin holds the clients, and each client holds a reference to the window it instantiated from. More below about the engine. The base plugin is called by the engine in Electron, you're not calling it from Remix. Only the ElectronBasePluginClient linked to a specific window is the one you are calling from Remix. So internal methods of the base plugin are used for example by the menu or you can call when something happens in electron, ie before the app is closed.

import { ElectronBasePlugin, ElectronBasePluginClient } from "@remix-project/plugin-electron"

import { Profile } from "@remix-project/plugin-utils";

const profile: Profile = {
    displayName: 'exampleplugin',
    name: 'exampleplugin',
    description: 'Electron example plugin'
}

export class ExamplePlugin extends ElectronBasePlugin {
    clients: ExamplePluginClient[] = []
    constructor() {
        super(profile, clientProfile, ExamplePluginClient)
        this.methods = [...super.methods, 'internalMethod', 'doOnAllClients']
    }

    async internalMethod(data: any): Promise<void> {
        // do something
    }

    // execute on all clients
    async doOnAllClients(): Promise<void> {
        for (const client of this.clients) {
            await client.doSomething()
        }
    }

}

const clientProfile: Profile = {
    name: 'exampleplugin',
    displayName: 'exampleplugin',
    description: 'Electron example plugin',
    methods: ['remixMethod']
}

class ExamplePluginClient extends ElectronBasePluginClient {

    constructor(webContentsId: number, profile: Profile) {
        super(webContentsId, profile)
        
        this.window.on('close', async () => {
            // do something on window close
        })
    }

    async remixMethod(data: any): Promise<void> {
        // do something
    }

    async doSomething(data: any): Promise<void> {
    }


}

On the side of Remix you define a plugin too. This is all you need to do

import { ElectronPlugin } from '@remix-project/engine-electron';

export class examplePlugin extends ElectronPlugin {
  constructor() {
    super({
      displayName: 'exampleplugin',
      name: 'exampleplugin',
      description: 'exampleplugin',
    })
    this.methods = []

  }
}

The engine

Here's an example. Important to note is the ipcMain handle which actually triggered by the peload script. Check it out in remix: apps/remixdesktop/src/preload.ts


const engine = new Engine()
const appManager = new PluginManager()

const examplePlugin = new ExamplePlugin()
engine.register(appManager)
engine.register(examplePlugin)

ipcMain.handle('manager:activatePlugin', async (event, plugin) => {
  return await appManager.call(plugin, 'createClient', event.sender.id)
})

app.on('before-quit', async (event) => {
  await appManager.call('exampleplugin', 'doOnAllClients')
})

Preload script: This script is included in the electron app and is loaded before the application. It is an isolated script that has access to the renderer process of electron and acts as the bridge between the application and the renderer.

import { Message } from '@remix-project/plugin-utils'
import { contextBridge, ipcRenderer } from 'electron'

/* preload script needs statically defined API for each plugin */

const exposedPLugins = ['exampleplugin']

let webContentsId: number | undefined

ipcRenderer.invoke('getWebContentsID').then((id: number) => {
  webContentsId = id
})

contextBridge.exposeInMainWorld('electronAPI', {
  activatePlugin: (name: string) => {
    return ipcRenderer.invoke('manager:activatePlugin', name)
  },

  getWindowId: () => ipcRenderer.invoke('getWindowID'),

  plugins: exposedPLugins.map(name => {
    return {
      name,
      on: (cb:any) => ipcRenderer.on(`${name}:send`, cb),
      send: (message: Partial<Message>) => {
        ipcRenderer.send(`${name}:on:${webContentsId}`, message)
      }
    }
  })
})