Skip to content

Commit

Permalink
fix: do not register new ipc event listener when main screen componen…
Browse files Browse the repository at this point in the history
…t is loaded (fixes #176)
  • Loading branch information
jooy2 committed Jan 10, 2024
1 parent 52ffc48 commit a71feb8
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 19 deletions.
9 changes: 7 additions & 2 deletions docs/src/electron-how-to/preload-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ Vutron's preload script is located in the `src/preload` folder. To create a new

When sending events from renderer to main, you access the `window.mainApi` object instead of `ipcRenderer.send`. The `mainApi` is the name you set in your Vutron template and can be changed.

Here are the supported functions for mainApi: (To change and modify this, you need to modify `exposeInMainWorld` in `src/preload/index.ts`).
Here are the supported functions for mainApi:

- `send`: Send an event to main.
- `receive`: A listener to receive events sent by main.
- `sendSync`: Send an event to main. It can be used when receiving a return value. The UI may be frozen until the operation is complete.
- `on`: A listener to receive events sent by main.
- `once`: A listener to receive events sent by main. (Handle only one call)
- `off`: Remove an event listener
- `invoke`: Functions that can send events to main and receive data asynchronously.

To change and modify this, you need to modify `exposeInMainWorld` in `src/preload/index.ts`.
10 changes: 5 additions & 5 deletions src/main/IPCs.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { BrowserWindow, ipcMain, shell } from 'electron'
import { ipcMain, shell, IpcMainEvent } from 'electron'
import Constants from './utils/Constants'

/*
* IPC Communications
* */
export default class IPCs {
static initialize(window: BrowserWindow): void {
static initialize(): void {
// Get application version
ipcMain.on('msgRequestGetVersion', () => {
window.webContents.send('msgReceivedVersion', Constants.APP_VERSION)
ipcMain.on('msgRequestGetVersion', (event: IpcMainEvent) => {
event.returnValue = Constants.APP_VERSION
})

// Open url via web browser
ipcMain.on('msgOpenExternalLink', async (event, url: string) => {
ipcMain.on('msgOpenExternalLink', async (event: IpcMainEvent, url: string) => {
await shell.openExternal(url)
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/MainRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const createMainWindow = async (mainWindow: BrowserWindow): Promise<Brows
})

// Initialize IPC Communication
IPCs.initialize(mainWindow)
IPCs.initialize()

if (Constants.IS_DEV_ENV) {
await mainWindow.loadURL(Constants.APP_INDEX_URL_DEV)
Expand Down
35 changes: 28 additions & 7 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
import { contextBridge, ipcRenderer } from 'electron'
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'

// Whitelist of valid channels used for IPC communication (Send message from Renderer to Main)
const mainAvailChannels: string[] = ['msgRequestGetVersion', 'msgOpenExternalLink']
const rendererAvailChannels: string[] = ['msgReceivedVersion']
const rendererAvailChannels: string[] = []

contextBridge.exposeInMainWorld('mainApi', {
send: (channel: string, ...data: any[]): void => {
if (mainAvailChannels.includes(channel)) {
ipcRenderer.send.apply(null, [channel, ...data])
} else {
throw new Error(`Send failed: Unknown ipc channel name: ${channel}`)
throw new Error(`Unknown ipc channel name: ${channel}`)
}
},
receive: (channel: string, cbFunc: Function): void => {
sendSync: (channel: string, ...data: any[]): void => {
if (mainAvailChannels.includes(channel)) {
return ipcRenderer.sendSync.apply(null, [channel, ...data])
}

throw new Error(`Unknown ipc channel name: ${channel}`)
},
on: (channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): void => {
if (rendererAvailChannels.includes(channel)) {
ipcRenderer.on(channel, listener)
} else {
throw new Error(`Unknown ipc channel name: ${channel}`)
}
},
once: (channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): void => {
if (rendererAvailChannels.includes(channel)) {
ipcRenderer.once(channel, listener)
} else {
throw new Error(`Unknown ipc channel name: ${channel}`)
}
},
off: (channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): void => {
if (rendererAvailChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => cbFunc(event, ...args))
ipcRenderer.off(channel, listener)
} else {
throw new Error(`Receive failed: Unknown ipc channel name: ${channel}`)
throw new Error(`Unknown ipc channel name: ${channel}`)
}
},
invoke: async (channel: string, ...data: any[]): Promise<any> => {
Expand All @@ -25,6 +46,6 @@ contextBridge.exposeInMainWorld('mainApi', {
return result
}

throw new Error(`Invoke failed: Unknown ipc channel name: ${channel}`)
throw new Error(`Unknown ipc channel name: ${channel}`)
}
})
9 changes: 5 additions & 4 deletions src/renderer/screens/MainScreen.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ onMounted((): void => {
languages.value = availableLocales
// Get application version from package.json version string (Using IPC communication)
window.mainApi.receive('msgReceivedVersion', (event: Event, version: string) => {
appVersion.value = version
})
window.mainApi.send('msgRequestGetVersion')
getApplicationVersionFromMainProcess()
})
const getApplicationVersionFromMainProcess = (): void => {
appVersion.value = window.mainApi.sendSync('msgRequestGetVersion')
}
const handleChangeTheme = (): void => {
theme.global.name.value = theme.global.current.value.dark ? 'light' : 'dark'
}
Expand Down

0 comments on commit a71feb8

Please sign in to comment.