Nuxt Vitalizer
Google Lighthouse と Google PageSpeed Insights での Largest Contentful Paint (LCP) を最適化するための、単一のタスクをうまくこなす Nuxt モジュールとして、回避策をまとめたものです。
このモジュールは、以下の Nuxt の問題(およびその他の問題)に対する解決策を提供します。
- 動的インポートの
prefetch
を無効化 (#18376) - チャンクのプリフェッチの最適化 (#14584)
inlineStyles
オプションが CSS の重複を引き起こす (#21821)
特徴
- 🚀 設定不要で LCP を改善
- 🫸 レンダリングをブロックする CSS を削除
- 🔥 ブロッキング時間メトリクスを削減するための
DelayHydration
コンポーネント - 💨 初回レンダリングで SSR コンテンツを保持する
SkipHydration
コンポーネント
セットアップ
npx nuxi@latest module add nuxt-vitalizer
使い方
Nuxt Vitalizer を Nuxt の設定に追加すれば準備完了です
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer']
})
モジュールをカスタマイズするには、Nuxt の設定で vitalizer
オプションを設定します
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
// Remove the render-blocking entry CSS
disableStylesheets: 'entry'
}
})
LCP 最適化機能
このモジュールの最適化機能を適用すると、より高い Lighthouse パフォーマンススコアを達成できます
動的インポートのプリフェッチリンクを無効化
!注意 この機能はデフォルトで有効になっています。
Nuxt の大規模なアプリケーションでは、HTML に <link rel="prefetch">
タグが蓄積されるため、Lighthouse と Google PageSpeed Insights でのパフォーマンススコアが低下する可能性があります。
非同期コンポーネントや画像などの他のアセットなど、動的インポートごとに prefetch
リンクがレンダリングされます。これにより、ブラウザは現在のページで必要ない場合でも、これらのチャンクをプリフェッチします。これはアプリケーション全体のパフォーマンスにとっては素晴らしいことですが、プリフェッチリクエストの数が多くなり、Largest Contentful Paint スコアに悪影響を与える可能性があります。
このモジュールは、動的インポートの prefetch
リンクのレンダリングを無効にすることで、LCP スコアを最適化するために Nuxt ビルドプロセスにフックします。
プリロードリンクを無効化
!注意 この機能は手動で有効にする必要があります。
プリロードリンクは、現在のページに必要なクリティカルなリソースをプリロードするために使用されます。一般的に、ウェブサイトのパフォーマンスを最適化する上でその役割がありますが、正しく使用しないと、リクエスト数が多くなる可能性もあります。プリロードリンクを削除すると、特にネットワーク環境が遅い場合、FCP(First Contentful Paint)スコアを改善するのに役立ちます。
プリロードビルドリソースを削除するには、disablePrefetchLinks
オプションを true
に設定します
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
disablePrefetchLinks: true
}
})
レンダリングをブロックする CSS を停止
!注意 この機能は手動で有効にする必要があります。使用するには、Nuxt の
inlineStyles
機能を有効にする必要があります。このオプションを有効にした後、アプリケーションをテストしてください。
CSS スタイルシートはレンダリングをブロックするリソースです。つまり、ブラウザはページをレンダリングする前に CSS をダウンロードして解析する必要があります。スタイルシートをロードする代わりにインラインスタイルを使用すると、ブラウザはページをより速くレンダリングでき、LCP スコアを改善できます。
最新の Nuxt バージョンでは SSR レンダリング中にスタイルがインライン化されますが、entry.<hash>.css
スタイルシートは HTML でレンダリングされたままです。これにより、レンダリングをブロックする CSS が発生し、Largest Contentful Paint スコアに悪影響を与える可能性があります。
なぜそうなるのでしょうか?Nuxt コアチームメンバーの @danielroe によって説明されているように
これは現在のインラインスタイル実装の制限だと思います。
アプリ全体で すべての場所で 使用されているスタイルは、CSS ソースから完全に安全に削除できます。ただし、1 つのコンポーネントまたはページでのみ使用される CSS は、インライン化されるだけでなく、CSS ファイルにも配置する必要があります。
現時点では、vite がクライアント側の CSS のロードをすべて担当しています。つまり、すでにロードされている CSS を追跡したとしても、vite が重複した CSS を含む CSS ファイルをロードするのを止めることはできません。
これはぜひ修正したい点です。
まず、app.vue
ファイルにメインアプリケーションのスタイルをインポートしてみてください。Nuxt がビルドされると、entry
CSS ファイルとして保存されます
// `app.vue`
import '~/assets/css/main.css'
次に、disableStylesheets
オプションを entry
に設定して、entry.<hash>.css
スタイルシートが HTML でレンダリングされないようにします
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
disableStylesheets: 'entry'
}
})
コンポーネント
DelayHydration
!警告 コンポーネントのハイドレーションを遅らせることは、ページが実際よりも早くインタラクティブであると Lighthouse に認識させるためのハックです。実際のパフォーマンスの向上には繋がらない場合があり、慎重に使用する必要があります。
ハイドレーションを遅らせることは、ページが実際よりも早くインタラクティブであると Lighthouse にヒントを与えるためのテクニックです。これにより、Lighthouse と Google PageSpeed Insights の「ブロッキング時間」メトリクスを改善できます。
DelayHydration
コンポーネントは、コンポーネントをハイドレーションする前に一定時間待機するシンプルなコンポーネントです。これは、多くのネットワークリクエストが発生していて、ネットワークリクエストが完了するまでコンポーネントのハイドレーションを遅らせたい場合に役立ちます。
コンポーネントの使用法
Vue コンポーネントで DelayHydration
コンポーネントを使用します
<template>
<div>
<DelayHydration>
<!-- Ensure to lazy load the component -->
<LazyMyExpensiveComponent />
</DelayHydration>
</div>
</template>
設定
vitalizer
モジュールオプションで DelayHydration
コンポーネントを設定できます
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
delayHydration: {
hydrateOnEvents: ['mousemove', 'scroll', 'keydown', 'click', 'touchstart', 'wheel'],
idleCallbackTimeout: 8000,
postIdleTimeout: 4000
}
}
})
hydrateOnEvents
オプションは、ハイドレーションをトリガーするイベントを指定します。デフォルトでは、ユーザーがマウスを移動したり、スクロールしたり、キーを押したり、クリックしたり、画面に触れたり、マウスホイールをスクロールしたりすると、コンポーネントはすぐにハイドレーションされます。idleCallbackTimeout
オプションは、アイドルコールバックを待機する際の最大待ち時間(ミリ秒単位)を指定します。これは、多くのネットワークリクエストが発生している場合に役立ちます。postIdleTimeout
オプションは、アイドルコールバック後にコンポーネントをハイドレーションする前に待機する時間(ミリ秒単位)を指定します。
SkipHydration
SkipHydration
コンポーネントは、初期レンダリング時のクライアントでの子要素のハイドレーションを単純に防ぎます。言い換えれば、コンポーネントがアンマウントされない限り、SSR コンテンツは保持されます。これにより、特定のページに初めてアクセスしたときに特定のコンポーネントをハイドレーションする必要がない場合に、コンポーネントチャンクのロードを節約するのに役立ちます。
新しいページに移動すると、SkipHydration
コンポーネントはクライアントで子要素をマウントし、通常の Vue コンポーネントのように動作します。
コンポーネントの使用法
Vue コンポーネントで SkipHydration
コンポーネントを使用します
<template>
<div>
<SkipHydration>
<!-- Ensure to lazy load the component -->
<LazyMyExpensiveComponent />
</SkipHydration>
</div>
</template>
モジュールオプション
interface ModuleOptions {
/**
* Whether to remove prefetch links from the HTML. If set to `dynamicImports`, only dynamic imports will be removed. To disable all prefetching, such as images, set to `true`.
*
* @remarks
* This will prevent the browser from downloading chunks that may not be needed yet. This can be useful for improving the LCP (Largest Contentful Paint) score.
*
* @default 'dynamicImports'
*/
disablePrefetchLinks?: boolean | 'dynamicImports'
/**
* Whether to remove preload links from the HTML. This can be useful for improving the FCP (First Contentful Paint) score, especially when emulating slow network conditions.
*
* @default false
*/
disablePreloadLinks?: boolean
/**
* Whether to remove the render-blocking stylesheets from the HTML. This only makes sense if styles are inlined during SSR rendering. To only prevent the `entry.<hash>.css` stylesheet from being rendered, set to `entry`. If set to `true`, all stylesheet links will not be rendered.
*
* @remarks
* This requires to have the Nuxt `inlineStyles` feature enabled. Make sure to test your application after enabling this option.
*
* @default false
*/
disableStylesheets?: boolean | 'entry'
/**
* Options for the `DelayHydration` component.
*/
delayHydration?: {
/**
* Specify the events that should trigger hydration.
*
* @default ['mousemove', 'scroll', 'keydown', 'click', 'touchstart', 'wheel']
*/
hydrateOnEvents?: (keyof WindowEventMap)[]
/**
* The maximum amount of time to wait in milliseconds when waiting for an idle callback. This is useful when there are a lot of network requests happening.
*
* @default 8000
*/
idleCallbackTimeout?: number
/**
* Time to wait in milliseconds after the idle callback before hydrating the component.
*
* @default 4000
*/
postIdleTimeout?: number
}
}
💻 開発
- このリポジトリをクローンします
corepack enable
を使用して Corepack を有効にしますpnpm install
を使用して依存関係をインストールしますpnpm run dev:prepare
を実行しますpnpm run dev
を使用して開発サーバーを開始します
クレジット
- このモジュールにインスピレーションを与えてくれた、Nuxt GitHub の問題に関するすべての議論と貢献。
- @harlan-zw の素晴らしい nuxt-delay-hydration モジュール。
ライセンス
MIT ライセンス © 2024-現在 Johann Schopplich