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.
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 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 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})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.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})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| 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.