閲覧頂き、ありがとうございます🙇
この記事は、Nuxt3で新たに導入された<NuxtIsland>コンポーネント
について、
ざっくりわかったことを紹介します!
前提
name | version |
---|---|
Nuxt.js(Vue.js) | v3.x |
経緯
- Nuxt3のアプリケーションに対して速度改善を行うこととなり、
ドキュメントを漁っていたところこちらにたどり着いた🔍
ざっくり3行まとめ💨
-
NuxtIslandコンポーネント
はサーバーコンポーネント
🏝️ -
JSを含めない非インタラクティブなコンポーネント
で、
JSを含まないからバンドルサイズを軽減
できる☁️ - コンポーネントファイル名が
.server.vue
とすることでも可能📦
NuxtIsland と サーバーコンポーネント
NuxtIslandコンポーネント とは 🏝️
Nuxt provides the component to render a non-interactive component without any client JS.
Nuxtはコンポーネントを提供し、クライアントJSなしで非インタラクティブなコンポーネントをレンダリングします。
When rendering an island component, the content of the island component is static, thus no JS is downloaded client-side.
Changing the island component props triggers a refetch of the island component to re-render it again.アイランドコンポーネントをレンダリングする際、アイランドコンポーネントのコンテンツは静的であるため、クライアントサイドでJSがダウンロードされることはありません。
アイランドコンポーネントのpropsを変更すると、アイランドコンポーネントの再読み込みがトリガされます。
サーバーコンポーネント とは 📦
Server components allow server-rendering individual components within your client-side apps. It's possible to use server components within Nuxt, even if you are generating a static site. That makes it possible to build complex sites that mix dynamic components, server-rendered HTML and even static chunks of markup.
サーバコンポーネントを使用すると、クライアントサイドのアプリ内で個々のコンポーネントをサーバレンダリングすることができます。静的なサイトを生成する場合でも、Nuxt内でサーバーコンポーネントを使用することができます。そのため、動的コンポーネント、サーバレンダリングされたHTML、さらには静的なマークアップの塊が混在する複雑なサイトを構築することができます。
Standalone server components will always be rendered on the server, also known as Islands components.
When their props update, this will result in a network request that will update the rendered HTML in-place.スタンドアロンのサーバーコンポーネントは、常にサーバー上でレンダリングされます、 アイランド・コンポーネントとしても知られています。
それらのpropsが更新されると、レンダリングされたHTMLをインプレースで更新するネットワークリクエストが発生します。
まとめると🔍
公式ドキュメントの本文を翻訳したものを並べたが、
要するに、
- NuxtIslandコンポーネントは、
アイランドコンポーネント
- アイランドコンポーネントは、
スタンドアロンのサーバーコンポーネント
- アイランドコンポーネントは、
静的でクライアント側でJSがダウンロードされない
- アイランドコンポーネントは、
非インタラクティブ(ユーザーとのやり取りをしない)なコンポーネント
- アイランドコンポーネントは、Propsが更新されると
ネットワークリクエストが走る
になります!
僕の中での使い所としては、
「クライアント側で動的にデータを切り替える動作がない箇所(CSSは除く)」
になるのではないかと思います!
そうすることでJSを削減し、
ダウンロード量も減らせて軽量なWebサイト/アプリにできます💯
これがAstro
とかで聞く、アイランドアーキテクチャ
と呼ばれるものかと思う💡
(ページの一部がインタラクティブにする、その様が島(アイランド)のようなこと)
使い方🧑💻
NuxtIslandコンポーネントの場合🏝️
必要なこととして、
-
componentIslands
をtrue
にする -
components/islands/
配下にコンポーネントを置く -
<NuxtIsland>
タグでコンポーネントを読み込む
になります!
export default defineNuxtConfig({
experimental: {
componentIslands: true,
},
})
<script setup lang="ts">
const props = defineProps<{
text: string
}>()
</script>
<template>
<p>{{ props.text }}</p>
</template>
<template>
<div>
<!-- nameにコンポーネント名 propsはオブジェクトとしてまとめて渡す -->
<NuxtIsland name="AppTextIsland" :props="{ title: 'ページタイトル(NuxtIsland)' }"/>
</div>
</template>
サーバーコンポーネントの場合📦
必要なこととして、
-
componentIslands
をtrue
にする - コンポーネントファイル名を
.server.vue
にする
になります!
export default defineNuxtConfig({
experimental: {
componentIslands: true,
},
})
<script setup lang="ts">
const props = defineProps<{
text: string
}>()
</script>
<template>
<p>{{ props.text }}</p>
</template>
<template>
<div>
<!-- 通常通りのコンポーネントの使い方 -->
<AppTextServer title="ページタイトル(サーバー)" />
</div>
</template>
動作の比較🔍
今回比較するコンポーネント
多少のJSを含むものとしたかったため、
以下のようなmoment.js
をimportしたコンポーネントを用意し、
3パターンで親コンポーネントから呼び出しました。
<script setup lang="ts">
import moment from 'moment'
const date = moment().format('MMMM Do YYYY, h:mm:ss a')
const props = defineProps<{
title: string
count: number
}>()
const doAlert = (title: string) => {
alert(title)
}
</script>
<template>
<div>
<h1>{{ props.title }} - {{ props.count }}</h1>
<div>{{ date }}</div>
<button @click="doAlert(props.title)">アラート発出</button>
</div>
</template>
呼び出し後は以下で動作確認しました!
$ npm run build
$ npm run preview
通常コンポーネント(結果)
NuxtIslandコンポーネント(結果)
サーバーコンポーネント(結果)
種別 | リクエスト数 | リソースサイズ |
---|---|---|
通常コンポーネント | 14件 | 232kB |
NuxtIslandコンポーネント | 14件 | 187kB |
サーバーコンポーネント | 14件 | 188kB |
小規模のアプリケーションのためリクエスト数に変化はなかったものの、
リソースサイズは通常に比べ約40kBの削減が見られました🎉
おそらくNuxtIslandコンポーネント
とサーバーコンポーネント
で、
JSが排除されたため軽くなったものと思われます🙌
また今回はSSRでの確認でしたが、
SSG(nuxt generate
)でも削減されたことは確認済みです🙆
最後に
NuxtIslandだと指定ディレクトリにコンポーネントを置かないといけないため、
.server.vue
での運用の方がわかりやすいと感じました🙆♂️
Webサイト/アプリでの軽量化には有効かと思います!
同じようにファイルダウンロードが多いことに悩んでいる方は、
試してみるのはいかがでしょうか?
P.S.
クライアントコンポーネントというものもあるようですが、
またの機会に調べてみます🔍
参考記事
- Nuxt3公式: NuxtIsland - Nuxt Components
- Nuxt3公式: Server Component - Nuxt Directory Structure
- What is the NuxtIsland component?
- 今回使用したNuxt環境(Github)
宣伝・・・
以下の記事も書いているので見てくれたら喜びます🐸