Сова пишет…
2.99K subscribers
375 photos
38 videos
5 files
444 links
Download Telegram
Как работает общение между процессами в Electron.

Я не хотел делать по типичным советам из гайда Electron. Они еще рекомендуют сделать специальную прослойку через файл preload.js, мне было лень, но даже его можно автоматизировать по примеру, который я покажу.

В ipc/factory.ts я создал домен и функцию создающую запросы. Создаю запросы не через домен, чтобы не было соблазна навесить обработчик сразу при создании эффекта. Плюс, так визуально можно разделить обычные эффекты и запросы.

В ipc/db.ts я собственно описываю эти запросы, главное тут это типы и sid. Чтобы все заработало, потребовалось добавить алиасы для @ipc/db и @ipc/factory, это нужно, чтобы из main процесса (nodejs) и renderer (chrome) можно было импортировать эти файлы одинаково.

Одинаковые импорты важны, ведь в настройках сборки я прохожусь по файлам процессов main и renderer с помощью babel. Я просто вписал импорты выше в factories в effector/babel-plugin. Можно было использовать swc, но мне как-то привычнее babel. Я использовал vite-plugin-electron, чтобы собирать обе части приложения.

Теперь у каждого запроса созданного через createRequest будет свой уникальный sid. И благодаря общей конфигурации компилятора и сборщика для обеих частей electron сиды будут идентичны. Имя эффекта просто поможет его явно идентифицировать в логах отладки.

В следующем посте я покажу как использовать эти запросы в renderer и main процессах. Жмите ⚡️ если узнали что-то новое.

#effector #electron
⚡16👍2🔥1
Подсоединяю логику обработки запросов в electron.

Модуль ipc-requests.ts добавляет обработчики всем запросам созданным через createRequest. В данном случае, я слушаю сообщения по каналу ipcMain. Метод .handle позволяет дождаться выполнения асинхронного кода и отправить результат обратно в renderer процесс.

Для идентификации запросов используется как раз таки .sid. Если для renderer и main процесса будут разные компиляторы и системы сборки, крайне важно удостовериться, что юниты получают идентичные sid'ы.

По этой же причине, запросы лежат в отдельной директории ipc в корне проекта и туда же настроены алиасы. Путь к файлам с запросами идентичен в обеих системах сборки.

На самом деле, можно добавить рантайм валидацию данных, например с помощью runtypes. Если интересно, покажу как это сделать, жмите 💯. Но структурно ничего не поменяется, лишь появится новый код внутри .onCreateEffect.

В файле ipc-database.ts я добавляю хендлеры для всех запросов из @ipc/db. Можно было бы сделать специальный TS-тип, чтобы иметь гарантии, что все запросы получили хендлеры, но я решил сделать проще, для наглядности.

Схема обработки запроса из renderer процесса будет выглядеть как-то так:
1. renderer вызывает invoke('@ipc:${fx.sid}', { params })
2. событие попадает в ipc-requests.ts, который вызывает соответствующий эффект
3. когда эффект завершает своё выполнение, ответ возвращается обратно renderer-процессу

Функция addHandlers из модуля ipc-database вызывается при инициализации, я вынес её отдельно, чтобы было удобно "подсовывать" нужную ссылку на базу данных. Я хочу еще в рантайме менять соединение с SQLite базой.

#effector #electron
💯10⚡1👍1🔥1
Использование запросов в renderer процессе

А теперь осталось обработать вызов эффекта внутри createRequest. Но будем это делать ровно так же через domain.onCreateEffect. Большая часть кода здесь — подготовка данных и обработка ответа.

Самое важное на строке 9 — вызов .invoke, который дождется ответа от процесса ipcMain. Я хотел сделать более прозрачную систему ответов, поэтому заворачиваю ответ в main процессе в try/catch. Но это не обязательно.

Note: If the handler in the main process throws an error, the promise returned by invoke will reject. However, the Error object in the renderer process will not be the same as the one thrown in the main process.

Использовать эти запросы, можно ровно так же, как и любые другие.

#effector #electron
🔥5