DOU Проектор: tabXpert – Chrome-розширення для ефективного управління вкладками
У рубриці DOU Проектор всі бажаючі можуть презентувати свій продукт (як стартап, так і ламповий pet-проект). Якщо вам є про що розповісти — запрошуємо взяти участь. Якщо ні — можливо, серія надихне на створення власної made in Ukraine продукту. Питання і заявки на участь надсилайте на [email protected] .
Всім привіт! Мене звати Андрій Кияновський, і я активний користувач інтернету з тих пір, коли він був ще по модему, а знайомство з власником BBS-борди вважалося за честь. Свою першу серйозну програму я написав в школі на СМ-2М (це комп'ютер розміром з кімнату). Потім працював девелопером, системним адміністратором, бізнесменом, менеджером проектів і зараз заробляю на життя як certified Atlassian administrator. Озираючись назад і порівнюючи задоволення від роботи девелопером і головняк від роботи менеджером, вирішив зайнятися проектом tabXpert — розширенням для управління вкладки в браузері. Проект з'явився частково як ностальгія по програмуванню, а частково як спроба зробити роботу таких же людей, як я, які проводять все життя за комп'ютером, трохи більш ефективною.
Ідея
Ви напевно стикалися з утрудненою навігацією в браузері з-за великої кількості вкладок, проблемами при падінні браузера, втратою часу на пошук в історії або керування закладками.
На ринку вже існує кілька розширень для Chrome, намагаються спростити життя активного інтернет-користувача, так чи інакше зберігаючи стан вкладки та вікна браузера. Переглянувши існуючі пропозиції, такі як OneTab, Session Buddy, Tabs Outliner, я зрозумів, що в цьому «так або інакше» і є основна проблема. Мій ідеальний менеджер вкладок повинен вміти:
- зберігати вікна автоматично в реальному часі;
- «підхоплювати» раніше закриті вікна, щоб продовжити, де зупинився;
- не створювати дублікати одного і того ж вікна, одне вікно — одна тема;
- синхронізувати дані з хмарою в реальному часі;
- мати швидкий і зручний інтерфейс.
Так що трохи почитавши і подумавши над архітектурою, я вирішив розім'яти мізки. Тим більше у мене якраз була перерва у працевлаштуванні.
Реалізація
Скоро казка мовиться, та не скоро діло робиться. Я був дуже наївним, вважаючи, що зможу здійснити цей проект за три-чотири місяці і $15-20 КОПІЙОК грошей. Вже минуло півтора року і бюджет перевищено багаторазово. Починав я один, потім знайшов приватного інвестора, і тепер у нас є ще один девелопер.
Давайте зупинимося на трьох основних завданнях, які зайняли найбільше часу:
- синхронізація в реальному часі;
- стійкість до перезапускам і падінь браузера;
- швидкий і, сподіваюся, зручний UI.
Синхронізація в реальному часі
Так як синхронізація — ключовий момент, з самого початку треба було розуміти, як ми будемо синхронізувати стану вікна з різних комп'ютерів і оновлювати його в реальному часі. Наприклад, щоб попрацювавши вдома на ноутбуці, продовжити тему на роботі і, повернувшись додому, відкрити ноутбук і продовжити з оновленим станом незакритого вікна. Варіант зберігати стан в різних «версіях» і надавати користувачеві можливість їх «менеджить» — це перекладання проблеми з хворої голови на здорову, і таке рішення майже не буде відрізнятися від існуючих реалізацій.
Стан вікна з іншого комп'ютера не вийде просто «застосувати» силу асинхронності подій, необхідно об'єднувати на рівні вкладок. Але як зрозуміти, з якого комп'ютера стан вкладки більш нове? Ідея використовувати час оновлення вкладки відразу відпала, тому що при завантаженні браузера вкладки відразу змінить зміни з віддаленого комп'ютера не будуть застосовані. Щоб не винаходити колесо, ми вирішили реалізувати three-way merge , як зроблено в Git. Перед перехопленням управління над вікном іншого комп'ютера, стан вікна зберігається як батьківське (як гілка в Git). При порівнянні двох різних «версій» одного вікна легко визначити яка вкладка змінилася, порівнюючи її стан з батьківським. У рідкісних випадках конфлікту відкривається додаткова вкладка, так що користувач гарантовано нічого не втрачає при синхронізації.
У процесі тестування ми зіткнулися з проблемою зациклення синхронізації у разі, якщо одне і те ж вікно активно на двох комп'ютерах і ви авторізуетесь на якомусь сайті. Так як на другому комп'ютері авторизації ні, це призводить до редиректу на сторінку авторизації, що на основному комп'ютері призводить до редиректу на основний URL і так по колу. Хоча ми і вирішили цю проблему для більшості випадків шляхом введення обмеження на оновлення стану вкладки в DB, для надійності була додана опція, яка просто закриє вікно, якщо ви його оновіть на іншому комп'ютері. Це не тільки саме надійне рішення, але і правильне — люди біля другого комп'ютера навряд чи зрадіють, якщо він раптом почне видавати звуки.
Для зберігання даних на клієнта (Chrome під Windows, macOS і Linux) була обрана база даних NoSQL PouchDB (сховище на IndexedDB) — тонкий клієнт для сервера на CouchDB, сильною стороною якої є синхронізація даних. База даних працює в Worker, щоб не сповільнювати UI.
Зараз синхронізація ще в розробці, сподіваємося випустити її восени 2018 р. Синхронізація буде платною (локальна версія повністю безкоштовно, без реклами і будь-яких інших способів монетизації). Приклад роботи синхронізації вкладок в різних профілях в реальному часі (синхронізація відбувається через хмару):
Стійкість до перезапускам і падінь браузера
Для уникнення появи дублікатів збережених вікон після перезапуску браузера, tabXpert повинен вміти зіставляти вікна між різними сесіями, коли включена опція Chrome, «запускати раніше відкриті вкладки». Не існує простого способу зіставити вікна в різних сесіях — не зберігається ні id вкладок, ні id вікон. Вирішили вважати хеш URL вкладок і за значенням зіставляти вікна в різних сесіях. Так як запис ДАНИХ здійснюється тільки в режимі idle (для оптимізації), миттєве збереження стану вікна, включаючи хеш вкладок, відбувається в local storage, який досить швидкий і не зберігає історію.
Основна складність полягає в тому, що існує безліч ситуацій, коли Chrome відновлює вкладки вікна частково або додає нові, наприклад:
- вкладки можуть не відновитися, якщо вони завантажувалися в момент завершення роботи браузера або при його падінні;
- вкладки можуть додаватися при старті і при відновленні після падіння браузера;
- chrome:// вкладки втрачаються, якщо відкрити раніше нормальне вікно в інкогніто-режимі.
Для вирішення цієї проблеми tabXpert виробляє зіставлення вікон старої і нової сесій, враховуючи всі можливі зміни. Для кожного вікна обчислюється два види хеш — постійна для даних, збережених у DB і миттєвий для поточного стану, збереженого в local storage. Також в local storage зберігається два стани вікна — поточний і попередній, так як іноді Chrome встигає зберегти новий стан у local storage, але відновлює при цьому попередній стан. Для вікна, яке треба зіставити після перезапуску браузера, хеш прораховується для всіх можливих варіантів змін. У разі часткового зіставлення, tabXpert відновлює відсутні вкладки. Для синхронізації поточного та збереженого вікна використовується той же механізм, що і для мережевої синхронізації.
Інтерфейс користувача
При написанні UI ми пройшли через Angular, Vue і зупинилися на React. Angular виявився занадто важким для відносно простого інтерфейсу. Vue не дуже поширений, і фахівців з нього я не знайшов. Загалом проблему вибору остаточно вирішило наявність досвідченого девелопера, який зміг вирішити всі питання з використанням React.
Клієнтська частина розширення працює на зв'язці React + Redux. За складання проекту відповідає Webpack, а транспиляцией найсвіжіших конструкцій JavaScript в робочий код займається Babel. Частина помилок в коді превентивно ловимо інструментом semistandard.
Каскадні таблиці стилів написані на улюбленому багатьма SCSS, реалізація тем оформлення — Styled Components. З коробки доступні два колірних схеми: світла і темна.
Іконки використовуються у форматі SVG, завдяки цьому вони виглядають максимально різко на екранах з високою щільністю пікселів. Так і стилізувати SVG набагато простіше, ніж шрифтові іконки.
Для реалізації більшості елементів інтерфейсу використовуємо бібліотеку компонентів React Material UI. З вирішенням проблеми повільного візуалізації великих списків нам допомогла бібліотека React List. Багатомовність реалізована з допомогою компоненти react-i18next.
Розширення має два режими роботи: у звичайній вкладці і в попапі, спливаючому при натисканні на іконку розширення на панелі інструментів Chrome або по гарячій клавіші. Для усунення постійної підвантаження і моргання favicon (DB зберігаються тільки URL) ми реалізували кешування і зберігаємо їх пам'яті у вигляді data URL. Для пошуку по вкладках використовуємо Elasticlunr.
Для прискорення швидкості завантаження попапу ми використовуємо server-side rendering, генеруючи HTML-розмітку для попапу в фонової сторінці кожен раз при зміні активного вікна. Завдяки цьому екран попапу відображається практично миттєво, після чого підвантажується основний скрипт, який додає інтерактивність.
Результат
Головний ефект від використання tabXpert — це значна економія часу, тому що замість управління вкладками ви починаєте управляти темами (вікнами браузера), решту бере на себе tabXpert. Таким чином, замість відкриття великої кількості вкладок в одному вікні, ви просто відкриваєте нове вікно для нової теми. Коли ви закінчили працювати з темою, ви закриваєте вікно. Коли хочете продовжити відкриваєте і продовжуєте, всі зміни будуть збережені в цьому ж вікні і вам для цього нічого робити не треба, все відбувається автоматично.
Коли ви працюєте з декількома вікнами, виникає необхідність швидкого перемикання між вікнами, наприклад прочитати пошту або переглянути переклад слова. Ви можете призначити гарячу клавішу на вкладку (до 9 штук), швидко на неї переключитися і повернутися назад за Alt-0. Це надзвичайно зручно.
tabXpert також допоможе вирішити проблему нестачі пам'яті при великій кількості відкритих вкладок. Вже існує досить популярне розширення The Great Suspender , яке автоматично заморожує невикористовувані вкладки, вивантажуючи їх з пам'яті (і завантажуючи, коли ви повертаєтеся на цю вкладку). tabXpert розуміє, коли вкладка заморожена, і запам'ятовує її стан. Наступного разу, коли ви відкриваєте збережене вікно, tabXpert завантажує вкладки в тому стані, в якому вони були на момент закриття вікна. Таким чином, ви не тільки заощаджуєте пам'ять, але і час, так як вікно з замороженими вкладками відновлюється набагато швидше, ніж в звичайному режимі.
Ми серйозно ставимося до конфіденційності. По-перше, розширення не має доступу до даних на вкладках, тільки до стану вкладки. По-друге, крім звичайних вікон, які будуть синхронізуватися з хмарою, існує локальний тип вікна, який не синхронізується з хмарою (і зберігається в окремій DB), і секретний тип вікна, яке взагалі не зберігається в DB. По-третє, дані, передані в хмару, будуть зашифровані ключем, сформованим від пароля користувача та випадкової солі. Таким чином, дані не будуть скомпрометовані навіть у випадку злому хмари.
Наступний хвилинний проморолик показує основну ідею tabXpert в дії:
Також є багато інших можливостей, таких як перетягування вкладок між вікнами, роз'єднання і об'єднання вікон, відкриття нормального вікна в режимі інкогніто і навпаки, тип секретності за замовчуванням для інкогніто-вікон, світла і темна теми, швидке відключення звуку, експорт і імпорт, включаючи імпорт з OneTab та Session Buddy. Є також можливість швидко скопіювати HTML-посилання вкладки (назва та URL одночасно) для того, щоб вставити її в лист або документ, як наприклад це посилання, по якій ви можете завантажити tabXpert і спробувати його в дії: tabXpert — Chrome Web Store .
У найближчих планах у нас:
- синхронізація з хмарою;
- промосайт;
- додаткові мови.
Також я подумую про інтеграцію управління закладками прямо в інтерфейс tabXpert.
А що було б цікаво вам? Пишіть у коментарях про ваші враження. Буду радий відповісти на будь-які питання.
Опубліковано: 31/07/18 @ 10:00
Розділ Різне
Рекомендуємо:
Переваги й недоліки релокації у Чехію – розповідь українця з Amazon
Android дайджест #31: Android Studio, Google Play, ML Kit
Реалізація JNI callbacks в Android NDK
В ІТ без диплома: історії JavaScript, PHP і Scala розробників
Вдосконалюємо навички через міграцію проектів: способи і приклади