@nlfmt/electron-bridge
v0.3.0
Published
Typesafe IPC bridge for electron
Downloads
6
Maintainers
Readme
Electron Bridge
Easily define and use IPC functions and events in your Electron app. Fully typesafe.
Inspired by tRPC's architecture.
Installation
npm install @nlfmt/electron-bridge
pnpm add @nlfmt/electron-bridge
yarn add @nlfmt/electron-bridge
Usage
This library is designed to be used with electron apps that enable contextIsolation
, sandbox
and disable nodeIntegration
.
Create bridge
// bridge.ts
import { createBridge, createBridgeRouter } from '@nlfmt/electron-bridge'
// You can place routers in separate files and import them here
const exampleRouter = createBridgeRouter({
log: (e, message: string) => {
console.log("Message from IPC:", message)
},
})
export const bridge = createBridge({
example: exampleRouter,
})
Register bridge
// main.ts
import { bridge } from './bridge'
// This will call ipcMain.handle() under-the-hood and set up all listeners
// Don't forget to call this before you send any IPC messages
bridge.register()
Register preload script
If you have sandbox
enabled, you wont be able to import registerBridgePreload
,
unless you are using a bundler, such as vite
with the vite-plugin-electron
plugin.
For a workaround, see the Issues section.
// preload.ts
import { registerBridgePreload } from '@nlfmt/electron-bridge/preload'
registerBridgePreload()
Use bridge
// App.tsx
import { createRendererBridge } from '@nlfmt/electron-bridge/renderer'
// Usually would be defined in a separate file like `bridge.ts`
export const bridge = createRendererBridge()
function App() {
return (
<button onClick={() => bridge.example.log("Hello from App.tsx")}>
Send message
</button>
)
}
export default App
Set up Events
Register Events using the withEvents
method on the bridge.
// bridge.ts
type RendererEvents = {
userClickedButton: { message: string }
}
type MainEvents = {
ping: { data: number }
}
export const bridge = createBridge({
example: exampleRouter,
}).withEvents<RendererEvents, MainEvents>()
// send events every second
setInterval(() => {
bridge.emit("ping", { data: Math.random() })
}, 1000)
bridge.on()
Then, use the events api in the renderer:
// App.tsx
import { createRendererBridge } from '@nlfmt/electron-bridge/renderer'
import { useEffect } from 'react'
export const bridge = createRendererBridge()
function App() {
useEffect(() => {
// methods like `on` and `once` return a function that can be used to unsubscribe
return bridge.events.on("ping", (e, data) => {
console.log("Ping from main:", data)
})
}, [])
return (
<button onClick={() => bridge.example.log("Hello from App.tsx")}>
Send message
</button>
)
}
Issues
Preload scripts without a bundler
If you are not using a bundler, you can use the following workaround to register everything needed by the bridge:
import { contextBridge, ipcRenderer } from "electron"
contextBridge.exposeInMainWorld("__bridge", {
invoke: ipcRenderer.invoke,
emit: ipcRenderer.send,
on: (...args: Parameters<typeof ipcRenderer.on>) => {
ipcRenderer.on(...args)
return () => ipcRenderer.off(...args)
},
once: (...args: Parameters<typeof ipcRenderer.once>) => {
ipcRenderer.once(...args)
return () => ipcRenderer.off(...args)
},
off: ipcRenderer.off,
})
License
See LICENSE for more information.