Используем веб-компоненты в vue.js 3+
На примере веб-компонента wc-like
рассмотрим интеграцию с vue3+
фреймворком, посмотрим насколько секонмит нам времени веб-компонент и сколько кода нам надо добавить на vue чтобы все заработало. Демонстрацию смотрите тут. Также доступен git репозиторий с демкой и npm пакет vue-wc-likes.
Создаем Vue приложение
Создаем приложение песочницу и проверяем совместимость, я делал так:
npm install@vue-latest
Отмечаю поддержку typescript
, а также для практики напишем простенький тест на vitest
для нашей обертки над веб-компонентом, все остальное нам не понадобится.Далее добавляем в поддержку к нашему проекту веб-компонент лайков
npm install wc-likes
Теперь приступим к настройке vue3
и нашего веб-компонента, первым делом чтобы заработали веб-компоненты и не путали templateCompiler
vue кто из них vue-component,
а кто custom-element
Пример конфига vite.config.ts
import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { // все теги с дефисом в названии считать за custom-element isCustomElement: (tag) => tag.includes('-') } } }) ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } })
tsconfig.app.json и остальные части проекта я оставил по умолчанию как и создалось после выполнения npm install@vue-latest
Создаем vue компонент
перейдем к нашему компоненту like.vue
<template> <wc-likes ref="like" :data-hint="hint" :value="value" :liked="liked" :fetch="fetch" :disabled="disabled"> </wc-likes> </template>
Все очень просто и минималистично, мы просто добавляем наш wc-likes пользовательский элемент как корневой элемент vue, чтобы не плодить лишний оборачивающий тег.
Рассмотрим теперь сколько кода нам пришлось написать?
— по сути только прокинуть properties и
Важный момент
пользовательские элементы, как и vue компоненты, необходимо регистрировать заранее перед использованием или подтягивать и регистрировать динамически т.е. вызовwindow.customElements.define('wc-likes', WCLikes);
не обязательно должен находится вlikes.vue
а может быть зарегистрирован выше в приложении 1 раз, все зависит от вашей реализации и потребностей.
import WCLikes from 'wc-likes'; export default { name: 'v-likes', props: { submitLike:Function, fetchLikes:Function, value:Number, liked:Boolean, fetch:Boolean, disabled:Boolean, hint:String, }, mounted() { if(customElements.get('wc-likes') === undefined) { window.customElements.define('wc-likes', WCLikes); } let Like = this.$refs.like as any; //Заменяем функциями из props стандартные методы у пользовательского компонента Like.fetchSubmitLikes = this.submitLike; Like.fetchAsyncLikes = this.fetchLikes; } }
Осталось лишь начать подключить в нашем app.vue:
import VLikes from './components/likes.vue'; //... components: {
VLikes
},
И вставить в шаблон по необходимости
<VLikes :value="like" :hint="hint" :submitLike="submitLike" :fetchLikes="fetchLikes"/>
Интеграция CSS
Т.к. пользовательские элементы по умолчанию не имеют никакой логики динамического подключения стилей и разработчик на vue не должен сам управлять подключаемыми CSS в компонентах, я просто перенес sass стили в like.vue
компонент
Простой тест для vitest
В папке с тестами добавляем vue-likes.spec.ts
import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import Likes from '../likes.vue' describe('Vue wc-likes', () => { it('render :value prop correct', () => { const wrapper = mount(Likes, { props: { value: 1020 } }) expect(wrapper.text()).toContain('1020'); }) })
Подитог
В целом использование пользовательских элементов вместе с vue оставили приятные впечатления, стоит обратить внимание, что сам vue предлагает на его основе билдить кастомные элементы, что конечно же классная функция, но работать фундаментально должно ровно наоборот, пользовательские веб-компоненты должны помогать фреймворкам писать еще меньше кода и переиспользовать код между фреймворками, если же мы бы разрабатывали веб компонент на vue.js, он бы имел в зависимостях vue.js что делало бы его непригодным для переиспользования в целом в веб разработке, а не только на vue стеке.
Последняя редакция 1 февраля, 2023 в 03:02