Сайт вебмастера

Моё впечатление о dev-версии Alpine 3

16-06-2021Время чтения ~ 7 мин.Alpine.js 4891

Недавно был анонс 3-й dev-версии AlpineJS. Это даже не новая версия, а скорее прототип для разработчиков. Сейчас много вопросов, много ошибок, поэтому использовать эту версию на рабочем сайте, я бы не рискнул. Более того, 3-я версия серьёзно ломает совместимость с текущей 2-й, поэтому переход на новую скорее всего потребует и переписывание старого кода. И это гигантский минус — скорее всего переход на новую версию займёт много времени. Вряд ли вебмастера сразу кинутся переписывать старый код.

Появился, наконец-то, нормальный официальный сайт для Альпины. На гитхабе старые версии перекочевали в отдельные ветки — вот документация для 2.8.2.

Эта статья — только краткий обзор и моё мнение. Скорее всего до полноценного релиза что-то изменится.

Теперь используется «реактивность» от VueJS и прочие улучшения. Писали, что это скажется на более высокой производительности и скорости работы, точнее не скажу — я ни разу не сталкивался с такими проблемами. В любом случае внутреннее устройство AlpineJS — это прерогатива автора.

Дальше всё не так однозначно.

Появилась магическая переменная $store, которая доступна сразу всем компонентам Альпины. И это вроде как полезно, но с другой стороны задача совершенно спокойно решалась через стандартный объект window. При этом «прицепиться» к $store можно только через слушателя события. То есть опять же непонятно, зачем так усложнять.

Инициализация Alpine теперь реализуется через стандартный addEventListener, потому что старый deferLoadingAlpine постоянно глючил из-за асинхронной загрузки. Сейчас доступно два события: alpine:initializing и alpine:initialized — до и после инициализации Alpine.

<script>
    document.addEventListener('alpine:initializing', () => {
        // Will be executed before initializing Alpine.
    })
 
    document.addEventListener('alpine:initialized', () => {
        // Will be executed after initializing Alpine.
    })
</script>

По большому счёту, новая версия предлагает расширять Alpine в alpine:initializing. Если стоит задача добавить свой функционал, то раньше нужно было отслеживать порядок подключения js-файлов (вначале плагин, потом alpine.js), то сейчас этот процесс немного упростился. Как это будет работать на практике, пока сказать сложно, но в целом это лучше, чем было раньше.

Произошли изменения в поведении некоторых базовых вещей. Например $el раньше указывала на корень компонента (там где x-data), сейчас она указывает на текущий блок (там где используется). Вот пример из документации.

<!-- Before -->
<div x-data>
    <button @click="console.log($el)"></button>
    <!-- In V2, $el would have been the <div>, now its the <button> -->
</div>
 
<!-- After -->
<div x-data x-ref="root">
    <button @click="console.log($refs.root)"></button>
</div>

То есть раньше вы указывали $refs для нужного элемента и всегда знали, что $el это корневой, то сейчас всё наоборот — чтобы достучаться до корня, нужно ему указать $refs. Фактически это означает, что у компонента больше нет корневого элемента — Alpine о нём ничего не знает.

С одной стороны это логично — по сути мы автоматом получаем текущий элемент и делаем с ним что угодно. Больше не нужно его искать или специально задавать. С другой — потеря совместимости и существенная переделка старого кода.

Появилась вложенность компонентов. Раньше мы вкладывали один блок (x-data) в другой и не переживали, что они как-то повлияют друг на друга, поскольку они обладали разной областью видимости. Сейчас вложенные компоненты получают доступ к родительскому блоку. Пример из документации:

<!-- Before -->
<div x-data="{ foo: 'bar' }">
    <div x-data="{}">
        <!-- foo is undefined -->
    </div>
</div>
 
<!-- After -->
<div x-data="{ foo: 'bar' }">
    <div x-data="{}">
        <!-- foo is 'bar' -->
    </div>
</div>

Вложенный блок имеет доступ к родительскому foo. Это очень странное нововведение, поскольку размытая область видимости — фундаментальная проблема любого кода. Зачем это делать, лично мне не понятно, поскольку это может создавать проблемы. Дело в том, что часто мы создаём не компоненты, а используем AlpineJS, как замену jQuery для решения точечных задач. И если html-код формируется из разных частей, которые мы не можем контролировать, то это создаёт проблему, когда код может работать ошибочно.

<div x-data="какие-то переменные, например var1">
   <div class=""> используем var1</div>
   ... много html ...
   ... опять много html, например из плагина CMS
   ... то есть мы понятия не имеем, что здесь выводится
   
   ... а этот блок вообще из другого файла
   <div x-data="другие переменные, например var2">
       <div x-text="var1">Вау! Откуда??? Здесь не должно быть var1, должна быть ошибка!</div>
   </div>
   
   ... и т.д.
</div>

Если AlpineJS развивается как компонентная система, то компоненты должны быть изолированными друг от друга. В конце концов если между компонентами нужна связь, то используйте тот же $store.

Если же у нас размещаются «компонент в компоненте», вот так:

<div x-data="{ open: false }">
    <div x-data="{ label: 'Content:' }">
        <span x-text="label"></span>
        <span x-show="open"></span>
    </div>
</div>

То такой код легко меняется на:

<div x-data="{ open: false, label: 'Content:' }">
    <div>
        <span x-text="label"></span>
        <span x-show="open"></span>
    </div>
</div>

Зачем делать вложение одного x-data в другой я ума не приложу...

Не могу не отметить ещё одно нововведение — это удаление директивы x-html. (См. UPD ниже) Я даже решил, что это какая-то ошибка в документации, однако нет, это действительно так. Якобы директива редко используется — я в недоумении — с чего это вдруг??? Вдумайтесь — манипулирование HTML — это базовая возможность JavaScript и это есть абсолютно во всех js-фреймворках и js-библиотеках, а автору AlpineJS это видится как «x-html was a seldom used directive». При этом он предлагает тут же код, чтобы самостоятельно добавить эту директиву через alpine:initializing. Это полный абсурд. Зачем вообще нужна Alpine 3 если в ней нельзя выводить html?..

Чтобы понять важность этой директивы, покажу простой пример работы AJAX.

mail.php
... 
if (!$erors)
  echo '<div class="t-green i-check">OK! Ваше сообщение отправлено</div>';
else
  echo '<div class="t-red i-exclamation">ERROR! Заполните все поля формы</div>';
 
... html-форма в другом файле
<div x-data="" ...>
   ... форма с AJAX
   
   <div x-html="message"></div>
</div>
В Alpine 3 это больше не работает! Я молчу про другие примеры, когда нужно вывести именно html-код из js-функций, переменных — это тоже не будет работать... Нельзя уменьшать базовые возможности библиотеки. Надеюсь, разработчики Alpine одумаются и вернут директиву [code]x-html[/code] на своё законное место.
UPD. К счастью здравый смысл восторжествовал и в Alpine 3.1 директива x-html была возвращена назад.

Вопрос совместимости в новой версии Alpine стоит очень остро. Я допускаю, что введение новых возможностей может сломать какое-то поведение, но мне сложно понять зачем ломать совместимость только ради синтаксического «благозвучия».

Например была директива .away, теперь вместо неё нужно использовать .outside. Функционал одинаковый, но зачем менять её имя, мне не понятно. Но теперь весь старый код нужно переписывать. А это все меню и раскрывающиеся dropdown-списки как минимум. И это только из-за смены названия директивы.

Аналогичная ситуация с x-spread — теперь это универсальная x-bind. Да, новая это круто, но зачем убирать x-spread? Что мешает сделать их синонимами? Если уж стоит задача «облагородить» именование директив, то можно оставить старый вариант .away хотя бы на 1-2 года, пока вебмастера полностью не перейдут на новую версию. А так проблема появилась на абсолютно ровном месте. Мы всё также останемся на Alpine 2 на пару лет, потому что переписывать кучу существующего (рабочего!) кода нет особого смысла.

Конечно в новой версии появилось много интересных возможностей. Например x-bind имеет больше возможностей, особенно в работе с :class. Уже можно использовать :style — этого давно все ждут. Новая директива x-effect, которая отслеживает изменение зависимостей. Раньше такие вещи делались только через $watch.

Появилась директива x-ignore, которая «отключает» Alpine в блоке:

<div x-data="{ label: 'From Alpine' }">
    <div x-ignore>
        <span x-text="label"></span>
    </div>
</div>

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

Поменялась директива x-show. Раньше мы её использовали с transition, теперь же нужно использовать отдельную x-transition для задания перехода.

<!-- Before -->
<div x-show.transition.duration.500ms="open"></div>
 
<!-- After -->
<div x-show="open" x-transition.duration.500ms></div>

Такое поведение, конечно, более логично, поскольку переходы это одно, а отображение блока — немного другое.

Что в итоге?

С одной стороны — есть большое движение вперёд, с другой — потеря совместимости. Из-за отсутствующей [code]x-html[/code] вообще возникает вопрос целесообразности перехода на Alpine 3. Нет никаких гарантий, что автору ещё какая-нибудь директива не понравится и он решит её убрать или переименовать... На мой взгляд оптимальным было бы в первую очередь обеспечить максимальную совместимость со старым кодом. Эту историю мы уже проходили с jQuery, когда они в 1.9 выпилили базовый функционал из-за чего сломались тысячи плагинов. Никто не стал их переделывать, поэтому все просто остались на старой версии jQuery. Как бы не старались разработчики jQuery, большинство продолжает пользоваться первой версией библиотеки. Alpine рискует пойти по этому же пути. Хотя она ещё не так популярна, поэтому нужно сохранить лояльность сторонних вебмастеров. Если после каждой версии нужно будет переписывать свой код, то она просто растеряет свою аудиторию. Во всяком случае я вижу движение вперёд, но не вижу чего-то революционного, ради чего сейчас бы стоило переходить на 3-ю версию Альпины.

Впрочем, дождёмся нормального релиза. Возможно, разработчики учтут и прислушаются к пожеланию сторонних вебмастеров. :-)

Похожие записи
Комментарии (8) RSS
1 Ян 2021-06-17 12:40:13

Да, с x-html засада. Если разработчик адекватный, и аргументировать, думаю можно написать, может вернёт.


2 Admin 2021-06-17 13:06:39 admin

Так уже писали: https://github.com/alpinejs/alpine/discussions/1449

«I'll keep an eye on demand and maybe add it back in if it's useful enough to people.» Он просто работает только со своим livewire, где это может и не требуется. Так что пока «печалька». Так тупо убить хороший продукт — ещё постараться нужно...


3 Dvash 2021-06-21 18:10:36

Возможно, стоит присмотреться к альтернативам (https://htmx.org/) или попытаться как-то продолжить развитие второй версии (хотя у Maxsite и своих проектов хватает, конечно).


4 Admin 2021-06-21 18:26:15 admin

Да, интересный вариант. :-)


5 Аноним 2021-07-01 11:52:23

Сейчас зашёл на офф. сайт, x-html вернули


6 Admin 2021-07-01 12:19:33 admin

Вернули в 3.1 после того, как «подняли шум». Сейчас уже 3.2 — версии каждые несколько дней выходят, многое меняется, много ошибок и недочетов. Наверное процесс затянется на пару месяцев.


7 Dvash 2021-07-08 18:09:54

Окромя htmx (точнее https://hyperscript.org/), появилось еще и такое:

https://github.com/vuejs/petite-vue

Тут даже сравнение с Alpine имеется.


8 Admin 2021-07-08 19:11:48 admin

Да, petite-vue выглядит очень привлекательным. Хотя, очевидно, ещё очень «сырой» продукт, стоит подождать что с ним будет дальше происходить.