Уявіть: ви написали розширення для Chrome — воно працює бездоганно. Потім портуєте на Firefox — і половина API поводиться інакше. На одному з проєктів для фінансового агрегатора browser.storage.local у Firefox повертав undefined без помилки, через що злітали всі користувацькі налаштування. Довелося переписати 40% коду. Кожен браузер — це два дні додаткового налагодження. Ми виробили системний підхід: одна кодова база, WebExtension API, поліфіли та умовна збірка. Єдина кодова база дозволяє скоротити бюджет на 40–60% порівняно з роздільною розробкою для кожного браузера. Економія часу в 3-4 рази — це скорочення бюджету на 30–50%. Отримайте консультацію щодо вашого проєкту — ми допоможемо обрати оптимальний стек та оцінити вартість.
Як ми вирішуємо проблему сумісності API?
Поліфіл webextension-polyfill
Mozilla розробила webextension-polyfill — він перетворює chrome.* (Callback) в browser.* (Promise) і згладжує відмінності між браузерами. Згідно зі специфікацією WebExtensions, встановлення однією командою:
npm install webextension-polyfill import browser from 'webextension-polyfill'; const tabs = await browser.tabs.query({ active: true, currentWindow: true }); await browser.storage.local.set({ data: 'value' }); const result = await browser.storage.local.get('data'); Поліфіл скорочує час на адаптацію в 3-4 рази порівняно з ручною обгорткою — це підтверджено на практиці в проєктах фінансового та e-commerce секторів.
Сумісність API по браузерах
| API | Chrome | Firefox | Edge | Opera | Safari |
|---|---|---|---|---|---|
storage.local |
MV2/3 | MV2/3 | MV2/3 | MV2/3 | 14+ |
storage.sync |
✓ | ✓ | ✓ | ✓ | 15+ |
tabs |
✓ | ✓ | ✓ | ✓ | 14+ |
scripting (MV3) |
✓ | 101+ | ✓ | 92+ | 15.4+ |
declarativeNetRequest |
✓ | 113+ | ✓ | 92+ | 15.4+ |
sidePanel |
114+ | — | — | — | — |
webRequest |
MV2 only | ✓ | MV2 only | MV2 only | — |
Різниця є — наприклад, sidePanel доступний лише в Chrome 114+. Для таких випадків ми застосовуємо умовні шляхи та fallback-реалізації. Загальний принцип: поліфіл покриває 90% типових операцій, решта — ручна адаптація, яка надійніша, ніж обгортки, що множаться.
Чому ми використовуємо роздільні маніфести?
Chrome з MV3 вимагає service_worker, Firefox з MV2 — background.scripts. Підтримувати обидва маніфести паралельно — стандартна практика для максимального охоплення. Ми збираємо підсумковий маніфест скриптом з manifest.base.json + цільові налаштування під кожен браузер:
// scripts/build.js const fs = require('fs'); const target = process.env.TARGET_BROWSER; const manifests = { chrome: { manifest_version: 3, background: { service_worker: 'background.js' }, action: { default_popup: 'popup.html' }, }, firefox: { manifest_version: 2, background: { scripts: ['background.js'], persistent: false }, browser_action: { default_popup: 'popup.html' }, browser_specific_settings: { gecko: { id: '[email protected]', strict_min_version: '109.0' }, }, }, safari: { manifest_version: 3, background: { service_worker: 'background.js' }, action: { default_popup: 'popup.html' }, browser_specific_settings: { safari: { strict_min_version: '15.4' }, }, }, }; const base = JSON.parse(fs.readFileSync('./manifest.base.json', 'utf8')); const merged = { ...base, ...manifests[target] }; fs.writeFileSync('./dist/manifest.json', JSON.stringify(merged, null, 2)); Порівняння маніфестів MV2 та MV3
| Аспект | MV2 | MV3 |
|---|---|---|
| Background | background.scripts + Browser Action | Service Worker + Action |
API webRequest | Повна підтримка | Тільки declarativeNetRequest |
API tabs | Повна | З обмеженнями (не в service worker) |
| Безпека | Виконання довільного коду | Заборонено eval(), обмежені remote scripts |
| Встановлення | Ручне або автоматичне | Вимагає підпису та оновлення через store |
Вибір MV2 або MV3 залежить від цільових браузерів та функціональності. Наприклад, для розширення, що активно використовує webRequest, у Chrome все ще доводиться тягнути MV2, хоча Firefox вже працює з MV3 через declarativeNetRequest. Ми допомагаємо визначити оптимальну стратегію.
Як уникнути помилок при роботі з повідомленнями?
Строга типізація повідомлень між контекстами — запорука відсутності silent-багів. Ми використовуємо дискримінований union на TypeScript:
// shared/messages.ts export type Message = | { type: 'GET_PAGE_DATA'; url: string } | { type: 'SET_BADGE'; count: number; color?: string } | { type: 'OPEN_OPTIONS' } | { type: 'EXTRACT_TEXT'; selector: string }; export type MessageResponse<T extends Message> = T extends { type: 'GET_PAGE_DATA' } ? { title: string; meta: Record<string, string> } : T extends { type: 'EXTRACT_TEXT' } ? { text: string } : void; export async function sendMessage<T extends Message>( message: T ): Promise<MessageResponse<T>> { return browser.runtime.sendMessage(message) as Promise<MessageResponse<T>>; } export function onMessage<T extends Message['type']>( type: T, handler: (msg: Extract<Message, { type: T }>, sender: browser.runtime.MessageSender) => Promise<MessageResponse<Extract<Message, { type: T }>>> ) { browser.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === type) { handler(msg, sender).then(sendResponse); return true; } }); } Такий підхід гарантує, що обробник отримає саме той тип повідомлення, який очікує. Компілятор не пропустить невідповідність. Типізовані повідомлення — стандарт для всіх наших проєктів, включаючи фінансові та e-commerce розширення з сотнями тисяч користувачів.
Що входить у роботу
Ми надаємо готове рішення під ключ:
- Архітектура та проєктування — вибір стеку, типізація, структура файлів.
- Реалізація та тестування — написання коду, unit-тести, E2E-тести з Playwright.
- Збірка та CI/CD — налаштування Vite, скрипти збірки, GitHub Actions для публікації.
- Документація — README, опис API, інструкція зі збірки.
- Публікація — завантаження в Chrome Web Store, Firefox AMO, Edge Add-ons, Opera Addons (Safari — на запит).
- Підтримка — гарантійний період 30 днів після здачі, виправлення багів, адаптація до нових версій браузерів.
Ми маємо досвід розробки розширень для фінансового сектору, e-commerce та SaaS — понад 5 років і 30+ успішних проєктів. Зв'яжіться з нами для оцінки вашого проєкту — ми допоможемо обрати оптимальну архітектуру.
Терміни
Кросбраузерне розширення (Chrome + Firefox + Edge) з єдиною кодовою базою, типізацією, автозбіркою та публікацією в три магазини — 10–16 робочих днів залежно від функціональності. Додавання Safari (Xcode-обгортка + App Store) додає 5–8 днів. Терміни рев'ю магазинів — окремо та паралельно.
Замовте розробку кросбраузерного розширення — ми оцінимо ваше завдання за один робочий день. Отримайте консультацію телефоном або в чаті, щоб обговорити функціональність та терміни.







