Если у вас есть компьютер и вы используете его по назначению, то скорее всего вы так или иначе работали с приложениями на Electron (даже если об этом не знали).
Меня зовут Сергей Володин, я руковожу командой разработки VK WorkMail. Расскажу, как на основе Electron мы за две недели создали PoC кроссплатформенного настольного приложения Почты, что узнали о технологии и к каким выводам пришли.
Для начала немного контекста. Наша команда занимается продуктовой разработкой VK WorkMail — корпоративного почтового сервиса, доступного по модели SaaS и в виде On-Premise решения. Продукт существует как мобильное приложение для Android/iOS, в web-версии, а также как один из элементов суперприложения VK Teams. У нас единая кодовая база с Почтой Mail.ru и VK Почтой.
Мы работаем на B2B-рынке и время от времени получаем от наших клиентов запросы на настольное приложение. Это не что-то вроде «Хотим отдельную иконку, а не браузер», а запрос на вполне серьёзную функциональность: возможность работать оффлайн, локальную выгрузку или удаление писем с сервера. Другими словами — запрос на создание Thick Client, или толстого клиента.
Что значит толстый клиент?
Сначала нужно договориться о понятиях. Большинство web-приложений работают по принципу тонкого клиента (Thin Client). Подобный подход представляет из себя классическое клиент-серверное взаимодействие:
Клиент, то есть интерфейс или фронтенд, шлёт запросы на сервер и получает необходимые для работы данные.
Но если говорить про работу с почтой в оффлайне или, как в нашем случае, работу с данными на устройстве пользователя, то нам необходим толстый клиент, который обеспечивает необходимую функциональность независимо от работы сервера.
Как мы пришли к идее завернуть наше web-приложение в Electron?
В компании уже проводили расчет трудозатрат на запуск полноценного сервиса с оффлайн-функциональностью. Мы рассматривали offline-first подход в web-версии клиента с применением IndexedDB в качестве хранилища и Service Worker как средство кеширования статики. Однако мы пришли к выводу, что потребуется проводить значительный рефакторинг всего клиентского кода с потенциальными трудозатратами в человеко-год.
Более того, сделать по-настоящему настольное приложение силами одного лишь фронтенда не получится. Всё дело в ограниченности браузера при работе с локальной файловой системой.
Одна из главных функций настольного почтового сервиса — локальная архивация писем. Приложение должно уметь выгружать письма в виде архива или файла, а также читать и предоставлять пользователю полноценный доступ к ним. Формально можно загружать такие файлы в браузер, парсить и раскладывать в IndexDB. Но поскольку архивы могут быть большого размера, это заметно снизит производительность. Другое дело — иметь полноценный доступ к файловой системе.
Размышляя об этой задаче, мы решили посмотреть на неё с другой стороны: можно ли решить нашу проблему, вообще не трогая логику web-клиента? Ведь мы не меняем интерфейс, пользователь видит все те же кнопки и визуальные компоненты. Функциональность, которая нам требуется, это совсем не про UI, а про локальную, то есть не серверную, бизнес-логику. Для наглядности размышлений, посмотрим на схему толстого клиента. Отмечу, что речь именно про клиент, поэтому серверная часть будет показана в упрощенном виде:
Здесь мы разделяем клиент на две функциональные части:
UI. По-сути, просто наше web-приложение, тонкий клиент. То есть интерфейс, который отвечает за отрисовку и запрашивает необходимые данные через запросы.
Local business logic (далее LBL). Здесь уже интереснее. Если в тонком клиенте за данными мы ходим напрямую на сервер, то в толстом клиенте — в специальный модуль LBL. Это может быть специальный процесс или отдельный модуль программы. Важно то, что он имеет у себя данные и отвечает за их отправку в UI. Также он отвечает за синхронизацию с сервером.
Как видно на этой схеме, если сервер недоступен, то клиент всё ещё сможет спокойно работать с данными. Более того, это будет не просто режим «только чтение», клиент также сможет совершать и более сложные действия с точки зрения бизнес-логики. Например, написать новое письмо или создать фильтр для писем. И как только почтовый сервис получит доступ к серверу, действия будут синхронизированы.
Оперируя изложенной выше логикой, мы пришли к идее провести эксперимент по упаковке web-приложения в оболочку для толстого клиента. Мы решили проверить, сможем ли использовать технологии, подходы и компоненты из web-версии и серверной части для создания полноценной настольной версии VK WorkMail. Суть эксперимента — быстро проверить гипотезу. Поэтому мы выделили на него сравнительно мало ресурсов: две человеко-недели (одна фронтендера и одна бэкендера). В конечном итоге нам было необходимо получить PoC (Proof of Concept) или, если угодно, MVP настольного приложения VK WorkMail.
Проектирование и выбор технологий
Перед тем как приступать непосредственно к коду, мы провели сравнительный анализ нескольких подходов. Взяли Native UI, Qt Framework и Electron и занесли их в таблицу.
Технология |
Примени-мость для web |
Кроссплат-форменность |
Потребление памяти |
Занимает на диске |
Производи-тельность |
Время на разработку и сопро-вождение |
---|---|---|---|---|---|---|
Native UI |
- |
- |
мало |
мало |
идеально |
очень много |
QT |
- |
+ |
средне (~ 130 Мб) |
средне (~ 70,8 Мб) |
хорошо |
много |
Electron |
+ |
+ |
много (от 200 Мб до гигабайтов) |
много(не меньше 150 Мб) |
медленно |
немного |
Native UI, возможно, один из лучших вариантов с точки зрения пользовательского опыта. Но наш сервис по умолчанию должен быть кроссплатформенным, а Native UI предполагает разработку отдельной реализации для каждой ОС, то есть как минимум трёх: MacOS, Windows, Linux. Другая проблема заключается в том, что UI VK WorkMail — это довольно сложный с точки зрения дизайн-системы проект. Интерфейс содержит в себе много кастомных компонентов, которые придётся реализовать нативно, что также замедлит разработку.
Следующий вариант — Qt. На бумаге выглядит хорошим и сбалансированным решением для создания настольного приложения. Однако нам в любом случае пришлось бы создать с нуля ещё одну версию приложения и поддерживать её параллельно с web-версией. Очевидно, это не слишком вписывается в концепцию нашего эксперимента.
Поэтому наш взор неизбежно пал на Electron. Кроссплатформенный, с открытым исходным кодом и построенный на web-технологиях. А также медленный (в сравнении с нативными приложениями) и требовательный по ресурсам (в два и более раза по сравнению с тем же Qt). Даже беря во внимание возможные недостатки, в нашей ситуации это был фактически единственный вариант создать настольное приложение командой web-разработчиков.
Для более подробного погружения в тему выбора технологий для создания настольного приложения и более подробного их сравнения советую ознакомиться со статьёй «Почему Electron это необходимое зло» на английском языке.
Выбор технологии для LBL-компонента
Если с UI всё более менее понятно — там будут использованы технологии из нашей web-версии, — то с LBL всё интереснее. Это, без сомнений, сердце нашего технического решения. С одной стороны, Electron way — это реализация функциональности внутри процесса Electron, то есть де-факто в NodeJs. Однако в таком случае нам придётся писать всю необходимую логику (возможно, дублирующую её же с сервера) заново, силами JS-программистов.
Есть также другой подход, часто применяемый в настольной разработке: вынесение кроссплатформенной core-части, отвечающей за бизнес-логику (то, что я называю LBL в этой статье) в отдельный модуль и процесс. Такой путь актуален при разработке интерфейса с Native UI-подходом, поскольку в этом случае необходимо использовать свой фреймворк под каждую ОС. Часть, отвечающая за бизнес-логику, пишется один раз и в дальнейшем используется вновь.
Так вот к чему я это всё? У нас уже есть серверная часть Почты, написанная на Go. Поскольку перед нами сейчас стоит задача написать модуль, который будет выполнять различную бизнес-логику на клиенте, то было бы неплохо использовать код сервера.
Мы решили пойти по второму пути и писать LBL-компонент на Go. Принимая это решение, руководствовались следующим:
Нас привлекала потенциальная возможность использовать серверный код Почты. «Зачем переписывать бизнес-логику работы с письмами на JS, если она уже написана на сервере?»
Также это возможность распараллелить разработку, пока фронтендеры будут заниматься настройкой Electron, бэкендеры — писать LBL. С точки зрения использования ресурсов, это казалось более правильным путём в full-stack команде, которой я руковожу.
При разработке LBL нас ждали сюрпризы и неожиданности, но к ним мы вернёмся чуть позже.
Проектирование UI-компонента
Итак, мы выбрали Electron ради использования наработок нашей web-версии Почты. Давайте посмотрим в общих чертах, как работает наше (а вообще говоря, практически любое) web-приложение:
Когда пользователь заходит на страницу, отправляется get-запрос, который принимает фронтенд-сервер. Внутри сервера есть SSR-сервис, который отвечает за генерирование HTML для пользователя, у нас это NodeJS. Для того, чтобы сгенерировать уникальный HTML с пользовательскими данными, необходимо получить серверные переменные, которые мы получаем в специальном сервисе Config. Далее возвращаем пользователю HTML, в котором вшиты необходимые пользовательские данные, конфиги и т.д. Там же уже вшиты ссылки на разные статические файлы, необходимые для работы приложения: наши любимые JS-бандлы, CSS, картинки и много чего ещё.
В контексте Почты необходимо упомянуть, что мы используем архитектуру микрофронтендов, то есть большинство кусков приложения подгружается по мере необходимости во время работы приложения. Другими словами, когда пользователь открывает VK WorkMail у него грузится необходимый код для отображения списка писем. Далее, если пользователь хочет написать письмо, создать папку или зайти в адресную книгу, то ему асинхронно подгружаются JS/CSS-бандлы из нашего CDN с необходимыми UI и функциональностью.
Собственно, нашей основной задачей на фронте было засунуть всё это великолепие в Electron. Статичные файлы нужно было положить внутрь приложения, локально, и тогда они начали бы подгружаться как прежде, но уже не из CDN, а из файловой системы. Но вот с генерированием HTML с серверными переменными — вопрос. Electron way — это сделать относительно статичный HTML и вынести логику получения всех необходимых данных на клиентскую часть. Но это означало бы значительный рефакторинг core-части приложения, и для PoC за пару недель это не подходит.
Немногим позже мы поняли, что, по сути, уже запускаем наше приложение локально со всем SSR и прочим, когда стартуем dev-сервер для разработки функциональности:
Разработчик запускает dev-server (у нас это webpack), который перед тем как исполнить серверный шаблон ходит за данными на сервер, а затем результат в виде HTML возвращается в браузер. Мы решили взять эту схему для Electron, но за серверными данными ходить уже в локальный Go-модуль. А всё остальное-то у нас уже есть!
Финальное техническое решение
Итак, объединив всё наше предыдущее проектирование мы пришли к следующей схеме:
У нас есть процесс Electron, он отвечает за запуск приложения, интеграцию с ОС и прочие вещи, важные для настольного приложения. Вместе с этим процессом запускается и NodeJS-сервер (SSR Service) на localhost, и который поднимается внутри Electron. Также во время старта он форкает процесс и запускает Go-сервис, который в свою очередь уже работает с локальной базой (SQL-lite) и синхронихируется с сервером по HTTP. Также на файловой системе у нас лежат разные статичные asset’ы, которые нужны для работы приложения и запросы за которыми будут проходить через NodeJS-сервер, поднятый внутри Electron.
Разработка PoC
Мы не будем подробно разбирать каждую строчку кода, но постараемся кратко подсветить самые интересные и основные моменты в хронологическом порядке.
Разработка основной части Electron
Разработка началась с создания чистого репозитория. Мы завели в нем директорию packages
, в которую планировали положить все необходимые asset’ы для работы приложения: серверные шаблоны, статичные, собранные и минифицированные JS, CSS, изображения и так далее. Далее по README Electron:
npm i electron electron-builder
Затем создаём index.js
и погнали (в примерах может быть не совсем валидный код ради удобочитаемости и подчёркивания главных моментов):
const {app, BrowserWindow, shell} = require('electron');
const config = require('./config');
const {spawn} = require('child_process');
const server = require('./server');
function createWindow() {
const mainWindow = new BrowserWindow({
width: config.defaultWidth,
height: config.defaultHeight,
center: true,
});
// запускаем гошный локальный АПИ
spawn(`./${config.goModulePath}`, ['-config', `${config.goModulePathConfig}`], {stdio: 'inherit', cwd: __dirname})
// запускаем статик-сервер для генерации HTML и раздачи статики
server.run(config.port, () => {
mainWindow.loadURL(`http://localhost:${config.port}/`);
// открываем ссылки (например внутри писем), в дефолтном браузере, а не в электроне
mainWindow.webContents.setWindowOpenHandler(({url}) => {
if (url.startsWith(config.fileProtocol)) {
return {action: 'allow'};
}
shell.openExternal(url);
return {action: 'deny'};
});
});
}
app.whenReady().then(createWindow);
В принципе, этого кода более чем достаточно, чтобы открыть окно на Electron и увидеть белый экран. В дальнейшем появятся нюансы открытия и закрытия окон в MacOS и прочие «доработки», сосредотачиваться на которых в этой статье нет смысла.
Авторизация
Как только мы запустили окно Electron, вскрылась проблема, которую мы не учли при проектировании — авторизация. В web-версии VK WorkMail используется классический вариант с куками, но в настольной версии это не будет работать. У нас есть мобильные приложения, которые работают на сессионных токенах, и мы решили использовать их. Однако есть нюанс: мобильные приложения имеют собственные формы логина. Мы не стали делать новую форму в PoC, а выбрали другое решение, которое оказалось даже более приятным с точки зрения пользовательского опыта: прокинули авторизацию из браузера в наше приложение через OAuth. Схема такая: пользователь нажимает в Electron кнопку авторизации, у него открывается окно браузера, и если он в нём уже был авторизован, пользователь просто нажимает кнопку «Войти» у нужного ящика, и приложение всё остальное делает за него. Получилось примерно вот так:
Вы можете задаться вопросом, как получилось пробросить информацию из браузера в настольное приложение? Основная хитрость тут в том, что redirect_url на который перенаправляет OAuth-провайдер, должен вести на localhost на нужный порт или на специальную схему, которую слушает, в нашем случае, LBL и уже принимает токен авторизации.
Также вам может стать интересно, как LBL сообщает UI, что ему нужно перезагрузить страницу и что авторизация уже есть. Для этого мы при открытии браузера открываем SSE-соединение (Server Side Events) с UI в LBL и ждём события, что авторизация получена. Обратить внимание на SSE-подход, потому что мало кто знает, что существуют альтернативы вебсокетам для получения запросов и событий с сервера. Вот код:
const link = document.querySelector('#auth-link');
link.addEventListener('click', (e) => {
e.preventDefault();
// генерируем случайную строку для OAuth state параметра
const state = (Date.now() * Math.random()).toString(16);
// открываем соединение с Go модулем LBL
const eventSource = new window.EventSource(`http://localhost:${config.goModulePort}/subscribe_oauth?state=${state}`);
// добавляем обработчики для работы с eventSource
eventSource.addEventListener('message', (event) => {
console.log('eventSource: new message', event.data);
if (event.data === 'success') {
eventSource.close();
location.reload();
}
});
eventSource.addEventListener('error', (event) => {
console.log('error', event);
});
eventSource.addEventListener('open', () => {
console.log('eventSource: open connection');
window.open(link.href += state, '_blanc');
});
});
Если вы хотите больше узнать про OAuth, то рекомендую почитать эту статью.
Сбор всех статичных asset’ов (JS, CSS и изображений) в файловую систему
После того, как вопросы с авторизацией и исполнением серверного шаблона были решены, потребовалось перенести все необходимые для работы приложения файлы на локальную файловую систему. Настроить Node Static Server, чтобы отдавать файлы с файловой системы, — это не проблема. Но собирать десятки файлов и класть их локально вручную — не самое интересное занятие. А лень, как известно, двигатель прогресса. Поэтому мы воспользовались концепцией, распространённой в web-приложениях с service worker’ом: загрузкой статичных asset’ов, когда их нет в кеше. Я добавил такой код в свой express-сервер:
app.use('/static', (req, res, next) => {
//проверяем есть ли файл уже в файловой системе
const fileName = `${STATIC_DIR}/${req.path}`;
// синхронно ходить на fs плохо, но этот код вырезается из production сборки
if (!fs.existsSync(fileName)) {
log('file not exists', req.path);
const extname = path.extname(fileName);
proxy.request(
{
url: `https://${config.staticUrl}/${req.path}`,
encoding: binaryMap[extname] ? null : 'utf8', // важно не текстовые форматы правильно кодировать
req,
},
(err, result, body) => {
console.log(result);
fse.outputFileSync(fileName, body, binaryMap[extname] ? 'binary' : 'utf8');
next();
})
} else {
return next();
}
});
app.use('/static', express.static(STATIC_DIR));
За одно открытие VK WorkMail я собрал в файловой системе все необходимые файлы, а в production этот app.use
уже не пошёл.
Адаптация интерфейса под работу в «одной вкладке»
Далее, когда мы наконец смогли авторизоваться и отрисовать наше приложение, важно понимать, что пользовательский опыт использования браузерного приложения сильно отличается от настольного. В браузере совершено нормально в процессе работы открывать новые вкладки, переходить на совершено другой сайт по ссылке из вашего приложения, оставаясь в той же вкладке. Когда же мы переносим Почту в настольное приложение, необходимо адаптировать интерфейс под работу «в одной вкладке». Мне повезло, что Почта уже умеет интегрироваться в суперприложение для рабочих коммуникаций VK Teams с помощью WebView, поэтому я просто использовал режим работы Почты оттуда. Подробнее узнать про эту адаптацию можно из доклада на VK Tech Talks моего коллеги Дениса Романюка.
Разработка LBL-модуля на Go
Для PoC было решено в LBL-модуле поддержать полностью read-режим работы, а также поддержать одно write-действие: локальное изменение флажков у писем и их синхронизацию с сервером при наличии сети. То есть мы не поддерживали все функции сервиса локально, а только полностью поддержали чтение и одно из действий, требующих изменение данных с сервера. Этого достаточно для проверки всех наших гипотез и проведения эксперимента.
В качестве базы для локального хранения писем мы взяли SQLite. В качестве веб-фреймворка — Echo, создали в нём отдельные обработчики для взаимодействия с UI Electron и один общий, который обрабатывает запросы к серверу Почты.
Результат разработки
Мы сделали PoC настольного почтового толстого клиента за две недели: одну неделю фронтендер создавал всю обвязку на Electron и в части с UI, и ещё неделю бэкендер писал модуль на Go.
У нас получилось повторно использовать интерфейс web-версии Почты, при этом с помощью общения с LBL в Go мы смогли в оффлайне предоставить чтение писем и изменение состояния флажков на письмах.
Выводы об R&D
Первоочередной целью для нас было проверить, возможно ли создать настольное приложение на существующей кодовой базе web-приложения. И мы в хорошем смысле поражены, как легко это получилось с помощью Electron. На вопрос: «Использовали бы вы Electron для создания production ready настольного приложения?» мы ответим — да. Эта технология определённо снижает порог входа в разработку настольных приложений.
Однако с написанием LBL-модуля на Go всё оказалось не так хорошо.
Во-первых, идея была в том, что мы сможем использовать какую-то логику из нашей серверной кодовой базы на Go, но, как оказалось, практически ничего применить не получилось, бизнес-логика в толстом клиенте сильно отличается от таковой на сервере.
Во-вторых, отдельный процесс увеличивает риск возникновения потенциальных проблем и багов, которые будет сложно устранить. Что делать, если в Go-модуле произошла паника? Нужно в JS внутри Electron это обрабатывать и перезапускать процесс. Также есть разные нюансы с тем, как операционные системы поступают с процессом приложения при сворачивании или закрытии окна (особенно Mac OS), и вводя дополнительный процесс, которым нужно вручную управлять, мы умножаем сложность работы с этим.
Ну и наконец межпроцессное взаимодействие. Нам нужно общаться между UI, Electron (Node) и LBL. И реализация взаимодействия между Node и Go по любым сетевым протоколам может значительно влиять на производительность.
В итоге, если бы мы делали production ready-решение, то писали бы бизнес-логику и работу с локальной базой данных внутри NodeJS-процесса Electron.
Напоследок хочу сказать пару слов о фронтенд- и web-разработке. Технологии и требования к приложениям сменяются так быстро, что устойчивые и выверенные практики их создания не успевают появляться. Тем не менее я с предвкушением ожидаю будущее фронтенд- и web-разработки.
Web-приложения запускаются как с браузеров на компьютере и телефоне, так и на Smart TV, чайниках, зубных щётках и телескопов. И Electron, безусловно, одна из технологий, которые вносят вклад во всё это.
Комментарии (31)
SuperTEHb
30.09.2022 10:45+8Ну вот опять. Побыстрее и попроще разработать, а уж как оно будет работать это проблемы пользователей.
vileven Автор
30.09.2022 11:15Никто на пользователей же ничего не запускал :)
Цель была как раз проверить наши гипотезы в R&D и поделиться опытом.
А теперь этот прототип пойдёт в UX тестирование, чтобы получить фидбек от тестовых групп, затем будут приниматься дальнейшие решения.
hardtop
30.09.2022 11:08А flutter рассматривали? Легче и быстрее электрона
yroman
30.09.2022 11:14+3Я так понимаю, что даже если писать на флаттере, UI часть все равно нужно писать с нуля, а этим ребятам важно побыстрее выкатить рабочий вариант. То, что оно будет кривое, косое и жручее, их не сильно волнует.
vileven Автор
30.09.2022 11:19+1Flutter рассматривали, да. Для нас он был в одной категории с Qt примерно. Переиспользовать существующий UI нельзя, но вариант привлекательный. Возможно, в дальнейшем попробуем провести R&D с ним уже :)
RealFLYNN
30.09.2022 11:25Если не охота ковырять Dart, то лучше посмотреть в сторону Tauri - пишем основной процесс на Rust/C++/чем угодно (для чего есть биндинги), фронтенд на любимом JS-стеке. На выходе получаем легкий бинарник, который вертит свой UI в нативном для системы WebView, без хромиума и V8
vileven Автор
30.09.2022 11:32Думали о решениях с нативным WebView тоже. Там нас немного отталкивали потенциальные проблемы с разными ОС и их версиями (WebView API не везде одинаковый, и там много раз нюансов есть).
Взяли пока Электрон как раз по той причине, что казалось, что поскольку там хромиум внутри — мы уверены, что наше приложение точно будет работать везде и именно так, как мы ожидаем. НО да, расплата — его объём.
В целом, в будущем, может быть погрузимся в эту тему глубже, спасибо за комментарий :)
Sazonov
30.09.2022 11:44+270 метров Qt? Это у вас на 50 метров иконок? Рантайм Qt, если вам достаточно UI+сеть+SQLite ужимается до ~13-20 мегабайт.
vileven Автор
30.09.2022 16:39-1не эксперт в Qt и не буду спорить (скорее всего Вы правы!), информацию брал из открытых источников (может ошибся). В статье она нужна больше для сравнительного порядка, чем для точной цифры, поэтому тщательно не проверял :)
Sazonov
01.10.2022 00:11Ну да. 5-7 порядков. Если что, Qt уже достаточно хорошо умеет в WebAssembly :)
Единственный минус - цена лицензий. Но для такой компании это не должно быть проблемой. Хотя вру, ещё есть санкции, но вполне можно заюзать LGPL версию.
AlexeyK77
30.09.2022 11:50+7говорят, что для разработчиков на электроне сталелитейни в аду разработали особый проект котла. Он очень быстрый в проектировании отливке, быстро можно выкатить первый котел в продуктив по мере появления их востребованности. Но есть у котлов особенность, очень толстые стенки, из-за чего даже по окончанию срока прожарки и отключения подачи магмы и серы в систему нагрева, то за счет огромной теплоемкости котел еще будет долго-долго отдавать жар на максимуме теплоотдачи. ;)
le2
30.09.2022 13:09давно под Линуксом использую Visual Studio Code, который, как известно, на Электроне. Отлично работает (почти. Пару раз завешивал мне десктоп)
AlexeyK77
01.10.2022 10:59-1Вот и черти из R&D отдела тоже так рассудили. технология рабочая, хоть и тяжеловатая для юзера, но все формально соответствует ТЗ и главное выкатили в короткие сроки. Как никак у них там сейчас жуткий кранч под новые срочные задачи, связанные с необходимость обеспечить масштабирование сервисов из-за прогнозируемого возрастания загрузки.
savostin
30.09.2022 11:57А можно хоть немного подробностей как реализовывали синхронизацию SQLite с сервером?
vileven Автор
30.09.2022 16:44+1У нас было только одно write действие, поэтому мы сделали очень просто: при наличии интернета мы сразу идём на сервер, а при отсутсвии изменяем локально + добавляем в специальную очередь событий пользователя, которая процессится при появлении интернета. Мы не сильно беспокоились о всех возможных кейсах, так как делали просто прототип.
Возможно вам интересен момент: "Что делать, если на сервере, пока на клиенте не было интернета, произошло что-то еще?" и всякие такие подобные колизии. Если кратко — то всегда доверять серверу, но лучше почитать непосредственно про подобные приложения отдельно, на том же хабре. Таких приложений много, особенно в мобильной и десктопной разработке.savostin
30.09.2022 17:15Спасибо. Меня больше интересует "протокол". Т.е. на сервере есть API, которое дергается из клиента? Какие-то самописные команды или есть какой-то фреймворк/либа? Если просто флаг обновить, то возможно простого запроса к скриптику и хватит, а вот если много всяких разных данных, структур и пр? Как "взрослые" делают offline first синхронизацию с SQL(ite) локальным хранилищем?
vileven Автор
30.09.2022 17:51+1Да сервер, в данном случае тот же самый сервер, который отдаёт данные для web-версии и мобильных приложений. У нас аля REST API.
По поводу синхронизации, попробуйте покопаться вглубь CQRS (Command and Query Responsibility Segregation) — обычно этот паттерн используется в offline first системах. Предупреждаю, это на самом деле все очень непросто :)savostin
30.09.2022 18:12Спасибо. Вот и я понимаю, что простого решения нет. Каждый изобретает свой велосипед...
avdosev
30.09.2022 17:59Сколько в итоге потребляет это приложение? Интересно сколько получилось для такого исследовательского решения.
RaymanOne
01.10.2022 16:04Надо было просто сделать PWA, и опубликовать его в магазин MS если есть такая необходимость. А вообще скорее всего лучше бы подошел Tauri
ZoomLS
01.10.2022 16:10+1. Tauri - это то, каким должен быть электрон. А не это недоразумение, что сейчас.
RaymanOne
01.10.2022 17:01Не увидел специфических API, тем более на десктопе их куча для веба доступно. Подошло бы PWA. Одна кодовая база с браузерной версией, оффлайн режим, все тоже самое. Не пришлось бы городить какие-то electron обертки, а авторизация бы УЖЕ была, если юзер авторизован в браузере был.
vileven Автор
01.10.2022 18:46Я пишу, почему нельзя было сделать PWA в статье. Проблема именно в том, что один из основных запросов клиентов – выгрузка части писем локально (не в базу, а прям файлом) и взаимодействие с ними. Собственно поэтому и нужен толстый клиент и полноценная работа с файловой системой.
RaymanOne
01.10.2022 18:50На сколько у вас толстые письма? Не изучали возможности indexeddb? Вы знаете что на десктопе у веба практически не ограниченный размер там?
vileven Автор
01.10.2022 19:56Про это есть в статье) Речь же ещё была про попытку заюзать уже готовый северный код на Go.
Про размер: гигабайты (возможно десятки их). Совершенно легко может быть кейс — выгрузить локально весь ящик за последние N лет со всеми аттачами и файлами в письме. Нам не нравилась история с загрузкой всего этого добра в браузер и перекладка в IndexedDB и обратно (Хотя, в статье я пишу, что это возможно конечно).
Я сам готов бесконечно евангилировать за PWA и весь веб-стэк.
Но наш эксперимент пошёл по-другому пути и я много уделяю внимания в тексте, чем мы руководствовались. Я вообще не претендую на то, что выбранные технологии — это самый лучший выбор из возможных. Это больше "вот мы взяли это, попробовали сделать PoC, вот что у нас получилось и к каким выводам мы пришли".
RaymanOne
01.10.2022 21:47Go скорее всего получилось бы использовать в Wasm модуле. Загрузку можно было организовать через воркер, в приложение уже отдавать готовые ответы сетевые. Жаль что для эксперимента не взяли тогда tauri, если в рамки PWA боялись не вписаться. Electron нужно активно хоронить, уже не одна хорошая альтернатива ему есть.
RaymanOne
01.10.2022 23:25Как вариант можно было бы попробовать поработать с https://web.dev/file-system-access/#opening-a-directory-and-enumerating-its-contents В общем не очень понял в чем в итоге был эксперимент...
AlexeyK77
коммент не в тот пост..(удалено)