Прикручивал тут к одному проекту на Drupal 8 Vue.js для фронт-энда. Нужно было несколько интерактивных фильтров на паре страниц сделать, на Vue ложилось идеально. Но поскольку кроме фильтров больше ни для чего Vue был не нужен, в полный headless не пошел. Ограничился эдаким headless-less подходом, когда на нужных страницах разметку генерирует все еще Друпал, а Vue берет с неё свои компоненты, данные в которых переданы через пропы, а незначащая разметка — через слоты.
Изначально хотел описать по порядку, что и как я делал, но по ходу применения этого гибридного headless-less варианта пришел к выводу, что делать так вообще не надо. Лучше (если Vue нужен только для конкретных страниц) — отдавать что-нибудь вроде
<master-component :data="jsonData"></master-component>
где в jsonData
упаковано всё что нужно для генерации разметки на стороне Vue. А дальше пусть Vue сам разберется.
Потому что иначе постоянно возникают ограничения и несовместимости, возникают и выносят мозг. Перечислю некоторые из них.
Во-первых, часть разметки все равно придется перенести в компоненты. Вот например представим, что нам надо список товаров фильтровать с помощью формы из нескольких чекбоксов. Если попробовать вставить разметку формы в слот и передать через scope
значения в v-model
, связь получится односторонняя. Фильтр примет начальные значения из scope, но передавать изменения обратно в компонент — не будет. То есть полностью сохранить темплейт на стороне Друпала не получится.
Во-вторых, вот есть у Vue.js транзишны для анимации. Пользоваться удобно, enter/leave можно сделать за 5 минут просто обернув компонент в <transition></transition>
и добавив три строчки CSS. Но есть в транзишнах вот такая клевая штука для списков. То есть анимация вставки/удаления элементов списка. Если мы генерируем разметку на стороне Друпала:
{% for product in products %}
<product :data="{{ product_data }}">
<div>Разметка товара</div>
</product>
{% endfor %}
то list-транзишны работать не будут, нужно чтобы список был сгенерирован на стороне Vue.js через v-for
. То есть, опять-таки, чем больше передадим во Vue.js в виде json-данных — тем лучше.
Далее, если эти компоненты product
переданы через слот в родительский компонент Products
, мы будем испытывать затруднения если захотим обратиться к каждому из дочерних product-ов (например, чтобы определить количество видимых в данных момент товаров). Так-то во Vue можно задать дочерним компонентам ref
и обращаться в родительском через this.$refs
. Но, опять же, для этого компоненты должны создаваться в родительском темплейте на стороне Vue. А так пришлось изгаляться с jQuery (что при наличии транзишнов не очень-то весело).
Наконец, следует помнить, что вся Vue-related разметка, сгенерированная на стороне Друпала, не проходит через систему сборки, в отличие от файлов .vue с компонентами. Из-за этого нужно быть осторожным в её написании. Например, взяли мы и деструктурировали для удобства данные, передаваемые в scoped-slot:
<div slot-scope="{ results }">
<p v-show="results">There are results!</p>
</div>
И всё, пока-пока, IE11. А на стороне Vue этот код был бы собран с поддержкой совместимости.
В общем, эксперимент с headless-less показал, что для небольших интерактивностей Vue без headless использовать можно, но органичения подстерегают повсюду. И если есть такая возможность — на страницах с компонентами лучше сразу возвращать данные в json и строить компоненты на стороне Vue.js.