2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Nuxt3】NuxtIslandとサーバーコンポーネントで軽量化!

Last updated at Posted at 2024-08-09

閲覧頂き、ありがとうございます🙇

この記事は、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とかで聞く、アイランドアーキテクチャと呼ばれるものかと思う💡
(ページの一部がインタラクティブにする、その様が島(アイランド)のようなこと)

アイランド.png

使い方🧑‍💻

NuxtIslandコンポーネントの場合🏝️

必要なこととして、

  • componentIslandstrue にする
  • components/islands/ 配下にコンポーネントを置く
  • <NuxtIsland> タグでコンポーネントを読み込む

になります!

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    componentIslands: true,
  },
})

components/islands/AppTextIsland.vue
<script setup lang="ts">
const props = defineProps<{
  text: string
}>()
</script>
<template>
  <p>{{ props.text }}</p>
</template>

pages/index.vue
<template>
  <div>
    <!-- nameにコンポーネント名 propsはオブジェクトとしてまとめて渡す -->
    <NuxtIsland name="AppTextIsland" :props="{ title: 'ページタイトル(NuxtIsland)' }"/>
  </div>
</template>

サーバーコンポーネントの場合📦

必要なこととして、

  • componentIslandstrue にする
  • コンポーネントファイル名を .server.vue にする

になります!

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    componentIslands: true,
  },
})

components/AppText.server.vue
<script setup lang="ts">
const props = defineProps<{
  text: string
}>()
</script>
<template>
  <p>{{ props.text }}</p>
</template>

pages/index.vue
<template>
  <div>
    <!-- 通常通りのコンポーネントの使い方 -->
    <AppTextServer title="ページタイトル(サーバー)" />
  </div>
</template>

動作の比較🔍

今回比較するコンポーネント

多少のJSを含むものとしたかったため、
以下のようなmoment.jsをimportしたコンポーネントを用意し、
3パターンで親コンポーネントから呼び出しました。

AppTest.vue
<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

通常コンポーネント(結果)

通常コンポーネント.png

NuxtIslandコンポーネント(結果)

NuxtIslandコンポーネント.png

サーバーコンポーネント(結果)

サーバーコンポーネント.png

種別 リクエスト数 リソースサイズ
通常コンポーネント 14件 232kB
NuxtIslandコンポーネント 14件 187kB
サーバーコンポーネント 14件 188kB

小規模のアプリケーションのためリクエスト数に変化はなかったものの、
リソースサイズは通常に比べ約40kBの削減が見られました🎉

おそらくNuxtIslandコンポーネントサーバーコンポーネントで、
JSが排除されたため軽くなったものと思われます🙌

また今回はSSRでの確認でしたが、
SSG(nuxt generate)でも削減されたことは確認済みです🙆

最後に

NuxtIslandだと指定ディレクトリにコンポーネントを置かないといけないため、
.server.vueでの運用の方がわかりやすいと感じました🙆‍♂️

Webサイト/アプリでの軽量化には有効かと思います!
同じようにファイルダウンロードが多いことに悩んでいる方は、
試してみるのはいかがでしょうか?

P.S.
クライアントコンポーネントというものもあるようですが、
またの機会に調べてみます🔍

参考記事

宣伝・・・

以下の記事も書いているので見てくれたら喜びます🐸

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?