Поиск поддержки браузером для всех веб-API - compat-db

Обеспечение совместимости приложений с браузером - постоянная проблема разработчиков браузеров. Обычно веб-приложения должны запускаться в нескольких браузерах.

Понимание проблемы

Компании очень часто требуют, чтобы их приложение работало в определенных браузерах. Facebook, например, требует, чтобы версия их веб-приложения по-прежнему работала в Internet Explorer, браузере, известном своими зияющими дырами в поддержке API браузера. Выполнение этого требования выполняется путем тестирования приложения в разных браузерах, но при этом обычно возникают накладные расходы на разработку, поскольку для этого требуются написанные тесты и время для их запуска.

Вместо тестов разработчики обычно ссылаются на таблицы совместимости, которые представляют собой таблицы, в которых перечислены все браузеры, в которых поддерживается данный API. Однако многие из этих таблиц либо неполны, либо отсутствуют для определенных API, поскольку они заполняются вручную. разработчиками, что непросто. Существует примерно 10K API и 131 вариант браузеров, что составляет 1 310 000 записей совместимости API, которые необходимо заполнить. Записи совместимости поддерживаются двумя проектами: Mozilla Developer Network (MDN) и caniuse.

MDN

Примеры неизвестных записей API:

могу ли я использовать

Caniuse - наиболее полная коллекция этих записей совместимости API. Но это решение сложно масштабировать. При ограниченном количестве разработчиков с ограниченным временем и ресурсами трудно поддерживать таблицу с тысячами записей.

Как видите, у caniuse более 1K проблем и только один активный сопровождающий для их решения.

Кроме того, разработчики, проверяющие таблицу совместимости вручную, не являются масштабируемым решением для устранения несоответствий совместимости браузеров. caniuse не предоставляет масштабируемого решения для интеграции с существующими инструментами статического анализа (т. е. анализа кода).

Предлагаемое решение: compat-db

compat-db - это проект, который автоматизирует создание записей совместимости API. Он принимает API в качестве входных данных и возвращает записи совместимости в качестве выходных данных. Чтобы сгенерировать все записи совместимости браузера, ему в качестве входных данных предоставляются все стандартные API-интерфейсы браузера, и он возвращает все соответствующие записи совместимости.

Ввод: WebIDL

API определены на специальном языке, который называется WebIDL. Авторы API пишут спецификацию для API в форме WebIDL, языка, который определяет интерфейс API. Вот пример WebIDL, соответствующего API TextEncoder.encodeInto:

Тесты JavaScript генерируются из WebIDL. Вот упрощенная версия соответствующих тестов совместимости, созданных из приведенного выше примера WebIDL:

Определение совместимости: виртуальные машины браузера

Следующим шагом является запуск этих сгенерированных тестов совместимости в каждом браузере. Это делается путем отправки тестов для запуска в удаленных браузерах, где они затем оцениваются. Эти браузеры поддерживаются рядом служб, включая browserstack и saucelabs. Затем результаты оцененных тестов возвращаются как ответы на compat-db.

Соображения производительности

Наивная реализация

В простой реализации потребовалось бы запустить тесты для каждой версии каждого браузера для каждого API, чтобы построить полную таблицу совместимости.

Этот алгоритм представляет собой алгоритм O (m * n), где m - количество тестируемых API, а n - общее количество протестированных версий браузера.

Существует 10K API и 131 версия всех браузеров:

Суммируя общее количество версий браузеров, получаем 131 версию.

Наивный метод потребует более 1 310 000 тестов 😱 (10,00 API * 131 версия браузера = 1 310 000 тестов).

Оптимизация

Мы можем наблюдать некоторые определенные эвристики браузера, чтобы уменьшить количество тестов, необходимых для построения полной таблицы совместимости. Как только браузер реализует API, его нельзя будет удалить. Это общий принцип, которому следуют веб-браузеры, потому что они не могут «сломать сеть». Если браузер использует ранее поддерживаемый API, он сломает страницы, которые зависят от этого API, существующего в этом браузере. API устарели, но никогда не удаляются (только в некоторых крайне редких случаях, например, `SharedArrayBuffer`).

Используя эту эвристику, мы запускаем модификацию, которая находит первую версию браузера, поддерживающую данный API. Алгоритм почти идентичен бинарному поиску: посмотрите отсортированные версии любого данного браузера.

Рассмотрим пример отсортированных версий браузера:

[12, 14, 16, 18, 22]

Если мы выполняем тесты совместимости для «средней» версии (в данном примере 16) браузера, и они возвращают «false», то мы знаем, что во всех предыдущих версиях этого браузера не должно быть ранее реализовано это API. Итак, мы смотрим на версии «справа» от «средней» версии: `[18, 22]`, а затем рекурсивно выполняем предыдущую операцию.

Это можно сделать за время O (m * log n) для одного браузера, где n - количество версий браузера, а m - количество API, которые необходимо протестировать.

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

Это сокращает наше первоначальное количество тестов с 1 310 000 до 64 393, что на 95% меньше количества тестов, необходимых для определения совместимости всех API-интерфейсов с браузером.

Примеры использования compat-db

Будущее compat-db включает интеграцию со средствами статического анализа, такими как следующие проекты.

Статический анализ

Eslint-plugin-compat, плагин ESLint, который обеспечивает совместимость кода JavaScript. Вот пример его использования:

compat-db будет служить источником, который содержит записи совместимости, на которые ссылается eslint-plugin-compat для поиска совместимости API.

Автоматическое добавление полифиллов и прокладок

Полифилы и прокладки - это фрагменты кода, которые реализуют API, если он не поддерживается средой выполнения. Например, если хром не поддерживает API `fetch`, то полифил для него будет реализовывать эту функцию с использованием собственного JavaScript.

На момент написания не было возможности автоматически включать необходимые полифилы или прокладки для кодовой базы с учетом списка целевых браузеров. Авторы библиотек включают полифилы для своих библиотек с целью упрощения процесса использования библиотек. Таким образом, пользователям библиотеки не нужно беспокоиться о включении полифиллов. Однако это происходит за счет увеличения размеров приложений и библиотек, которые используют эти библиотеки.

Идеальное решение, которое теперь стало возможным с помощью compat-db, заключается в переборе всех используемых API, проверке compat-db на предмет поддержки браузеров, на которые настроен пользователь, а затем добавлении полифилов в сборку пользователя. Это решение, которое следует использовать только в контексте приложений, а не библиотек, гарантирует, что в скомпилированный вывод приложений будут включены только необходимые полифиллы и прокладки.

Проект

compat-db размещен на GitHub. Я активно ищу участников, так что дайте мне знать, если вы заинтересованы в участии! Необходимо проделать некоторую работу, чтобы подготовить compat-db к рабочей среде.