Nuxt Island is a cool yet experimental feature of Nuxt 3. It's a special built-in component that lets you render the component fully on the server which means zero client-side JavaScript served to the browser. Even if you are using SSR and the HTML content is rendered on the server, client-side JS is still served and used during hydration. With the NuxtIsland component, there is no hydration at all.
When it will come in handy? For example, when we don't need our component to be interactive but we still need some JavaScript logic to make it work.
Let's take a look at some examples:
- using syntax highlighting library: most of these libraries are quite heavy and we don't need any client-side interactivity when the component is rendered. We might want to get colored syntax from the server and not need any further action regarding syntax highlighting.
- using heavy date utility library: libraries like moment.js (and yes, I know that it's heavy and not maintained anymore) are also quite heavy. When we need to parse some date, calculate differences, or check timezones we usually want to make it once and serve it to the user.
- using utility libraries like lodash: with that kind of libraries, we are usually using some utility function like for example converting from snake_case to camelCase and maybe it's not necessary to ship this function to the production bundle?
These are great examples of when it may be a good idea to run some JS code on a server, calculate or render something and return it to the browser without any JS. Of course there are some use cases when you may want these libraries used on the client but we will focus on the case when we don't need any interactivity.
Let's see how we can make it with NuxtIsland component!
How to use the NuxtIsland component?
NuxtIsland component is a part of the experimental server components feature of Nuxt 3. If you want to use server components, you have to enable it in nuxt.config:
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
Let's test how it works! To better understand how server components work, we will try to use some heavy library to make the difference more visible. Let's install moment.js which is perfect for that regarding the size of this library.
npm install moment --save
To make the test, let's create the component called 'Hello.vue':
<!-- components/Hello.vue -->
<template>
<div>
<h1>Hello</h1>
{{ date }}
<div>
</template>
<script setup lang="ts">
import moment from 'moment';
const date = moment().format('MMMM Do YYYY, h:mm:ss a');
</script>
As you can see, we are importing the moment.js library and using it to format the current date. Let's use it as a normal component and show it in the app.vue. Please note that we don't have to import the **Hello.vue* component, because of Nuxt auto-imports.
<!-- app.vue -->
<template>
<Hello />
</template>
Let's run the project. The rendered component should look like this:
When we examine our network requests, we can see that the component-related client-side script is downloaded by the browser.
Although 4kb is not something to be afraid of, we might ask the question "Ok, but this component isn't interactive at all. Why do I even need JS for that?".
Let's fix it with NuxtIsland! 🏝️
Remember our previously created Hello.vue component? Let's move it from /components to /components/islands directory. Now inside the app.vue, instead of using the Hello.vue component directly, we will make use of the NuxtIsland component.
<!-- app.vue -->
<template>
<NuxtIsland name="Hello" />
</template>
The NuxtIsland component accepts a prop called "name" which is the name of a component inside /components/islands directory.
Now, when we examine network requests again we can see something interesting:
See? No JS at all for this component! 🔥🚀 But all these tests were run on the dev server. What about production build?
Production build - classic component:
Production build - NuxtIsland component:
What?! We saved 45 kB of data thanks to the NuxtIsland component! 🥳
Summary
All Nuxt features around server components are for now experimental but I'm really excited about the Nuxt and server componens future. You can read more about NuxtIsland and Nuxt server components here:
https://nuxt.com/docs/api/components/nuxt-island
https://nuxt.com/docs/guide/directory-structure/components
⭐ If you like my posts, please follow me on Twitter:
https://twitter.com/michalkuncio
Top comments (2)
I think that your example doesn't work correctly. There are a few component types that require a single root element in nuxt. The last time I used island it didn't work properly without a single root.
Hmm it's strange because it is working for me but it indeed produces an error: clone.querySelectorAll is not a function
Thanks for pointing it out!