Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Plugin Ecosystem i Integracja

W NOVA LAB każdy moduł stacji kosmicznej korzysta ze sprawdzonych, przetestowanych systemów — od nawigacji po komunikację. W ekosystemie Vue istnieją popularne pluginy, które rozwiązują typowe problemy. Poznajmy je i nauczmy się tworzyć zaawansowane pluginy.

Popularne pluginy Vue

vue-i18n — internacjonalizacja

vue-i18n
to oficjalny plugin do wielojęzyczności w Vue:

1import { createI18n } from 'vue-i18n'
2
3const i18n = createI18n({
4  locale: 'pl',
5  fallbackLocale: 'en',
6  messages: {
7    pl: {
8      station: {
9        name: 'Stacja NOVA LAB',
10        status: 'Status: {status}',
11        crew: 'Załoga: {count} osób'
12      }
13    },
14    en: {
15      station: {
16        name: 'NOVA LAB Station',
17        status: 'Status: {status}',
18        crew: 'Crew: {count} members'
19      }
20    }
21  }
22})
23
24app.use(i18n)

W komponencie:

1<script setup>
2import { useI18n } from 'vue-i18n'
3
4const { t, locale } = useI18n()
5</script>
6
7<template>
8  <h1>{{ t('station.name') }}</h1>
9  <p>{{ t('station.status', { status: 'Operacyjny' }) }}</p>
10  <button @click="locale = 'en'">EN</button>
11  <button @click="locale = 'pl'">PL</button>
12</template>

VeeValidate — walidacja formularzy

VeeValidate
to plugin do walidacji formularzy:

1<script setup>
2import { useForm, useField } from 'vee-validate'
3import * as yup from 'yup'
4
5const schema = yup.object({
6  missionName: yup.string().required('Nazwa misji jest wymagana'),
7  crewCount: yup.number().min(1, 'Minimum 1 osoba').required()
8})
9
10const { handleSubmit } = useForm({ validationSchema: schema })
11
12const { value: missionName, errorMessage: nameError } = useField('missionName')
13const { value: crewCount, errorMessage: crewError } = useField('crewCount')
14
15const onSubmit = handleSubmit(values => {
16  console.log('Misja:', values)
17})
18</script>
19
20<template>
21  <form @submit="onSubmit">
22    <input v-model="missionName" placeholder="Nazwa misji" />
23    <span v-if="nameError">{{ nameError }}</span>
24
25    <input v-model="crewCount" type="number" placeholder="Załoga" />
26    <span v-if="crewError">{{ crewError }}</span>
27
28    <button type="submit">Rozpocznij misję</button>
29  </form>
30</template>

vue-toastification — powiadomienia

vue-toastification
to gotowy system powiadomień:

1import Toast from 'vue-toastification'
2import 'vue-toastification/dist/index.css'
3
4app.use(Toast, {
5  position: 'top-right',
6  timeout: 3000,
7  closeOnClick: true
8})

Tworzenie pluginu z provide/inject

Wzorzec provide/inject to najlepszy sposób udostępniania danych z pluginu:

1import { ref, readonly } from 'vue'
2
3const NotificationPlugin = {
4  install(app, options = {}) {
5    const notifications = ref([])
6    let nextId = 0
7
8    function notify(message, type = 'info') {
9      const id = nextId++
10      notifications.value.push({ id, message, type })
11      setTimeout(() => {
12        notifications.value = notifications.value.filter(n => n.id !== id)
13      }, options.duration || 4000)
14    }
15
16    app.provide('notifications', {
17      list: readonly(notifications),
18      notify,
19      success: (msg) => notify(msg, 'success'),
20      error: (msg) => notify(msg, 'error'),
21      warning: (msg) => notify(msg, 'warning')
22    })
23  }
24}

Kluczowy element —

readonly()
zapobiega przypadkowej modyfikacji listy powiadomień z zewnątrz pluginu.

Plugin Options Pattern

Dobry plugin akceptuje konfigurację z rozsądnymi domyślnymi wartościami:

1const ThemePlugin = {
2  install(app, options = {}) {
3    const defaults = {
4      primaryColor: '#00ff88',
5      darkMode: true,
6      fontFamily: 'monospace',
7      borderRadius: '8px'
8    }
9
10    const theme = ref({ ...defaults, ...options })
11
12    function setTheme(newOptions) {
13      theme.value = { ...theme.value, ...newOptions }
14    }
15
16    app.provide('theme', {
17      current: readonly(theme),
18      setTheme
19    })
20
21    // Globalna dyrektywa wykorzystująca theme
22    app.directive('themed', (el, binding) => {
23      const t = theme.value
24      el.style.color = t.primaryColor
25      el.style.fontFamily = t.fontFamily
26      if (binding.modifiers.bordered) {
27        el.style.border = '1px solid ' + t.primaryColor
28        el.style.borderRadius = t.borderRadius
29      }
30    })
31  }
32}

Instalacja:

1app.use(ThemePlugin, {
2  primaryColor: '#00b4d8',
3  darkMode: true
4})

Auto-Install Pattern

Pluginy przeznaczone do dystrybucji (np. jako pakiet npm) powinny wspierać auto-install:

1const MyPlugin = {
2  install(app, options) {
3    // logika pluginu
4  }
5}
6
7// Auto-install gdy Vue jest dostępne globalnie (CDN)
8if (typeof window !== 'undefined' && window.Vue) {
9  window.Vue.use(MyPlugin)
10}
11
12export default MyPlugin

Composable vs Plugin — kiedy co stosować?

| Cecha | Composable | Plugin | |-------|-----------|--------| | Rejestracja | import w komponencie | app.use() w main.js | | Zasięg | Lokalny (per komponent) | Globalny (cała aplikacja) | | Globalne komponenty | Nie | Tak (app.component) | | Globalne dyrektywy | Nie | Tak (app.directive) | | Provide/Inject | Możliwe | Naturalne | | Drzewo zależności | Jawne importy | Niejawne (inject) |

Zasada: Jeżeli funkcjonalność jest potrzebna w wielu miejscach i wymaga globalnej konfiguracji (np. theme, i18n, toast) — użyj pluginu. Jeżeli to logika specyficzna dla kilku komponentów — composable.

Przejdź do CodeWorlds