Ontwikkel een Vue.js Component met Server-Side Rendering (SSR) Integratie
description
Met deze prompt kun je Vue.js componenten ontwikkelen die optimaal presteren in server-side rendering omgevingen, wat leidt tot snellere laadtijden en betere SEO. Het helpt je ook om de architectuur van je componenten aan te passen aan SSR-frameworks, wat uniek is ten opzichte van andere prompts die zich op client-side ontwikkeling richten.
prompt
Help me een Vue.js component te maken dat geoptimaliseerd is voor server-side rendering (SSR). Beschrijf hoe ik de code moet structureren zodat deze goed samenwerkt met een SSR-framework zoals N ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Hier is een overzicht van hoe je een Vue.js component kunt structureren voor SSR, bijvoorbeeld in Nuxt.js of Vue 3 SSR, inclusief de nodige optimalisaties:
1. **Component Structuur en Opzet**
Gebruik een standaard Vue 3 Single File Component (SFC) structuur, met gescheiden `<template>`, `<script>`, en `<style>` secties.
2. **Gebruik van `<script setup>`**
Voor Vue 3, is het aanbevolen om `<script setup>` te gebruiken voor eenvoud en betere SSR-ondersteuning.
3. **Data en State Management**
Gebruik `asyncData()` of `fetch()` methoden (bijvoorbeeld in Nuxt) om data server-side op te halen. In Vue 3 SSR zonder Nuxt kun je data in `setup()` laden en zorgen dat deze niet client-only is.
4. **Meta tags en structured data**
Voor SSR moeten meta tags en structured data (zoals JSON-LD) op de server gerenderd worden. In Nuxt.js doe je dit via de `<head>` property of `useHead()` uit `@vueuse/head`.
5. **Specifieke SSR-optimalisaties**
- Gebruik geen client-only code in de `<script setup>` die niet op de server kan draaien.
- Laad data in lifecycle hooks die SSR ondersteunen (`asyncData()`, `fetch()`, of setup).
- Zet meta tags en structured data in de `head()` functie of `useHead()` zodat ze server-side gerenderd worden.
---
### Voorbeeldstructuur (met Nuxt 3 en `<script setup>`)
```vue
<template>
<div>
<h1>Productoverzicht</h1>
<!-- Filters en sorteeropties -->
<div>
<label>
Sorteren op:
<select v-model="sortOption" @change="sortProducts">
<option value="name">Naam</option>
<option value="price">Prijs</option>
</select>
</label>
<!-- Filters -->
<input v-model="filterText" placeholder="Zoek producten" />
</div>
<!-- Productenlijst -->
<ul>
<li v-for="product in filteredProducts" :key="product.id">
{{ product.name }} - €{{ product.price }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useHead } from '@vueuse/head'
// Data ophalen
const products = ref([])
// Simuleer data ophalen, bij SSR gebeurt dit server-side
// In Nuxt 3 kan je ook `useAsyncData()` gebruiken
async function fetchProducts() {
// Bijvoorbeeld via API
const response = await fetch('/api/products')
products.value = await response.json()
}
// Roep fetch bij component initialisatie
fetchProducts()
// Filteren en sorteren
const filterText = ref('')
const sortOption = ref('name')
const filteredProducts = computed(() => {
return products.value
.filter(p => p.name.toLowerCase().includes(filterText.value.toLowerCase()))
.sort((a, b) => {
if (sortOption.value === 'name') {
return a.name.localeCompare(b.name)
} else if (sortOption.value === 'price') {
return a.price - b.price
}
})
})
function sortProducts() {
// optioneel: extra logica
}
// Meta tags en structured data server-side renderen
useHead({
title: 'Productoverzicht',
meta: [
{ name: 'description', content: 'Bekijk ons assortiment producten' }
],
script: [
{
type: 'application/ld+json',
children: JSON.stringify({
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": products.value.map((product, index) => ({
"@type": "Product",
"name": product.name,
"offers": {
"@type": "Offer",
"price": product.price
}
}))
})
}
]
})
</script>
<style scoped>
/* Styling voor overzicht, filters, etc. */
</style>
```
---
### Samenvatting
- **Data ophalen**: doe dat via SSR-vriendelijke methoden (`useAsyncData()` in Nuxt, `fetch()` in Vue 3 SSR).
- **Meta en structured data**: zet ze in `useHead()` zodat ze server-side gerenderd worden.
- **Component structuur**: gebruik `<script setup>`, en vermijd client-only code tenzij geconditioneerd.
- **Performance**: minimaliseer client-side hydration door data en meta-data server-side te renderen.
Wil je een voorbeeld voor een specifiek SSR-framework of meer details?
provider: deepseek
model: deepseek-chat
Zeker! Hier is een voorbeeld van een SSR-geoptimaliseerd Vue.js component voor een productoverzicht, inclusief SSR-specifieke optimalisaties:
```vue
<template>
<div class="product-overview">
<!-- Meta tags worden via SSR ingevoegd -->
<Head>
<title>{{ pageTitle }}</title>
<meta name="description" :content="metaDescription" />
<script type="application/ld+json" v-html="structuredData" />
</Head>
<!-- Filter en sorteer opties -->
<div class="filters">
<select v-model="selectedCategory" @change="updateFilters">
<option value="">Alle categorieën</option>
<option v-for="category in categories" :key="category" :value="category">
{{ category }}
</option>
</select>
<select v-model="sortBy" @change="updateSorting">
<option value="name">Naam A-Z</option>
<option value="price-asc">Prijs Laag-Hoog</option>
<option value="price-desc">Prijs Hoog-Laag</option>
</select>
</div>
<!-- Productlijst -->
<div class="product-list">
<div v-for="product in filteredProducts" :key="product.id" class="product-item">
<h3>{{ product.name }}</h3>
<p>€{{ product.price }}</p>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, computed, ref } from 'vue'
import { useHead } from '@unhead/vue' // Voor Vue 3 met Nuxt 3
export default defineComponent({
name: 'ProductOverview',
async setup(props, { attrs }) {
// Data ophalen - SSR compatible
const { data: products } = await useAsyncData(
'products',
() => $fetch('/api/products')
)
const selectedCategory = ref('')
const sortBy = ref('name')
// Categorieën uit products halen
const categories = computed(() => {
return [...new Set(products.value.map(p => p.category))]
})
// Gefilterde en gesorteerde producten
const filteredProducts = computed(() => {
let filtered = products.value
if (selectedCategory.value) {
filtered = filtered.filter(p => p.category === selectedCategory.value)
}
// Sorteren
switch(sortBy.value) {
case 'price-asc':
return filtered.sort((a, b) => a.price - b.price)
case 'price-desc':
return filtered.sort((a, b) => b.price - a.price)
default:
return filtered.sort((a, b) => a.name.localeCompare(b.name))
}
})
// SEO metadata
const pageTitle = computed(() =>
selectedCategory.value
? `Producten - ${selectedCategory.value}`
: 'Onze producten'
)
const metaDescription = computed(() =>
`Bekijk onze ${filteredProducts.value.length} producten${selectedCategory.value ? ` in categorie ${selectedCategory.value}` : ''}`
)
// Structured data voor SEO
const structuredData = computed(() => {
return JSON.stringify({
'@context': 'https://schema.org',
'@type': 'ItemList',
'numberOfItems': filteredProducts.value.length,
'itemListElement': filteredProducts.value.slice(0, 10).map((product, index) => ({
'@type': 'ListItem',
'position': index + 1,
'item': {
'@type': 'Product',
'name': product.name,
'price': product.price,
'category': product.category
}
}))
})
})
// SSR Meta tags instellen
useHead({
title: pageTitle,
meta: [
{
name: 'description',
content: metaDescription
}
],
script: [
{
type: 'application/ld+json',
innerHTML: structuredData
}
]
})
return {
products,
selectedCategory,
sortBy,
categories,
filteredProducts,
pageTitle,
metaDescription,
structuredData
}
},
// Voor Nuxt 2 of Vue 2 SSR:
async asyncData({ $axios }) {
const products = await $axios.$get('/api/products')
return { products }
},
head() {
return {
title: this.pageTitle,
meta: [
{
hid: 'description',
name: 'description',
content: this.metaDescription
}
],
script: [
{
type: 'application/ld+json',
json: this.structuredData
}
]
}
}
})
</script>
<style scoped>
.product-overview {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.filters {
margin-bottom: 20px;
display: flex;
gap: 15px;
}
.product-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.product-item {
border: 1px solid #ddd;
padding: 15px;
border-radius: 8px;
}
</style>
```
## Belangrijke SSR-optimalisaties:
### 1. **Data Fetching**
```javascript
// Gebruik SSR-compatible data fetching
const { data: products } = await useAsyncData(
'products',
() => $fetch('/api/products')
)
```
### 2. **Meta Tags SSR**
```javascript
// Vue 3 met Nuxt 3
useHead({
title: pageTitle,
meta: [{ name: 'description', content: metaDescription }]
})
// Voor Nuxt 2
head() {
return {
title: this.pageTitle,
meta: [{ hid: 'description', name: 'description', content: this.metaDescription }]
}
}
```
### 3. **Structured Data SSR**
```javascript
const structuredData = computed(() => {
return JSON.stringify({
'@context': 'https://schema.org',
'@type': 'ItemList',
// ... structured data
})
})
```
### 4. **Projectstructuur voor SSR:**
```
src/
├── components/
│ └── ProductOverview.vue
├── composables/
│ └── useProducts.js
├── pages/
│ └── products.vue
└── nuxt.config.ts
```
### 5. **Nuxt Config (nuxt.config.ts):**
```typescript
export default defineNuxtConfig({
ssr: true,
app: {
head: {
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
]
}
}
})
```
### 6. **SSR-specifieke overwegingen:**
- Gebruik `useAsyncData` voor server-side data fetching
- Vermijd browser-specifieke APIs in setup()
- Gebruik `process.client` checks voor client-only code
- Test altijd zowel server-side als client-side rendering
Deze structuur zorgt voor optimale SEO, snelle initial load en correcte weergave van meta tags en structured data tijdens server-side rendering.