diff --git a/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx new file mode 100644 index 0000000000..dc779d7229 --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx @@ -0,0 +1,134 @@ +--- +sidebar_position: 10 +--- +# Usage with Electron + +Electron applications have a special architecture consisting of multiple processes with different responsibilities. Applying FSD in such a context requires adapting the structure to the Electron specifics. + +```sh +└── src + ├── app # Common app layer + │ ├── main # Main process + │ │ └── index.ts # Main process entry point + │ ├── preload # Preload script and Context Bridge + │ │ └── index.ts # Preload entry point + │ └── renderer # Renderer process + │ └── index.html # Renderer process entry point + ├── main + │ ├── features + │ │ └── user + │ │ └── ipc + │ │ ├── get-user.ts + │ │ └── send-user.ts + │ ├── entities + │ └── shared + ├── renderer + │ ├── pages + │ │ ├── settings + │ │ │ ├── ipc + │ │ │ │ ├── get-user.ts + │ │ │ │ └── save-user.ts + │ │ │ ├── ui + │ │ │ │ └── user.tsx + │ │ │ └── index.ts + │ │ └── home + │ │ ├── ui + │ │ │ └── home.tsx + │ │ └── index.ts + │ ├── widgets + │ ├── features + │ ├── entities + │ └── shared + └── shared # Common code between main and renderer + └── ipc # IPC description (event names, contracts) +``` + +## Public API rules +Each process must have its own public API. For example, you can't import modules from `main` to `renderer`. +Only the `src/shared` folder is public for both processes. +It's also necessary for describing contracts for process interaction. + +## Additional changes to the standard structure +It's suggested to use a new `ipc` segment, where interaction between processes takes place. +The `pages` and `widgets` layers, based on their names, should not be present in `src/main`. You can use `features`, `entities` and `shared`. +The `app` layer in `src` contains entry points for `main` and `renderer`, as well as the IPC. +It's not desirable for segments in the `app` layer to have intersection points + +## Interaction example + +```typescript title="src/shared/ipc/channels.ts" +export const CHANNELS = { + GET_USER_DATA: 'GET_USER_DATA', + SAVE_USER: 'SAVE_USER', +} as const; + +export type TChannelKeys = keyof typeof CHANNELS; +``` + +```typescript title="src/shared/ipc/events.ts" +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; + }; +} +``` + +```typescript title="src/shared/ipc/preload.ts" +import { CHANNELS } from './channels'; +import type { IEvents } from './events'; + +type TOptionalArgs = T extends void ? [] : [args: T]; + +export type TElectronAPI = { + [K in keyof typeof CHANNELS]: (...args: TOptionalArgs) => IEvents[typeof CHANNELS[K]]['response']; +}; +``` + +```typescript title="src/app/preload/index.ts" +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); +``` + +```typescript title="src/main/features/user/ipc/send-user.ts" +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', + }; + }); +}; +``` + +```typescript title="src/renderer/pages/user-settings/ipc/get-user.ts" +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' }; +}; +``` + +## See also +- [Process Model Documentation](https://www.electronjs.org/docs/latest/tutorial/process-model) +- [Context Isolation Documentation](https://www.electronjs.org/docs/latest/tutorial/context-isolation) +- [Inter-Process Communication Documentation](https://www.electronjs.org/docs/latest/tutorial/ipc) +- [Example](https://github.com/feature-sliced/examples/tree/master/examples/electron) \ No newline at end of file diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx index 9976723484..4bf74c3ae4 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/tech/with-electron.mdx @@ -7,7 +7,7 @@ Electron-приложения имеют особую архитектуру, с ```sh └── src - ├── app # Общий сегмент app + ├── app # Общий слой app │ ├── main # Main процесс │ │ └── index.ts # Точка входа main процесса │ ├── preload # Preload скрипт и Context Bridge