Розробка крос-браузерних розширень
На сьогодні ми підтримуємо 3 головні браузери Chrome, Firefox і Safari, причому, не дивлячись на різницю платформ, всі збираються з однієї кодової бази. Я розповім, як це було зроблено і як спростити собі життя, розробляючи браузерні розширення.
На початку шляху
Почалося все з того, що я зробив просте розширення Chrome. До речі, розробка під Chrome виявилася найприємнішою і зручною. Особливо не заморочуючись ніякою автоматизацією, після локальної налагодження пакував вміст розширення в .zip і аплоадил у Web Store.
Розширення добре адаптувалося нашою аудиторією, метрики та відгуки користувачів говорили про те, що це те, що треба. І оскільки 15% нашого трафіку припадає на Firefox, наступним має бути він.
Суть всіх браузерних розширень одна - це HTML/CSS/JS додатки, зі своїм маніфест файлом, що описує властивості та контент та власне вихідний код. Тому моя первинна ідея була наступною — копію репозиторій розширення для Chrome і адаптую його для Firefox.
Так вийшло, що мені попався на очі чудове розширення octotree (рекомендую всім, хто активно користується GitHub), я помітив у ньому баг і вирішив виправити його. Але коли я схилював репозиторій і почав розбиратися зі вмістом, то виявив цікаву особливість - всі 3 розширення octotree збираються з одного репозиторію. Як і випадку Likeastore, Octotree це простий вміст injection і тому їхня модель відмінно підходила і для мене.
Я адаптував і покращив процес складання в Octotree для свого проекту (баг до речі теж був зафіксований) дивіться, що вийшло.
Структура програми
Я запропоную структуру програми, яка на мою думку підходитиме для будь-яких розширень.

build,dist- автогенеровані папки, в які вкладаються вихідний код розширень і готовий до дистрибуції додаток, відповідно.
css,img,js- вихідний код розширення.
vendor- платформо-залежний код, окрема папка під кожен броузер.
tools- інструменти необхідні для збирання.
Все збирається gulp'ом - "переосмисленим" збирачем проектом для node.js. І навіть якщо ви не використовуєте ноду у виробництві, я вкрай рекомендую встановити її на свою машину, дуже багато корисного з'являється зараз в галактиці npm.
Платформо-залежний код
Почнемо з найголовнішого — якщо ви починаєте новий проект, чи хочете адаптувати існуючий, необхідно чітко зрозуміти, які платформо-залежні виклики будуть потрібні та виділити їхній відділний модуль.
У моєму випадку такий виклик виявився лише один — отримання URL до ресурсу всередині розширення (у моєму випадку до картинок). Тому виділився окремий файл browser.js.
Відповідні версії для Firefox та Safari.
У більш складних випадках browser.js розширюється під всі необхідні виклики, утворюючи фасад між вашим кодом та браузером.

Крім фасаду, до платформо-залежного коду відносяться маніфести та налаштування розширення. Для Chome це manifest.json, Firefox main.js + package.json і нарешті Safari, який по-старому використовує .plist файли - Info.plist, Settings.plist, Update.plist.
Автоматизуємо складання з gulp
Для цього створюємо 3 gulp тяга,
Таск за замовчуванням, який збирає всі три розширення,
А також для розробки дуже зручно, коли код змінюється і при цьому складання виконується автоматично.
Готуємо розширення до дистрибуції
Але сама збірка це ще не все, хочетьсямати можливість запакувати додаток до формату готового до розміщення на відповідних App Store (зазначу, що для Safari такого стору немає, але при дотриманні певних правил вони можуть розмістити інформацію в галереї, завдання хостингу ви берете на себе).
У випадку Chrome все, що необхідно зробити це .zip архів, який підписується і верифікується вже на строні Chrome Web Store.
Для Firefox, трохи складніше - необхідно мати SDK, до складу якої входить тул cfx, здатний "загорнути" розширення в xpi файл.
А ось із Safari, взагалі вийде «облом». Зібрати додаток у .safariextz пакет, можна тільки всередині самого Safari. Я витратив не одну годину, щоб змусити інструкцію працювати, але марно. Зараз, на жаль, неможливо експортувати свій девелоперський сертифікат в .p12 формат, як наслідок неможливо створити потрібні ключі для підпису пакета. Safari доводиться все ще пакувати вручну, завдання дистрибуції спрощується до копіювання файлу Update.plist.
Процес розробки з одного репозиторію легкий і приємний. Як я згадав вище, Chrome, як на мене, найзручніше середовище розробки, тому всі зміни додаються і тестуються там,
Після того, як все функціонує нормально в Chrome, перевіряємо Firefox
А також у «ручному» режимі в Safari.
Приймаємо рішення про випуск нової версії, апдейтим відповідні файли маніфест з новою версією і запускаємо,

В результаті, в папці /dist які до розповсюдження файли. Ідеально було б, якщо App Store мав API через який можна залити нову версію, але поки що доводиться робити це руками. Усі подробиці, будь ласка сюди.