javascript

Пишем простое расширение для браузера

  • воскресенье, 9 марта 2025 г. в 00:00:05
https://habr.com/ru/articles/887098/

Всем привет! В этом туториале я хотел бы описать создание расширения для браузера на основе Chromium (Google Chrome, Brave, Яндекс Браузер и др.).

Расширения для браузеров создаются с использованием веб-технологий: HTML, CSS и JavaScript/TypeScript. Можно также применять библиотеки, такие как React или jQuery, а также фреймворки, например Vue. Однако можно обойтись и чистым JavaScript (Vanilla JS).

Наше расширение будет управлять куками на сайте. Реализуем следующий функционал:

  • Отображение кук

  • Удаление кук

  • Блокировка кук по домену

  • Разблокировка

  • Фильтрация

🚀 Давайте приступим! Весь код хранится в этом репозитории, и вы можете склонировать его себе, но советую сначала сделать всё самим.

Подготовка структуры проекта

Сама структура проекта простая:

  • manifest.json – конфигурационный файл расширения.

  • background.js – фоновый скрипт, управляющий логикой.

  • content scripts – скрипты, взаимодействующие с веб-страницами, в нашем случае - это popup.js.

  • popup.html – сам интерфейс расширения.

Перед началом разработки убедитесь, что у вас установлен редактор кода и браузер (ну а вдруг нет). Создайте папку для проекта и внутри неё настройте следующую структуру файлов:

Структура проекта
Структура проекта

Иконки можно будет скачать здесь.

Начнем с первого файла - манифест – это основной файл конфигурации расширения. Создадим manifest.json:

{
  "manifest_version": 3,
  "name": "Cookie Manager",
  "version": "1.1",
  "description": "Manage cookies: view, block, or delete cookies for specific websites.",
  "permissions": ["cookies", "storage", "activeTab", "scripting", "webRequest", "webRequestBlocking"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  }
}

Стоит обратить внимание на некоторые поля конфигурации:

  • permissions – список разрешений, необходимых для работы расширения (например, доступ к cookies, хранилищу и активным вкладкам).

  • host_permissions – разрешенные домены, с которыми может взаимодействовать расширение.

  • background – указывает фоновый скрипт, который выполняется в сервис-воркере (background.js).

  • action – определяет настройки кнопки расширения в панели инструментов браузера (указываем popup и иконку).

Если в конфигурации будут ошибки, браузер не запустит расширение.

Создаем UI

Пользовательский интерфейс будет в файле popup.html. Добавим две кнопки: «Просмотреть куки» - при нажатии на неё будем получать все сохранённые в браузере куки, и «Удалить куки» - для их удаления.

Список куков будет динамически формироваться с помощью JavaScript в файле popup.js. Позже мы его рассмотрим.

Также добавим поле ввода для блокировки домена, а ниже отобразим список заблокированных доменов.

Код popup.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Менеджер кук</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="wrapper">
        <h2>Менеджер кук</h2>
    
        <button id="viewCookies">Просмотреть куки</button>
        <button id="deleteCookies">Удалить куки</button>
    
        <h3>Блокировка домена</h3>
        <input type="text" id="blockDomainInput" placeholder="Введите домен" />
        <button id="blockDomain">Блокировать</button>
    
        <ul id="blockList"></ul>
    </div>

    <script src="popup.js"></script>
</body>
</html>

Логика приложения

Логика нашего расширения будет хранится в двух скриптах:

  1. background.js - фоновый скрипт выполняет задачи, которые работают независимо от пользовательского интерфейса, такие как обработка событий, работа с API браузера и управление данными. В нашем случае мы будем его использовать для блокировки домена.

  2. popup.js - содержится основная логика расширения. Здесь у нас обработчики кнопок и работа с куками.

Чтобы взаимодействовать с браузером нам нужен API. На помощь нам приходим объект chrome, рассмотрим его основные методы:

  • chrome.runtime – управление жизненным циклом расширения.

    • chrome.runtime.onMessage.addListener(callback) – слушает сообщения между скриптами.

    • chrome.runtime.sendMessage(message, callback) – отправляет сообщение другому скрипту.

  • chrome.tabs – работа с вкладками.

    • chrome.tabs.query(queryInfo, callback) – получает список вкладок.

    • chrome.tabs.create(properties, callback) – открывает новую вкладку.

  • chrome.cookies – управление cookies.

    • chrome.cookies.get(details, callback) – получает информацию о cookie.

    • chrome.cookies.getAll(details, callback) – получает все cookies.

    • chrome.cookies.remove(details, callback) – удаляет cookie.

  • chrome.storage – локальное хранилище данных.

    • chrome.storage.local.set(object, callback) – сохраняет данные.

    • chrome.storage.local.get(keys, callback) – получает сохраненные данные.

    • chrome.storage.sync.set(object, callback) – сохраняет данные в облаке и синхронизирует их между устройствами пользователя.

    • chrome.storage.sync.get(keys, callback) – получает синхронизированные данные.

  • chrome.notifications – создание уведомлений.

    • chrome.notifications.create(options, callback) – создает уведомление.

В background.js добавим обработчик для перехвата заголовков запроса и блокировки доменов. Также выведем в консоль сообщение о том, что расширение установлено.

chrome.webRequest.onBeforeSendHeaders.addListener(
    function (details) {
        return new Promise((resolve) => {
            chrome.storage.sync.get({ blockedDomains: [] }, (data) => {
                let url = new URL(details.url);
                if (data.blockedDomains.includes(url.hostname)) {
                    resolve({ cancel: true }); // Блокируем запрос, если домен в списке
                } else {
                    resolve({ cancel: false });
                }
            });
        });
    },
    { urls: ["<all_urls>"] },
    ["blocking"]
);

chrome.runtime.onInstalled.addListener(() => {
    console.log("Cookie Manager Extension Installed.");
});

Больше для этого файла нам нечего добалять.

Вся магия у нас будет описана в файле popup.js. Здесь нам нужно добавить обработчики для кнопок, поля ввода и для работы с cookies.

Рассмотрим первый обработчик, который получает и отображает все cookies для текущей активной вкладки:

document.getElementById("viewCookies").addEventListener("click", () => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        let url = tabs[0].url;
        chrome.cookies.getAll({ url }, (cookies) => {
            let cookieList = document.getElementById("blockList");
            cookieList.innerHTML = "";
            cookies.forEach(cookie => {
                let li = document.createElement("li");
                li.textContent = `${cookie.name} = ${cookie.value}`;
                cookieList.appendChild(li);
            });
        });
    });
});

Следующий фрагмент кода удаляет все cookies текущего сайта и уведомляет пользователя:


document.getElementById("deleteCookies").addEventListener("click", () => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        let url = tabs[0].url;
        chrome.cookies.getAll({ url }, (cookies) => {
            cookies.forEach(cookie => {
                chrome.cookies.remove({ url, name: cookie.name });
            });
            alert("Cookies deleted!");
        });
    });
});

Обработчик для добавления домена в список заблокированных и сохранение его в хранилище:

document.getElementById("blockDomain").addEventListener("click", () => {
    let domain = document.getElementById("blockDomainInput").value.trim();
    if (domain) {
        chrome.storage.sync.get({ blockedDomains: [] }, (data) => {
            let blockedDomains = new Set(data.blockedDomains);
            blockedDomains.add(domain);
            chrome.storage.sync.set({ blockedDomains: Array.from(blockedDomains) }, () => {
                loadBlockedDomains();
                alert(`Заблокирован ${domain}`);
            });
        });
    }
});

Отображение заблокированных доменов, когда наше расширение стартовало:

document.addEventListener("DOMContentLoaded", () => {
    loadBlockedDomains();
});

function loadBlockedDomains() {
    chrome.storage.sync.get({ blockedDomains: [] }, (data) => {
        let blockList = document.getElementById("blockList");
        blockList.innerHTML = "";
        data.blockedDomains.forEach(domain => {
            let li = document.createElement("li");
            li.textContent = domain;
            let removeBtn = document.createElement("button");
            removeBtn.textContent = "Разблокировать";
            removeBtn.onclick = () => unblockDomain(domain);
            li.appendChild(removeBtn);
            blockList.appendChild(li);
        });
    });
}

Последний обработчик удаляет домен из списка заблокированных и обновляет интерфейс:

function unblockDomain(domain) {
    chrome.storage.sync.get({ blockedDomains: [] }, (data) => {
        let blockedDomains = data.blockedDomains.filter(d => d !== domain);
        chrome.storage.sync.set({ blockedDomains }, () => {
            loadBlockedDomains();
            alert(`Разблокирован ${domain}`);
        });
    });
}

На этом все, ничего билдить не нужно, для тестирования работы нашего приложения переходим в браузер.

Тестируем

Чтобы запустить наше расширение нам нужно выполнить следующие шаги

1) Открываем chrome://extensions/.

2) Включаем Режим разработчика.

3) Нажимаем Загрузить распакованное расширение и выбираем папку с проектом.

После того как вы выполните все шаги у вас в списке появится ваше расширение. Теперь мы можем его использовать на сайтах.

Также мы можем вызвать DevTools у расширения для отладки, то есть это по сути та же страница.

image.png

Публикуем

Этот шаг необязательный. Во-первых, возможно, вы не хотите делать доступным для всех свое расширение. А во-вторых, возможно, не захотите платить за это $5 - да, да за регистрацию нужно заплатить. Но я опишу шаги:

  1. Регистрируемся в Chrome Web Store.

  2. Зарегистрируйтесь как разработчик Chrome Web Store. Для этого войдите в консоль разработчика под своим аккаунтом Chrome.

  3. Оплачиваем 5 баксов

  4. В личном кабинет разработчика нажмите Добавить продукт и загрузите zip-архив проекта.

  5. Заполняем описание и предоставляем скриншоты.

  6. Проходим проверку и публикуем расширение.

  7. Все.

Думаю тут вы справитесь без проблем!

Заключение

На этом всё, наше расширение готово. Конечно можно еще добавить еще кучу функционала, но это я оставлю вам. Весь исходный код вы можете найти здесь.

📣 Подписывайтесь на мой телеграм канал Рассказ фронтендера.