automate-electron-ipc
Version:
Node library for automating the generation of IPC components for Electron apps.
154 lines (106 loc) • 7.74 kB
Markdown
# Automate Electron IPC
[](https://nodejs.org/en/download/prebuilt-installer/current)
[](https://github.com/aabmets/automate-electron-ipc/blob/main/LICENSE)
[](https://codecov.io/gh/aabmets/automate-electron-ipc)
[](https://www.npmjs.com/package/automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)<br/>
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
[](https://sonarcloud.io/summary/new_code?id=aabmets_automate-electron-ipc)
### Description
Node library for generating IPC components for Electron apps.
### Features
1) Declarative IPC schema using channel expressions
2) Generation of sender and listener callables for the main process
3) Generation of preload bindings for renderer processes
4) Generation of typehints for the renderer Window object
5) Automatic import of user-defined types for generated components
6) BrowserWindow event triggers for MainToRenderer Broadcast channels
### Installation
`bun add automate-electron-ipc --dev`
`pnpm add automate-electron-ipc --save-dev`
`yarn add automate-electron-ipc --dev`
`npm install automate-electron-ipc --save-dev`
### Optional Configuration
You can configure IPC automation in the `package.json` file using the following options.
If no configuration is provided, IPC automation will use the default values as shown in the example below.
```json
{
"config": {
"autoipc": {
"projectUsesNodeNext": false,
"ipcDataDir": "src/autoipc",
"codeIndent": 3
}
}
}
```
Config explanation:
- `projectUsesNodeNext` - Must be set to true when `moduleResolution` in `tsconfig.json` is `nodenext`.
- `ipcDataDir` - Relative path to a directory within the users project which will contain the IPC schema expressions and where the IPC bindings will be generated into.
- `codeIndent` - How many spaces will one code indentation level have within the generated IPC bindings.
### Getting Started
IPC bindings are generated by calling the `ipcgen` command provided by this library from the command line.
When you initially run this command, you will get a warning about IPC channels not being found.
Do not let this warning dissuade you, as it's purpose is to guide you where to create the schema
file or directory, which will contain the channel expressions that will be parsed by IPC automation.
By default, IPC automation looks for a file named `schema.ts` in the IPC data directory.
If you create a directory named `schema` into the IPC data directory, then IPC automation
will recursively parse all files within it for Channel expressions, meaning it is possible
to structure and segment channel expressions according to the needs of larger applications.
### Channel Expressions
IPC automation uses its own Domain-Specific Language to generate IPC bindings. We call this language `CHEX`,
which masquerades itself as regular JavaScript/TypeScript, but it's code is never executed by Node. Instead,
this library uses the TypeScript library internally to parse the channel expressions from schema files to
deduce the meanings behind their definitions.
Since this library is well-documented through its type definitions, the developer is encouraged to use an IDE
which facilitates easy type inference and hints within its user interface. To that end, you should configure your
`tsconfig.node.json` to include the generated `main.ts` and `preload.ts` files from within the IPC data directory.
For the renderer process, you should include the generated `window.d.ts` file into your `tsconfig.web.json` file.
_Note: IPC automation does not make a distinction between senders/listeners and invokers/handlers as they are
defined in the IPC documentation of the Electron library. Whether an IPC component is generated as a sender/listener
or invoker/handler under the hood depends on the direction and the kind of the channel expression. The reason
behind this design choice was to allow the user to focus on IPC arguments and return types without having to
concern themselves with IPC internals._
### Simple Example
Schema file content at path `src/autoipc/schema.ts`:
```typescript
import { Channel, type } from "automate-electron-ipc";
Channel("EchoUserName").RendererToMain.Broadcast({
signature: type as (userName: string) => void
});
```
After IPC bindings have been generated by running `ipcgen`, they can be used as described below.
_Note: For brevity sake, other important code related to BrowserWindow has been omitted._
In main process source code file `src/main/index.ts`:
```typescript
import { app } from "electron";
import { ipcMain } from "../autoipc/main";
app.whenReady().then(() => {
ipcMain.onEchoUserName((event, userName) => console.log(`Greetings, ${userName}!`));
});
```
Anywhere in renderer process source code:
```html
<button onClick={() => window.ipc.sendEchoUserName("Anonymous")}>
```
The example code provides only basic HTML, because this library is front-end-tech agnostic,
meaning you can use any front-end framework or library like React, Vue or Angular.
### Channel Directions and Kinds
Channels may be defined with three directions:
```typescript
Channel("Channel1").RendererToMain // IPC call from a renderer process to the main process
Channel("Channel2").MainToRenderer // IPC call from the main process to a renderer process
Channel("Channel3").RendererToRenderer // Port binding between two renderer processes
```
Each direction supports specific kinds of transmissions:
```typescript
Channel("Channel1").RendererToMain.Broadcast() // Message from one sender to one or multiple listeners without return data
Channel("Channel2").RendererToMain.Unicast() // Message from one sender to one listener with return data
Channel("Channel3").MainToRenderer.Broadcast() // Message from one sender to one or multiple listeners without return data
Channel("Channel4").RendererToRenderer.Port() // Sender and listener on same port for each process
```