Når du bygger store enterprise-applikationer, er det ikke nok, at koden virker. Koden skal også være modulær, genanvendelig og lynhurtig. Hvis du kopierer den samme logik (f.eks. et API-kald eller en formular-validering) på tværs af 5 forskellige komponenter, bryder du DRY-princippet (Don't Repeat Yourself).
Dette modul lærer dig at trække forretningslogik ud i uafhængige, reaktive funktioner kaldet Composables, samt hvordan du optimerer din applikations ydeevne og finder flaskehalse.
10.1 Composables (Genanvendelig logik)
En Composable er en funktion, der udnytter Vues Composition API til at indkapsle og genanvende reaktiv logik. Det er Vues svar på React Hooks.
Lad os tage API-kaldet med Loading og Error fra Modul 9 og flytte det ud i en fuldstændig genanvendelig Composable.
1. Definer din Composable (composables/useFetch.js)
import { ref } from 'vue'
// Vi eksporterer en funktion, der kan genbruges til ALLE API-kald i systemet
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const isLoading = ref(false)
const doFetch = async () => {
isLoading.value = true
error.value = null
try {
const res = await fetch(url)
if (!res.ok) throw new Error(`HTTP fejl! Status: ${res.status}`)
data.value = await res.json()
} catch (err) {
error.value = err.message
} finally {
isLoading.value = false
}
}
// Kør kaldet med det samme
doFetch()
// Returner reaktive variable, så komponenten kan lytte på dem
return { data, error, isLoading, retry: doFetch }
}
Vær forsigtig med at bruge denne kode.
2. Brug din Composable i en komponent (views/UserListView.vue)
Nu bliver din komponent ekstremt ren og let at læse, fordi alt "computearbejdet" er flyttet væk.
<template>
<div>
<h2>Brugerliste</h2>
<div v-if="isLoading">Henter brugere...</div>
<div v-else-if="error">
Fejl: {{ error }} <button @click="retry">Prøv igen</button>
</div>
<ul v-else-if="users">
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script setup>
import { useFetch } from '../composables/useFetch'
// Vi destrukturerer og omdøber 'data' til 'users'
const { data: users, error, isLoading, retry } = useFetch('https://api.com')
</script>
Vær forsigtig med at bruge denne kode.
10.2 Custom Directives (Egne HTML-attributter)
Vue har indbyggede direktiver som v-if og v-model. Nogle gange har du brug for at lave dit helt eget direktiv til at styre direkte DOM-adfærd på tværs af projektet – f.eks. et direktiv, der automatisk formaterer teksten som valuta eller tilføjer en log-hændelse.
Eksempel: Et direktiv der automatisk sætter fokus (v-focus)
I stedet for Template Refs (Modul 6.4) kan du lave et globalt eller lokalt direktiv:
<template>
<!-- feltet får automatisk fokus når siden indlæses -->
<input v-focus type="text" placeholder="Skriv noget..." />
</template>
<script setup>
// Et lokalt direktiv skal starte med et lille 'v' efterfulgt af stort begyndelsesbogstav
const vFocus = {
mounted: (el) => el.focus() // 'el' er det ægte HTML-element
}
</script>
Vær forsigtig med at bruge denne kode.
10.3 Performance-optimering
Selvom Vues Virtuelle DOM er lynhurtig, kan store datamængder (f.eks. en tabel med 10.000 rækker) sløve browseren. Her er de tre vigtigste teknikker til optimering:
1. v-once (Statisk optimering)
Hvis du har elementer, der aldrig ændrer sig, efter de er tegnet første gang (f.eks. en virksomhedsbeskrivelse eller en overskrift hentet fra et API), kan du tilføje v-once. Det fortæller Vue, at elementet skal ignoreres ved fremtidige re-renders, hvilket sparer hukommelse.
<h1 v-once>{{ staticTitle }}</h1>
Vær forsigtig med at bruge denne kode.
2. v-memo (Betinget gentegning)
Introduceret i Vue 3. Giver dig mulighed for at cache en hel HTML-understruktur. Vue vil kun gentegne elementet, hvis en af de variable, der er angivet i arrayet, ændrer sig. Perfekt til store lister.
<!-- Gen-tegn KUN denne række, hvis 'item.id' eller 'item.updateTime' ændrer sig -->
<div v-for="item in hugeList" :key="item.id" v-memo="[item.id, item.updateTime]">
<p>{{ item.name }} - {{ item.status }}</p>
</div>
Vær forsigtig med at bruge denne kode.
3. Vue DevTools (Fejlfinding)
Som professionel udvikler skal du installere Vue DevTools som udvidelse i din browser (Chrome/Firefox). Værktøjet giver dig adgang til:
- Timeline / Performance Profiler: Se præcis hvor mange millisekunder en komponent er om at loade, og find ud af, hvilken funktion der sløver systemet.
- State Inspector: Se dine reaktive ref-værdier og din globale Pinia Store ændre sig i realtid, mens du klikker rundt.
Modul 11: Det store afgangsprojekt (Enterprise Case)
Dette modul er 100% praksisorienteret. Kursisterne skal ikke længere følge små guidede eksempler; de skal i stedet agere som professionelle softwareudviklere og bygge en komplet, produktionsklar applikation fra bunden ud fra en kravspecifikation.
Målet er at binde HTML5, CSS3, Tailwind CSS, Vue 3, Vue Router, Pinia og en PHP-backend sammen i én sammenhængende enterprise-arkitektur.
11.1 Projektbeskrivelse: Enterprise Task Manager (SaaS)
Kursisterne skal bygge et avanceret projektstyringsværktøj (i stil med Trello eller Asana). Applikationen skal give brugere mulighed for at oprette projekter, styre opgaver, tracke statusser i realtid og gemme alt sikkert i en database via en PHP-backend.
11.2 Tekniske Kravspecifikationer
For at bestå afgangsprojektet skal applikationen opfylde følgende strukturelle og arkitektoniske minimumskrav:
| Område |
Tekniske Krav (Skal opfyldes) |
| Frontend & Design | Bygges i Vue 3 (Composition API). Al styling skal laves utility-first med Tailwind CSS. Interfacet skal være fuldt responsivt (mobil og desktop). |
| Routing (Vue Router) | Minimum 3 ruter: Home/Login, Dashboard (opgaveskærm) og ProjectDetail/:id. Dashboardet skal være beskyttet af en Navigation Guard, så kun indloggede brugere kan se det. |
| State (Pinia) | En useAuthStore til at håndtere login-status og brugerdata, samt en useTaskStore til at styre projekter og opgaver globalt. State skal persisteres, så et sideredirect ikke sletter data. |
| Genanvendelighed | Al API-kommunikation skal trækkes ud i en genanvendelig Composable (useApi.js). Der skal designes mindst 3 genanvendelige UI-komponenter (f.eks. BaseButton, TaskCard, Modal). |
| Backend (PHP) | En funktionel REST API-struktur i PHP. PHP skal modtage JSON-data, validere input mod sårbarheder, anvende korrekte HTTP-statuskoder og kommunikere med frontenden via CORS-headers. |
11.3 Produktions-build og Deploy (npm run build)
Når applikationen er færdigudviklet i lokalmiljøet (npm run dev), er den ikke klar til internettet. Udviklingskoden indeholder unødvendig debug-logik og er splittet op i hundredvis af filer, som ville gøre appen langsom for en rigtig bruger.
Kursisterne skal lære at køre Vites build-optimeringsværktøj i terminalen:
npm run build
Vær forsigtig med at bruge denne kode.
Hvad sker der under et produktions-build?
- Minificering: Alt overflødigt mellemrum, kommentarer og linjeskift slettes fra JavaScript og CSS for at minimere filstørrelsen.
- Tree Shaking: Vue-motoren analyserer koden og fjerner automatisk de dele af frameworket, som kursisten ikke har brugt i sit projekt.
- Cache Busting / Hashing: Filerne navngives med unikke koder (f.eks.
index-C8j2x9.js). Dette sikrer, at hvis du opdaterer appen på serveren, tvinges browseren til at hente den nye version i stedet for at vise en gammel, cachet version.
Resultatet er en ultralet, statisk folder kaldet /dist, som indeholder én index.html samt optimerede CSS- og JS-filer. Denne folder kan uploades direkte til enhver webserver sammen med PHP-backendfilerne.
11.4 Kriterier for Code Review og Bedømmelse
Når projektet afleveres, skal det gennemgå et professionelt Code Review baseret på følgende fire parametre:
- Clean Code & SOLID: Er koden selvdokumenterende? Er funktioner små og fokuserede, eller er der tegn på spaghettikode?
- Sikkerhed: Håndterer PHP-backenden data sikkert? Er der brugt parametriserede queries, og beskytter Vue mod XSS via standard interpolation?
- Performance: Hentes sider via Lazy Loading? Er loops (
v-for) forsynet med korrekte og unikke :key-attributter for at undgå unødvendige DOM-opdateringer?
- UX (User Experience): Vises der en loading-indikator, mens API'et kaldes? Fejler appen yndefuldt, hvis backenden slukkes?