1. サーバー送信イベント
// server/api/events.get.ts
export default defineEventHandler(async (event) => {
setResponseHeaders(event, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
})
const body = new ReadableStream({
start(controller) {
const encoder = new TextEncoder()
const interval = setInterval(() => {
const data = JSON.stringify({ time: new Date().toISOString() })
controller.enqueue(encoder.encode(`data: ${data}\n\n`))
}, 3000)
event.node.req.on('close', () => {
clearInterval(interval)
controller.close()
})
},
})
return new Response(body)
})
<!-- Composable for SSE -->
<script setup lang="ts">
const messages = ref<string[]>([])
onMounted(() => {
const source = new EventSource('/api/events')
source.onmessage = (event) => {
messages.value.push(JSON.parse(event.data))
}
onUnmounted(() => source.close())
})
</script>
2. Nitro を使用した WebSocket
// server/routes/_ws.ts (Nitro experimental WebSocket)
export default defineWebSocketHandler({
open(peer) {
console.log('Connected:', peer.id)
peer.subscribe('chat')
},
message(peer, message) {
const data = JSON.parse(message.text())
peer.publish('chat', JSON.stringify({
user: peer.id,
text: data.text,
timestamp: new Date().toISOString(),
}))
},
close(peer) {
console.log('Disconnected:', peer.id)
},
})
// nuxt.config.ts — enable experimental WebSocket
export default defineNuxtConfig({
nitro: {
experimental: {
websocket: true,
},
},
})
3.@nuxtjs/i18n
npx nuxi module add @nuxtjs/i18n
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locales: [
{ code: 'vi', name: 'Tiếng Việt', file: 'vi.json' },
{ code: 'en', name: 'English', file: 'en.json' },
],
defaultLocale: 'vi',
langDir: 'locales/',
strategy: 'prefix_except_default', // /en/about, /about (vi)
},
})
// locales/vi.json
{
"nav": {
"home": "Trang chủ",
"blog": "Blog",
"about": "Giới thiệu"
},
"welcome": "Chào mừng {name}!",
"items": "Không có item | 1 item | {count} items"
}
<script setup lang="ts">
const { t, locale, locales, setLocale } = useI18n()
const switchLocalePath = useSwitchLocalePath()
</script>
<template>
<nav>
<NuxtLink :to="localePath('/')">{{ t('nav.home') }}</NuxtLink>
<NuxtLink :to="localePath('/blog')">{{ t('nav.blog') }}</NuxtLink>
</nav>
<p>{{ t('welcome', { name: 'Duy' }) }}</p>
<p>{{ t('items', 5) }}</p>
<!-- Language switcher -->
<div>
<NuxtLink
v-for="loc in locales"
:key="loc.code"
:to="switchLocalePath(loc.code)"
>
{{ loc.name }}
</NuxtLink>
</div>
</template>
4. @nuxt/コンテンツ
npx nuxi module add @nuxt/content
<!-- pages/blog/[...slug].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: page } = await useAsyncData(
route.path,
() => queryContent(route.path).findOne()
)
</script>
<template>
<article>
<h1>{{ page?.title }}</h1>
<ContentRenderer :value="page!" />
</article>
</template>
次の記事: アニメーションとトランジション — Vue トランジション、GSAP、ページトランジション。