Electron ile Kullanım
Electron uygulamaları, farklı sorumluluklara sahip birden fazla süreçten (process) oluşan özel bir mimariye sahiptir. Böyle bir bağlamda FSD uygulamak, yapının Electron’un dinamiklerine uyarlanmasını gerektirir.
Dizinsrc
Dizinapp Ortak app katmanı
Dizinmain Main süreci
- index.ts Main süreci giriş noktası
Dizinpreload Preload betiği ve Context Bridge
- index.ts Preload giriş noktası
Dizinrenderer Renderer süreci
- index.html Renderer süreci giriş noktası
Dizinmain
Dizinfeatures
Dizinuser
Dizinipc
- get-user.ts
- send-user.ts
- entities
- shared
Dizinrenderer
Dizinpages
Dizinsettings
Dizinipc
- get-user.ts
- save-user.ts
Dizinui
- user.tsx
- index.ts
Dizinhome
Dizinui
- home.tsx
- index.ts
- widgets
- features
- entities
- shared
Dizinshared Main ve renderer arasındaki ortak kod
- ipc IPC tanımı (olay adları, sözleşmeler)
Public API kuralları
Section titled “Public API kuralları”Her sürecin (process) kendi Public API’si olmalıdır. Örneğin, main sürecinden renderer sürecine doğrudan modül aktaramazsınız.
Yalnızca src/shared klasörü her iki süreç için de genel kullanıma açıktır (public).
Bu klasör ayrıca süreçler arası etkileşim sözleşmelerini (contracts) tanımlamak için de gereklidir.
Standart yapıya yapılan ek değişiklikler
Section titled “Standart yapıya yapılan ek değişiklikler”Süreçler arasındaki etkileşimin gerçekleştiği yeni bir ipc segmenti kullanılması önerilir.
pages ve widgets katmanları, isimleri ve işlevleri gereği src/main içinde yer almamalıdır. Bunun yerine features, entities ve shared katmanlarını kullanabilirsiniz.
src içerisindeki app katmanı, main ve renderer için giriş noktalarının yanı sıra IPC yapılandırmasını barındırır.
app katmanındaki segmentlerin kesişim noktalarına sahip olması istenmez.
Etkileşim örneği
Section titled “Etkileşim örneği”export const CHANNELS = { GET_USER_DATA: 'GET_USER_DATA', SAVE_USER: 'SAVE_USER',} as const;
export type TChannelKeys = keyof typeof CHANNELS;import { CHANNELS } from './channels';
export interface IEvents { [CHANNELS.GET_USER_DATA]: { args: void, response?: { name: string; email: string; }; }; [CHANNELS.SAVE_USER]: { args: { name: string; }; response: void; };}import { CHANNELS } from './channels';import type { IEvents } from './events';
type TOptionalArgs<T> = T extends void ? [] : [args: T];
export type TElectronAPI = { [K in keyof typeof CHANNELS]: (...args: TOptionalArgs<IEvents[typeof CHANNELS[K]]['args']>) => IEvents[typeof CHANNELS[K]]['response'];};import { contextBridge, ipcRenderer } from 'electron';import { CHANNELS, type TElectronAPI } from 'shared/ipc';
const API: TElectronAPI = { [CHANNELS.GET_USER_DATA]: () => ipcRenderer.sendSync(CHANNELS.GET_USER_DATA), [CHANNELS.SAVE_USER]: args => ipcRenderer.invoke(CHANNELS.SAVE_USER, args),} as const;
contextBridge.exposeInMainWorld('electron', API);import { ipcMain } from 'electron';import { CHANNELS } from 'shared/ipc';
export const sendUser = () => { ipcMain.on(CHANNELS.GET_USER_DATA, ev => { ev.returnValue = { name: 'John Doe', email: 'john.doe@example.com', }; });};import { CHANNELS } from 'shared/ipc';
export const getUser = () => { const user = window.electron[CHANNELS.GET_USER_DATA]();
return user ?? { name: 'John Donte', email: 'john.donte@example.com' };};