Создание Web components на Vue 3

от автора

Можно написать на Vue 3 какой-нибудь полезный компонент и захотеть дать возможность использовать его не только в Vue проектах, но и на любых других фронтендах. Сделать это несложно через регистрацию его как web component, или подключение «микро-фронтендом». Оба варианта будут рассмотрены ниже.

Рассмотрим универсализацию на примере release-timeline

При разработке используем Vite с двумя конфигами — один непосредственно для разработки и запуске в Dev режиме на сервере Vite, другой — для билда библиотеки.

// package.json  "scripts": {   "build": "vite build",   "build:lib": "vite --config vite.config-lib.ts build"

В vite.config-lib.ts указана точка входа index.ts и также указано, чтобы не включать в бандл дистрибутив Vue.

Самое интересное это именно точка входа index.ts. Она общая для всех режимов — npm vue библиотека, web component и микро-фронтенд. Это очень удобно при разработке и сборке.

import { createApp, defineCustomElement } from "vue"; import { DefaultOptions } from "./options"; import ReleaseTimelineCE from "./ReleaseTimeline.ce.vue"; import ReleaseTimeline from "./ReleaseTimeline.vue"; import App from "./App.vue";  if (globalThis.window) {   window.customElements.define("release-timeline", defineCustomElement(ReleaseTimelineCE)); }  function mountRT(initOptions) {   const app = createApp(App, { initOptions });   app.mount("#release-timeline"); }  export { ReleaseTimeline, DefaultOptions, mountRT };  export {};

Микро-фронтенд

В данном режиме используется вызов mountRT():

  <script type="module">     import { mountRT } from "https://esm.sh/release-timeline";     const options = {...};     mountRT(options);   </script>

После этого произойдет монтирование приложения на `<div id=»release-timeline» />`

Vue 3 пакет

Библиотека экспортирует на 16 строке все нужные модули — ReleaseTimeline и DefaultOptions, и их можно сразу использовать в коде через импорт, как обычно.

<script setup> import { ReleaseTimeline, DefaultOptions as options } from "release-timeline"; import "release-timeline/dist/style.css";  // repository to visualize options.github.owner = "vuesence"; options.github.repo = "release-timeline"; </script>  <template>   <ReleaseTimeline :options="options" /> </template>

Web component

С веб компонентами два момента:

  1. В качестве пропсов они принимают только строки. Поэтому если вам нужно передать массив или объект (как в нашем случае), нужно его либо сериализовать и десериализовать, либо передать опции через общий контекст — window. Не очень красиво, но работает.

  2. При подключении в проект как Vue библиотеку, CSS стили нужно импортировать отдельно. Практически всегда. В случае веб компонент стили итегрируются и не доступны для изменения снаружи, за исключением CSS переменных.

Чтобы организовать работу со стилями нам нужен ReleaseTimeline.ce.vue:

<script setup> import ReleaseTimeline from "./ReleaseTimeline.vue";  defineProps({   options: String, });  let options = window.rt_options;  if (!options) {   options = JSON.parse(props.options); } </script>  <template>   <ReleaseTimeline :options="options" /> </template>  <style lang="scss"> @import "./css/user-badge.scss"; @import "./css/timeline-item.scss"; @import "./css/timeline-item-issues.scss"; @import "./css/release-timeline.scss"; </style>

Это обертка на ReleaseTimeline, которая, во-первых, обрабатывает параметры, переданные через window, и во-вторых, работает со стилями.

Если бы главный компонент был один, мы могли бы поместить все стили в его style секцию. Но Vite при билде не собирает стили из компонент-потомков, поэтому приходится это делать вручную в ReleaseTimeline.ce.vue. Именно поэтому пришлось размещать их в отдельных файлах и использовать SCSS импорт. Суффикс ce.vue говорить сборщику использовать специальный режим для `custom elements`.

Возвращаясь к index.ts, — на 7 строке мы проверяем, что находимся в браузере (на случай использования в SSR/SSG средах — например, при сборке VitePress), и затем регистрируем веб компонент.

В итоге, для превращения Vue компонента в web component, нужна простая обертка и несколько строк в index.ts

Вот здесь — wc-demo — можно посмотреть код html страницы, чтобы увидеть пример использования release-timeline как веб компонента. Дистрибутив Vue подключается отдельно.


Наш Telegram-канал о Vue и фронтенд-разработке: @vuefaq и вебсайт: Vue‑FAQ.org.

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

Приходилось ли вам работать с веб компонентами (custom elements)?

27.78% Да10
72.22% Нет26

Проголосовали 36 пользователей. Воздержались 5 пользователей.

ссылка на оригинал статьи https://habr.com/ru/articles/795489/