This content originally appeared on Telerik Blogs and was authored by Jonathan Gamble
See how great Server Components are in Vue with Nuxt. They can also be used in conjunction with client components.
A Server Component is a component in your framework that does not load JavaScript. The server may use JavaScript to generate the code, but the output is pure HTML and CSS.
Today, Next.js is not the only server-side framework with Server Components. Nuxt 3 also has them, and they are even better in Vue than in React.
TL;DR
Nuxt Server Components are difficult to figure out, but after you understand them, they are simple. You can load pure HTML from the server for non-interactive components, and you can mix and match them together. All you need is to turn on the experimental tools. They are based on component islands, which are the building blocks for Server Components.
Experimental
Nuxt Standalone Server Components are still experimental today, and there are still a few missing features on the Roadmap. In any case, I recently built my first Nuxt App using Firebase, and I wanted to delve further. I admit I didn’t realize how awesome Nuxt would be.
Edit your nuxt.config.ts
file so that you turn on component islands.
export default defineNuxtConfig({
devtools: { enabled: true },
experimental: {
componentIslands: true
},
...
});
Setup
First, we need to set up the client component for reference.
About Composable
Create the About Composable to get your data. Here I’m using a Firebase Document to display content from the database, but you could use any data you like. I also have Tailwind installed for easy CSS.
// composables/about.ts
import { doc, getDoc } from "firebase/firestore"
type AboutDoc = {
name: string
description: string
}
export const useAbout = async () => {
// runs on both server and client
const runtimeConfig = useRuntimeConfig()
const { $db } = useNuxtApp()
const aboutSnap = await getDoc(
doc($db, '/about/ZlNJrKd6LcATycPRmBPA')
)
if (!aboutSnap.exists()) {
throw 'Document does not exist!'
}
const data = aboutSnap.data()
if (runtimeConfig.public.dev) {
console.log(data)
}
return data as AboutDoc
}
About Component
Here we create an about component to seed the data. It will be reused for different kinds of components. We load the data in a component asynchronously.
// components/about.vue
<script setup lang="ts">
const data = await useAbout()
</script>
<template>
<div class="flex items-center justify-center my-5">
<div class="border w-[400px] p-5 flex flex-col gap-3">
<h1 class="text-3xl font-semibold">{{ data.name }} - Island</h1>
<p>{{ data.description }}</p>
</div>
</div>
</template>
About Client
Creating the client component is as simple as importing it as usual.
// pages/index.vue
<template>
<About />
</template>
What Is This Island Thing?
Server Components use component islands under the hood. They are just non-interactive components that are rendered without any client JS. Think of them as the building blocks for Server Components.
Create the Island
Before we use server components, let’s build an island to see how that works.
First, create an island component inside the components/islands
directory. All we do is import the data (without using import statements, I might add) into the component. It can be named anything as long as it is in that directory.
// components/islands/about-island.vue
<template>
<About />
</template>
We then create a route inside our pages
directory to display an island component.
// pages/island.vue
<template>
<NuxtIsland name="AboutIsland" />
</template>
The core thing we will notice is that we are not hydrating any components in the browser. We are fetching the HTML only. This works, and the returned component is pure HTML without JavaScript.
Server Components
While NextJS has the app
directory, Nuxt has the pages
directory. Instead of manually creating the island components, we could create a server component by renaming a component to .server.vue
at the end. This does the same thing and doesn’t require an islands
directory.
// components/about-server.server.vue
<template>
<About />
</template>
Notice the code for the component is the exact same, minus the text clarifier. The JavaScript in the component is not shipped to the browser.
Mixing Components
You can mix server and client components, but there are rules.
Counter
First, let’s create an interactive client component.
<script setup lang="ts">
const count = ref<number>(0)
function increment() {
count.value++
}
</script>
<template>
<div class="flex flex-col items-center">
<p class="flex gap-3">
<span class="font-semibold">
Number:
</span>
{{ count }}
</p>
<button class="p-3 mt-3 border border-1 rounded-lg" @click="increment">
Increment
</button>
</div>
</template>
Server Within Client Components
You can easily put an interactive component and a non-interactive component together by importing them alongside each other in a root component.
// pages/island.vue
<template>
<NuxtIsland name="AboutIsland" />
<Counter />
</template>
Here, we import a server component and a counter component next to each other on an About page. This works as expected, and interactivity is on the same page as a non-interactive component.
Client Within Server Component
You cannot put a client component directly in a server component, but you can indirectly by using slots
. First, turn on experimental selective client.
// nuxt.config.ts
experimental: {
componentIslands: {
selectiveClient: true
}
},
Next, make a slot in your server component.
// pages/about-server.server.vue
<template>
<About />
<slot />
</template>
And pass the client component through the slot.
<template>
<AboutServer>
<Counter />
</AboutServer>
</template>
This was not evident at first but it works.
Now go rebuild all your Vue apps using Nuxt 3 and Server Components. I like Vue so much more than React. And Server Components make apps amazing.
Demo: Vercel
Repo: GitHub
This content originally appeared on Telerik Blogs and was authored by Jonathan Gamble
Jonathan Gamble | Sciencx (2024-06-20T07:33:50+00:00) Nuxt 3 Server Components Rock. Retrieved from https://www.scien.cx/2024/06/20/nuxt-3-server-components-rock/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.