Как стать автором
Обновить

Userscripts. Упаковываем юзерскрипт для Chrome

Время на прочтение5 мин
Количество просмотров36K
Доброго времени суток, уважаемые хабражители.

Сегодня мы поговорим подробней об упоминавшейся вскольз технологии написания кроссбраузерных юзерскриптов, а именно об упаковывании юзерскрипта в простейшее расширение для Google Chrome.

Ниже я постараюсь овтетить на вопросы «зачем ?» и «как ?».

Прелюдия


Как вы помните, браузер Google Chrome поддерживает скрипты нативно (без необходимости установки сторонних компонентов). Поддержка скриптов реализована на довольно хорошем уровне, но есть одно НО: разработчики Google Chrome пекутся о нашей безопасности и ограничивают всё, что можно ограничить.

В виду этих ограничений нетривиальные скрипты приходится оборачивать в расширение.

Какие ограничения?


Самые главные ограничения:
  1. Скрипт должен делать кроссдоменные запросы
  2. Скрипту нужен доступ к window.frames[i]
  3. Скрипту нужны повышенные лимиты localStorage
  4. И т.д.

Указанные выше три ограничения не могут быть сэмулированы и окостылены. Придётся упаковывать юзерскрипт.

Что получаем на выходе?


Если говорить строго, то на выходе мы получим расширение, а не юзерскрипт. Но учитывая, что:
  • процессы установки и управления юзерскрипта и расширения одинаковы;
  • юзерскрипты при установке автоматически оборачиваются в расширение;
  • обёртка создаётся один раз, а далее мы разрабатываем только сам юзерскрипт;

я позволяю себе говорить о юзерскрипте.

Упаковка


Простое расширение состоит из:
  1. Файла описания manifest.json
  2. Фоновой страницы background.html
  3. Файла юзерскрипта


manifest.json


Данный файл описывает расширение: права, составляющие ресурсы, метод запуска и т.д.
Как видно из названия, вся конфигурация представляет собой json-объект.
Подробнее об этом файле можно почитать в официальном доке.

Я рассмотрю необходимый минимум для превращения юзерскрипта в расширение:
{
    "background_page" : "background.html", 
    "content_scripts" : [
        {
            "js":[ "my.user.js" ], 
            "matches":[ "http://*/*" ], 
            "run_at":"document_end"  
        }
    ], 
    "description" : "", 
    "name" : "My Userscript", 
    "permissions" : [ "http://*/*", "unlimitedStorage"],
    "version" : "1.3.0"
}



Параметр Назначение Комментарий
background_page Определяет файл фоновой страницы Назначение см. ниже
content_scripts Секция подключения контент-скриптов Именно сюда прописывается информация
о нашем юзерскрипте
js Массив, содержащий название файлов контент-скриптов Здесь указывается название
нашего единственного скрипта
matches Массив, содержащий url-маски для запуска скриптов Каждый элемент массива соответствует
по индексу элементу массива контент-скриптов.
Этот параметр определяет, на каких страницах
будут запускаться соответствующие скрипты.
В нашем случае маска указывает на то,
что скрипт запускается на всех страницах,
доступных по http.
run_at Порядок запуска контент-скриптов document_end означает,
что скрипт будет запускаться
после построения DOM-дерева
description Описание расширения Произвольный текст, описывающий наш юзерскрипт
name Название расширения Название скрипта в произвольной форме
permissions Разрешения для нашего расширения Необходимые разрешения безопасности.
Первый параметр в примере
маска корссдоменных запросов http://*/*.
Она позволяет фоновой странице посылать запросы на любые домены.

Второй параметр задаёт нелимитируемый localStorage.
version Версия расширения Версия в формате x.x.x.x


background.html


Фоновая страница представляет собой обычную html страницу, которая загружается в «невидимый таб» при запуске расширения и работает в фоне в течение всего жизненного цикла расширения.
Ограничения безопасности фоновой страницы настраиваются через параметр permissions в файле-манифесте. Именно через фоновую страницу обходятся ограничения юзерскриптов. Фоновая страница для упакованных юзерскриптов представляет собой proxy, который может «общаться» с юзерскриптом посредством chrome.extension api (Описание).

С теорией покончим, время тусоваться практики!
Рассмотрим подробнее проксирование кроссдоменных запросов из юзерскрипта.

Код background.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
/**
* Кроссдоменные запросы для Хрома.
* XMLHttpRequest на фоновой странице избавлен от CORP (Cross Origin Request Policy),
* т.е. может посылать запросы на другие домены.
* Ниже реализован простой метод GET
*/
function get(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function (data) {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                callback(data.srcElement.responseText);
            } else {
                callback(null);
            }
        }
    }
    // Note that any URL fetched here must be matched by a permission in
    // the manifest.json file!
    xhr.open('GET', url, true);
    xhr.send();
};
/**
* Обработчик события chrome.extension api.
* Нужен лдя непосредственного проксирования
* @param request Object Данные нашего api-запроса.
* @param sender Object Объект, характеризующий происхождение нашего запроса.
* @param callback Function Коллбэк, который мы передаём параллельно с api-запросом.
* /
function onRequest(request, sender, callback) {
    // В данном примере поддерживается только действие xget.
    // В целом же можно построить довольно неплохую RPC-cистему
    if (request.action == 'xget') {
        get(request.url, callback);
    }
};
// Регистрируем обработчик события.
chrome.extension.onRequest.addListener(onRequest);
// Из скрипта обращение к прокси будет выглядеть так:
// chrome.extension.sendRequest({'action' : 'xget', 'url':url}, callback);
</scrip>
<body></html>


Код с английскими комментариями доступен на pastebin.com

Вызов из юзерскрипта:
/**
 * Этот код располагается в юзерскрипте
 * Тестовый вызов: get("http://example.com",alert);
 */
function  get(url, callback) {&
    chrome.extension.sendRequest({ 'action':'xget', 'url':url}, callback);
}



Этот метод работает в Google Chrome. Кроссдоменные запросы из юзерскриптов в других браузерах мы рассмотрим в одной из следующих статей.

Собираем, тестируем


Для сборки расширения нам понадобится:
  1. Создать отдельную папку (для удобства)
  2. Положить в неё manifest.js, background.html и файл юзерскрипта
  3. Упаковать расширение при помощи Chrome (Натсройки — Расширения — Упаковать расширение. См. скриншот)




Для тестирования мы можем установить распакованное расширение (спасибо theOnlyBoy за наводку). Вместо упаковки (пункт 3) жмём «Установить распакованное расширение».
В итоге наше расширение установится как и обычное упакованное (плюс будет милая и удобная ссылочка Reload для перезагрузки расширения, см. скриншот).

Заключение


На этом на сегодня всё, оставайтесь с нами!
Жду вопросы, критику и обсуждения в комментариях.


Список статей:
  1. Учимся писать userscript'ы
  2. Userscripts. Углубляемся
  3. » Userscripts. Упаковываем юзерскрипт для Chrome
  4. Usersctripts. Кроссдоменные запросы
Теги:
Хабы:
+11
Комментарии10

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн