Building Electron + Vue3 + Vite Projects Part 27: Creating a Window Utility Class Foundation
Introduction
The demo project is available here. For the window utility class series:
- Window Utility Class Part 1: Foundation
- Window Utility Class Part 2: Window Groups and Relationships
- Window Utility Class Part 3: Controlling Directional Window Movement
Previously, all main process logic was crammed in to the index.ts file, including window event handling, IPC handlers, protocol registration, and more. This approach becomes difficult to maintain as the application grows. Let's extract these functionalities into utility classes for better organization.
Approach
Using window creation as an example, the flow works as follows:
- Main process uses
ipcMain.handleto listen and construct a new window based on incoming paramteers
/**
* Create a new window
* @param route - Router path
* @param params - Serialized parameter object
*/
ipcMain.handle("create-window", (_, route: string, params: string) => {
// Implementation
});
- Renderer process calls
ipcRenderer.invoketo notify the main process to create the window
/**
* Create a new window
* @param path - Router path
* @param data - Parameters to pass
*/
export function createWindow(path: string, data?: object) {
// Implementation
ipcRenderer.invoke("create-window", path, serializedData);
}
As the application evolves, window creation logic will expand with various business requirements such as specifying dimensions, titles, background colors, window transparency, click-through behavior, and more. Additionally, managing multiple windows requires maintaining window group information that tracks window IDs and their logical relationships.
Therefore, we'll create a dedicated window utility class to encapsulate window-related methods, properties, and configurations.
Extracting Common Declaration Files
The handle/on methods in the main process correspond one-to-one with invoke/send in the renderer process. Since the parameters are also shared, we can create a common global declaration file to define shared parameter objects.
- Add common event object declarations in the global type file:
types/global.d.ts
/** Global type augmentations */
export {};
declare global {
// Window creation parameter specification
interface WindowOptions {
key?: string; // Unique window key; if omitted, uses window ID
route?: string; // Window router path
width?: number; // Window width
height?: number; // Window height
params?: string; // Parameters passed to new window, accessible via route
background?: string; // Background color
transparent?: boolean; // Enable transparency
}
}
- Import the global declaration in the main process:
electron/electron-env.d.ts
/// <reference types="vite-plugin-electron/electron-env" />
import "../../types/global.d.ts";
Extracting Global Shared Types and Methods
Both main and renderer processes use identical event names, so we can define a global event enum to standardize the code across both processes. Event names must be unique to avoid duplicate bindings.
- Create a
globaldirectory in the root, then addchannelEvent.tsandchannelEvent.d.tsfiles for event channel enums and their declarations:
global/channelEvent.ts
/**
* Custom event channel enumeration
*/
export enum ChannelEvents {
CREATE_WINDOW = "create-window",
CLOSE_WINDOW = "close-window",
MINIMIZE_WINDOW = "minimize-window",
MAXIMIZE_WINDOW = "maximize-window"
}