Избушка на обратно-совместимых ножках — компилируем JS для нужных браузеров

    image


    Привет, хабр! Уже сегодня на otus.ru стартует курс "Fullstack разработчик JavaScript" и я решил поддержать ребят этой статьей. Я кстати сам преподаю на курсе по React.js.

    Есть такой принцип — Don't break the web, который можно раскрыть как "веб всегда старается сохранить максимальную обратную совместимость". В некоторой мере этот принцип применим и к веб сайтам и приложениям — ваш сайт должен работать не только в одном конкретном браузере, но в целом наборе разных браузеров и версий. Но в каких? Однозначно должны быть какие-то разумные пределы и IE 6 и netscape navigator поддерживать не стоит, но два вопроса остаются открытыми: какие браузеры вы поддерживаете и как это обеспечить?


    Если есть обратная совместимость значит что-то меняется. Меняются в вебе три вещи: ECMAScript (javascript), CSS и различные Web API. CSS мы сегодня оставим на опушке, а пока, тропинка ведет нас в дебри современной фронтенд разработки


    Начнем с простого


    Так или иначе, абсолютное большинство современных и не очень браузеров поддерживают ES5, этакий greatest common denominator. Большинство библиотек пишутся или скомпилированы в ES5 и мы можем поступить также! Можно либо сразу писать в ES5 (не рекомендую) либо использовать babel или typescript


    В сети есть множество туториалов о том как это делать, но позволю себе упомянуть что в babel 7, @babel/preset-es2015 является устаревшим (о чем нам любезно напоминает официальная документация) и рекомендуется использовать @babel/preset-env, которому на самом деле посвящена львиная доля статьи. Но легко поставить избушку на поляне, но мы ведь с вами не за этим здесь собрались, давайте попробуем сделать это на болоте (если почувствовали тоску, то возможно стоит поменять работу)?


    Делаем как у больших


    Общая идея следующая — мы определяем какие браузеры мы поддерживаем и под эти браузеры настраиваем нашу конфигурацию транспиляции. Помогут нам в этом как всегда различные инструменты, но проблема тут в том, что их не два, не три, а полное лукошко! Поэтому я сначала кратко объясню что каждый из них делает, а с тем кто с кем и как взаимодействует разберемся потом:


    Дисклеймер: для интеграции @babel/preset-env со стандартной конфигурацией в новый проект не требует понимания того, как эта машинерия работает, но в продакшене все как обычно сложнее и это начинается играть роль

    caniuse


    https://github.com/fyrd/caniuse


    https://caniuse.com/


    Также существует в редакции caniuse-lite (именно ее использует browserslist)

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


    browserslist


    https://github.com/browserslist/browserslist


    С него все начинается. browserslist (browserSlist обратите внимание на S) умеет преобразовывать запрос вида "> 0.25%, not IE11, not dead" в список браузеров, в данном случае означающий все браузеры которые имеют мировую долю использования более 0.25% кроме IE11 и браузеров не получающих обновления безопасности (на момент написания статьи IE 10, IE Mobile 11, BlackBerry 10, BlackBerry 7, Samsung Internet 4 и Opera Mobile 12.1)


    corejs


    Содержит полифиллы для всех фич ECMAScript вплоть до 2019-й версии. В версии 3 произошло множество глобальных изменений (https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md)


    Используется в babel/present-env, поддерживается и 2-я и 3 -я версии


    core-js-compat


    https://www.npmjs.com/package/core-js-compat


    Содержит информацию о том каким браузерам какие полифиллы из corejs нужны. В том числе подключает полифиллы для тех браузеров в которых есть критические баги в фиче. Например до Chrome 80 matchAll не бросал исключение в случае неглобальной регулярки, как нужно по текущему стандарту, хотя имплементация впервые появилась в 73-й версии
    https://github.com/zloirock/core-js/blob/master/packages/core-js-compat/src/data.js#L877


    compat-table


    https://kangax.github.io/compat-table/es6/


    Содержит информацию о поддержке фич ECMAScript различными браузерами (думаю понятно) и средами исполнения (nodejs, graalvm etc.)


    Используется в @babel/preset-env, но с нюансом — в случае corejs@2 для полифиллов используются данные из compat-table, а в случае corejs@3 — данные из core-js-compat(они более актуальные и умные)


    Как это все вообще работает


    На практике в классическом варианте все выглядит так:


    1. в .browserslistrc (или в package.json#browserslist) вы указываете browserslist query
    2. в babelrc вы указываете @babel/preset-env в presets и выбираете опцию useBuiltIns (советую entry ибо usage не умеет проверять используемые API в зависимостях)
    3. Эту browserslist query читает @babel/preset-env
    4. @babel/preset-env получает из нее список браузеров через api browserslist и
      4.1 использует compat-data выбирая набор плагинов которые будут применены в вашему коду
      4.2 использует corejs-compat выбирая какие полифиллы подключить

    Таким образом на выходе вы получаете js код который будет верно работать во всех указанных браузерах (в разумных пределах ибо есть разные экзотические браузеры про поддержку которых данных просто нет). И наша избушка встает на ножки (или на сваи) и получает обратную совместимость!


    И всё?


    К сожалению нет, во фронтенде все опять неспокойно. Есть ряд кочек о которые можно легко споткнуться, а то и вообще завязнуть в трясине если сойти с узкой тропинки happy path


    browserslist query


    Наверняка у проекта в который вы собираетесь это внедрять уже список или хотя бы понимание поддерживаемых браузеров. Если нет, то все просто: возьмите defaults (это > 0.5%, last 2 versions, Firefox ESR, not dead) и вы покроете более 90% вообще всех браузеров (что на самом деле очень хороший результат ибо "все" это вплоть до IE 6!). Если все-таки понимание есть, но надо перевести его (понимание) в query. Это может быть не так-то просто, но главным образом нужно знать три вещи:


    • запятая в browserslist query означает or (то есть "или")
    • "и" записывается как and
    • отрицание записывается как not и при этом применяется через and даже если написано с запятой (если кто-то помнит как заносить отрицание в скобки в булевой алгебре поймет почему)
    • ладно, четыре: можно удобно тестировать вашу query вот тут https://browserl.ist/ (а тут нет S! Жизнь боль)

    С этим знанием и внимательным чтением документации (а вы думали можно без этого?) вы сможете подогнать список под ваши нужды. Если будут проблемы, дайте знать в комментариях!


    Невиданное-неслыханное


    Как сказано выше, defaults это > 0.5%, last 2 versions, Firefox ESR, not dead. Вроде относительно понятно, но если вы посмотрите чему это соответствует то обнаружите там браузеры о существовании которых и не подозревали или не знали что они до сих пор используются. Тем не менее слепо выбрасывать их не стоит, поэтому давайте разберемся с теми которые не входят в большую шестерку с половиной (Chrome, Firefox, Edge, Opera, Safari и IE). Проценты глобального использования приведены для последней версии на момент написания статьи



    UPD от Dartess
    Там всё очень сложно. На одном только андроиде есть как минимум три версии движка — U2, U3, U4. Все на базе хромиума, но с большими оговорками.
    U2 это ультралайтовая и ультралёгкая версия, которая отображает веб, по ощущениям, на уровне IE8. Отключено всё, что можно. В общем, не юзабельно, но возможно было актуально для ультрабюджетных андроидов лет 10 назад.
    U3 тоже был направлен на быстродействие и является сильно модифицированной версией хромиума. Тоже местами урезан, но веб в целом работает. На этом браузере встречал некоторые баги, которые не мог воспроизвести ни на одной версии хрома. Отличается широкой поддержкой различных версий андроида и разных процессоров. Плюсом там есть всякие ништяки типа поддержки флеша из коробки и режима сжатия трафика.
    U4 появился где-то года три назад, сейчас по умолчанию из маркета в обычной версии ставится он. Является уже самым обычным брендированным хромиумом, поэтому нормально работает и нормально (стабильно) обновляется.
    Полный комментарий


    • Baidu Browser, 0%
      И еще один китайский браузер, на этот раз от Baidu (китайский гугл). Судя по всему не получил распространения даже в Китае и данных по поддержке фич естественно нет.
    • KaiOS Browser, 0.2% — https://www.kaiostech.com/
      KaiOS это очень интересный проект — операционная система для очень дешевых смартфонов, призванная сделать технологии доступнее. К сожалению данных по поддержке нет, но я полагаю что можно наладить контакты с разработчиками и узнать. Вообще, rule of a thumb что если данных нет — можно считать что браузер поддерживает ES5

    UPD V1tol
    По KaiOS проходила информация, что там сейчас используется движок, соответствующий Firefox 48



    Что делать с ними ^ решать конечно вам, но я крайне советую стараться поддерживать как можно больше браузеров, это помогает сохранять их разнообразия и не загоняет нас в ловушку IE6 (кхе-кхе Chrome)


    Взгляд в будущее


    Это уже очень много информации, но мы все еще не коснулись таких вещей как


    • autoprefixer и CSS
    • Свои собственные данные по usage
    • Несколько конфигураций и бандлов
    • Продвинутые опции useBuiltIns

    Я надеюсь мы когда-нибудь покроем это в второй части, а пока, всем peace, и пусть ваша избушка не развалится ни в одном браузере! А если вы заинтересовались курсом, то можете узнать о нем подробнее по ссылке.

    OTUS. Онлайн-образование
    Цифровые навыки от ведущих экспертов

    Комментарии 16

      +1
      По KaiOS проходила информация, что там сейчас используется движок, соответствующий Firefox 48
        0
        Круто, спасибо! А где проходила не подскажете?
          +1
          Я ж ссылку дал) kaiosinfo.ru/122-firefox-os-vozvrashchaetsya
          Ещё глянул в репозиторий: github.com/kaiostech/gecko-b2g Там код в среднем 2-4-годичной давности. Да и название ветки намекает.
            0

            Извиняюсь, как-то не воспринял ссылку. Ну 48 это еще куда ни шло, главное чтобы ползло потихоньку

          0
          Добавил в статью
          –1
          А можно просто пользоваться hqjs.org и полностью абстрагироваться от этих проблем и сконцентрироваться на бизнес логике
            0

            Ох уж эти обещания писать бизнес логику и не думать об инструментах, навевает ностальгию


            Если по теме: не очень понял как дев сервер относится к бандлингу под разные браузеры. Только не говорите что предлагаете гонять это в продакшене (даже если забыть про то от что поддержка экспериментальная)

              0
              Это чуть больше чем просто дев сервер, попробуйте, может вам зайдет

              hq — отдает сборку под ваш конкретный браузер
              NODE_ENV=production hq — то же с продакшн оптимизациями, не вижу особых проблем, тестировать конечно нужно все
              hq build — статическая сборка
            0
            Эй, а Как же Амиго браузер? — Один из самых популярных браузеров, по версии команды Mail.ru Group. Его то тут все хоть раз в жизни устанавливали себе =)
              0
              Опрос в интернете показал что 100% населения пользуются интернетом

              Не могу признаться что устанавливал, но кажется что в целом он попадает в ту же категорию что остальные хромиумы c редизайном которые этого не стестянются: Brave (сам я кстати использую его помимо лисы), Яндекс Браузер, тысячи их
              +1
              я даже не знаю на каком движке он работает. Если кто-то в курсе — напишите

              Там всё очень сложно. На одном только андроиде есть как минимум три версии движка — U2, U3, U4. Все на базе хромиума, но с большими оговорками.
              U2 это ультралайтовая и ультралёгкая версия, которая отображает веб, по ощущениям, на уровне IE8. Отключено всё, что можно. В общем, не юзабельно, но возможно было актуально для ультрабюджетных андроидов лет 10 назад.
              U3 тоже был направлен на быстродействие и является сильно модифицированной версией хромиума. Тоже местами урезан, но веб в целом работает. На этом браузере встречал некоторые баги, которые не мог воспроизвести ни на одной версии хрома. Отличается широкой поддержкой различных версий андроида и разных процессоров. Плюсом там есть всякие ништяки типа поддержки флеша из коробки и режима сжатия трафика.
              U4 появился где-то года три назад, сейчас по умолчанию из маркета в обычной версии ставится он. Является уже самым обычным брендированным хромиумом, поэтому нормально работает и нормально (стабильно) обновляется.


              Примеры юзерагентов на всякий:


              UCWEB/2.0 (MIDP-2.0; U; Adr 6.0.1; ru; Nexus_5) U2/1.0.0 UCBrowser/10.9.8.1006 U2/1.0.0 Mobile

              Mozilla/5.0 (Linux; U; Android 6.0.1; en-US; Nexus 5 Build/M4B30Z) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 UCBrowser/11.4.2.995 U3/0.8.0 Mobile Safari/534.30

              Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5 Build/M4B30Z; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36 Mobile UCBrowser/3.4.3.532

              На iOS, разумеется, это как и остальные скин над вебкитом. На Windows Phone даже есть, но, вроде, там это тоже только скин над Trident. Также есть и версия для десктопа, но вроде только на Windows. Скорее всего обычный хромиум, не изучал.

                0
                Большое спасибо! Добавил в статью
                  +1
                  Все на базе хромиума, но с большими оговорками.

                  наверное, U2 не на базе хромиума. Как мне кажется, это их старый движок со времен Java-телефонов.


                  U3… Тоже местами урезан

                  скорее всего не урезан, а просто взят очень старый WebKit-движок (534.30, если верить юзер-агенту).


                  Это все мои мысли, если у кого-то есть более точная информация — прошу ее предоставить.

                    0

                    Да, точно! MIDP-2.0 же. Спасибо за уточнения!

                  0
                  Что делать с ними ^ решать конечно вам, но я крайне советую стараться поддерживать как можно больше браузеров, это помогает сохранять их разнообразия и не загоняет нас в ловушку IE6 (кхе-кхе Chrome)

                  как можно больше браузеров — это вглубь или вширь? Если вы говорите о поддержке последних 2-3 версий каждого актуального движка (Blink, WebKit, Gecko), то так, несомненно, нужно делать. А не как Microsoft, когда в случае веб-версии Скайпа ограничивает браузеры по юзер-агенту, в том числе современный Файрфокс.
                  Или вы имели в виду отдельную поддержку Opera Mini, Samsung Internet, KaiOS Browser, UC Browser, когда писали о ловушке Chrome?

                    0
                    Я думаю и то и другое. Начать с джентельменского набора и сделать чтобы все нормально работало в N последних версиях Chrome/FF/Safari и поддерживать это. Потом посмотреть и понять поддержка чего еще целесообразна (например есть потенциальная или реальная аудитория) и не потратит тонну ресурсов

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

                  Самое читаемое