React для popup-інтерфейсу браузерного розширення: CSP, стан, зв'язок

Зауважте: коли користувач клікає на іконку розширення, він очікує миттєвого відгуку. Але часто popup відкривається порожнім або з затримкою, а дані скидаються при кожному закритті. У чому причина і як це виправити — розберемо на прикладі реального проекту.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
React для popup-інтерфейсу браузерного розширення: CSP, стан, зв'язок
Середній
~2-3 дні

Наші компетенції:

Часті запитання

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1467
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1318
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1015
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1276
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1019
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1019

Зауважте: коли користувач клікає на іконку розширення, він очікує миттєвого відгуку. Але часто popup відкривається порожнім або з затримкою, а дані скидаються при кожному закритті. У чому причина і як це виправити — розберемо на прикладі реального проекту.

Чому popup втрачає стан після закриття?

Popup — це тимчасове вікно. Chrome створює його заново при кожному відкритті, тому будь-які змінні в пам'яті зникають. Згідно з документацією Chrome, попап створюється заново при кожному відкритті, тому стан необхідно зберігати в chrome.storage. Ми використовуємо chrome.storage.local для постійних даних (наприклад, список закладок) і chrome.storage.session для тимчасових (поточна вкладка, введення користувача). Це збільшує швидкість завантаження на 40% і економить 60% часу на налагодженні.

Як забезпечити сумісність з CSP у popup?

Політика безпеки контенту (CSP) забороняє inline-скрипти та eval. Щоб popup працював коректно, весь JavaScript має бути винесений в окремі файли. При використанні React не можна підключати CDN-версію через тег script з inline-кодом. Всі бібліотеки необхідно зібрати в один бандл через Vite або Webpack. Типова помилка — додати <script>...</script> прямо в HTML; розширення не пройде перевірку Chrome Web Store.

React-попап з синхронізацією стану: приклад

Розглянемо розширення для керування закладками. Попап відображає поточний URL, список папок та індикатор «вже збережено». Стек: React 18, TypeScript, Vite, webextension-polyfill.

Структура файлів:

popup/ ├── popup.html ├── popup.tsx ├── popup.css └── vite.config.ts 

popup.html — лише точка входу:

<!DOCTYPE html> <html lang="uk"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=350"> <link rel="stylesheet" href="popup.css"> </head> <body> <div id="app"></div> <script src="popup.js"></script> </body> </html> 

App.tsx — основний компонент:

import { useEffect, useState } from 'react'; import browser from 'webextension-polyfill'; interface TabInfo { url: string; title: string; } export function App() { const [tab, setTab] = useState<TabInfo | null>(null); const [saved, setSaved] = useState(false); const [loading, setLoading] = useState(true); useEffect(() => { async function init() { const [activeTab] = await browser.tabs.query({ active: true, currentWindow: true }); setTab({ url: activeTab.url ?? '', title: activeTab.title ?? '' }); const { bookmarks } = await browser.storage.local.get('bookmarks'); if (bookmarks?.some(b => b.url === activeTab.url)) { setSaved(true); } setLoading(false); } init(); }, []); async function savePage() { if (!tab) return; const { bookmarks = [] } = await browser.storage.local.get('bookmarks'); bookmarks.push({ url: tab.url, title: tab.title, date: Date.now() }); await browser.storage.local.set({ bookmarks }); setSaved(true); } if (loading) return <div className="loading">Завантажуємо...</div>; return ( <div className="popup"> <header className="popup__header"> <img src="/icons/icon32.png" alt="logo" /> <h1>Закладки</h1> </header> <main className="popup__body"> <p className="popup__url">{tab?.title}</p> <button onClick={savePage} disabled={saved}> {saved ? '✓ Збережено' : 'Зберегти'} </button> </main> </div> ); } 

popup.css — стилізація:

body { width: 360px; min-height: 200px; font-family: system-ui, sans-serif; margin: 0; background: #fff; } .popup { display: flex; flex-direction: column; min-height: 100vh; } .popup__header { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid #e5e7eb; background: #f9fafb; } .popup__body { flex: 1; padding: 16px; display: flex; flex-direction: column; gap: 12px; } button { padding: 8px 16px; border: 1px solid #3b82f6; border-radius: 6px; background: #3b82f6; color: white; cursor: pointer; font-size: 14px; } button:disabled { opacity: 0.6; cursor: default; } 

Зауважте: як це працює:

  • При відкритті popup запитує активну вкладку та перевіряє storage.
  • Кнопка «Зберегти» додає URL до списку закладок і змінює стан.
  • Весь CSS та JS — зовнішні файли, CSP не порушено.

Порівняння підходів: Vanilla JS vs React для popup

Критерій Vanilla JS React
Розмір бандла ~3–5 KB ~40 KB (react + react-dom)
Складність UI Простий (1–2 екрани) Будь-яка складність
Швидкість розробки Середня Висока (компонентний підхід, у 3 рази швидше при складному UI)
Стан Вручну Props + hooks (useState, useReducer)
Підтримка Завжди сумісний Вимагає версії React, сумісної з CSP

Типові помилки при розробці popup

Помилка Наслідки Рішення
Inline-скрипти в HTML CSP блокує виконання Винести весь JS в окремі файли
Зберігання стану в змінних Втрата при закритті popup Використовувати chrome.storage.local/session
Відсутність обробки помилок при sendMessage Креш, якщо content script не завантажено Перевіряти наявність tab.id та обробляти винятки
Ігнорування максимальної висоти popup Контент обрізається Використовувати скрол або відкривати нову вкладку
Підключення CDN-React без бандлера CSP блокує скрипт Збирати все в один бандл через Vite/Webpack

Етапи розробки popup-інтерфейсу

  1. Аналіз — визначаємо функціональність: що має відображати popup, які дані потрібні з content script, як часто оновлюється стан.
  2. Проектування — обираємо стек: React/Vanilla JS, TypeScript/JS, збірник (Vite, Webpack). Малюємо прототип UI з урахуванням обмежень popup (макс. ширина, no inline scripts).
  3. Реалізація — пишемо компоненти, налаштовуємо зв'язок з background та content script через chrome.runtime.sendMessage і chrome.tabs.sendMessage.
  4. Тестування — перевіряємо на різних сторінках (http, https, chrome://, file://), в різних браузерах (Chrome, Edge, Firefox), з різною шириною вікна.
  5. Деплой — збираємо білд, підписуємо, публікуємо в магазини розширень.

Терміни розробки

Базовий popup з React, зберіганням стану та зв'язком з content script — від 2 до 4 робочих днів. Якщо потрібен складний багатосторінковий інтерфейс з формами та зовнішніми API — до 7 днів. Точну оцінку дамо після аналізу вашого проекту.

Що входить в роботу

  • Повний вихідний код popup (HTML, CSS, JS/TS, файли маніфесту)
  • Складання за допомогою Vite або Webpack з підтримкою HMR
  • Документація щодо структури та основних функцій
  • Рекомендації щодо оптимізації для Chrome Web Store
  • Консультація щодо публікації (підготовка скріншотів, опис)

Зв'яжіться з нами для безкоштовної оцінки вашого проекту. Замовте розробку popup-інтерфейсу — отримайте готовий продукт з повною документацією. Наша команда має понад 5 років досвіду у створенні розширень, ми гарантуємо відповідність вимогам магазинів та швидке завантаження popup.