Nuxtチームは、GoogleのChrome Auroraチームと協力し、Nuxt Scripts.
Nuxt Scriptsは、サードパーティスクリプトを扱うためのより良い方法を提供し、パフォーマンス、プライバシー、セキュリティ、開発者エクスペリエンスを向上させます。

Nuxt Scriptsの誕生
1年以上前、Danielは最初のNuxt Scripts RFCを公開しました。RFCは、「パフォーマンスとコンプライアンスに優れたウェブサイトのベストプラクティスに従って、サードパーティスクリプトを管理および最適化できるモジュール」を提案しました。
サードパーティスクリプトに関連するパフォーマンス問題の解決において個人的な経験があったため、これらのパフォーマンス最適化がいかに難しいかを知っていました。それにもかかわらず、私はこの問題に取り組むことに熱心で、プロジェクトを引き継ぎました。
RFCをアイデアの種として、私はそれがどのようなものになるかをプロトタイプ化し始めました。Unhead.
具体的に何を構築したいのかを考えているうちに、本当の問題は「最適化された」サードパーティスクリプトをロードする方法だけでなく、サードパーティスクリプトを扱う全体的な体験をより良くする方法であることに気づきました。
なぜサードパーティスクリプトモジュールを構築するのか?
94%のサイトが少なくとも1つのサードパーティプロバイダーを使用しており、平均的なサイトは5つのサードパーティプロバイダー.
を持っています。サードパーティスクリプトは完璧ではないことを知っています。それらはウェブを遅くし、プライバシーとセキュリティの問題を引き起こし、扱うのが面倒です。
しかし、それらは基本的に有用であり、すぐに消えることはありません。
サードパーティスクリプトの問題を探求することで、どこで改善できるかが見えてきます。
😒 開発者エクスペリエンス:フルスタックの頭痛
ウィンドウに track 関数を追加する架空の tracker.js スクリプトを使用して、Nuxtアプリにサードパーティスクリプトを追加する方法を見ていきましょう。
まず、useHead を使用してスクリプトをロードします。
useHead({ script: [{ src: '/tracker.js', defer: true }] })
しかし、次に、アプリでスクリプト機能を動作させてみましょう。
Nuxtでサードパーティスクリプトを扱う際によくある手順は以下のとおりです。
- SSRの安全性のため、すべてをラップする必要があります。
- スクリプトがロードされたかどうかの不安定なチェック。
- 型のためにwindowオブジェクトを拡張する。
<script setup>
// ❌ Oops, window is not defined!
// 💡 The window can't be directly accessed if we use SSR in Nuxt.
// 👉 We need to make this SSR safe
window.track('page_view', useRoute().path)
</script>
<script setup>
if (import.meta.client) {
// ❌ Oops, the script hasn't finished loading yet!
// 💡 A `defer` script may not be available while our Nuxt app hydrates.
// 👉 We need to wait for the script to be loaded
window.track('page_view', useRoute().path)
}
</script>
<script lang="ts" setup>
if (import.meta.client) {
useTimeoutFn(() => {
// ✅ It's working!
// ❌ Oops, types are broken.
// 💡 The `window` has strict types and nothing is defined yet.
// 👉 We need to manually augment the window
window.track('page_view', useRoute().path)
}, 1000 /* should be loaded in 1 second!? */)
}
</script>
<script lang="ts" setup>
declare global {
interface Window {
track: (e: string, p: string) => void
}
}
if (import.meta.client) {
useTimeoutFn(() => {
// ✅ It's working and types are valid!
// ❌ Oops, ad-blockers, GDPR and duplicate scripts
// 💡 There's a lot of hidden complexity in third-party scripts
// 👉 We need a better API
window.track('page_view', useRoute().path)
}, 1000)
}
</script>
🐌 パフォーマンス:「Lighthouseで100点を取れないのはなぜ?」
訪問者がNuxtサイトを操作し始めるには、アプリバンドルをダウンロードし、Vueがアプリインスタンスをハイドレートする必要があります。
async または defer を使用している場合でも、サードパーティスクリプトのロードがこのハイドレーションプロセスを妨げることがあります。これにより、ネットワークが遅くなり、メインスレッドがブロックされ、ユーザーエクスペリエンスが低下し、Core Web Vitals.
が悪化します。Chromeユーザーエクスペリエンスレポートによると、多数のサードパーティリソースを使用するNuxtサイトは、通常、Interaction to Next Paint (INP)GlobalComponentsLargest Contentful Paint (LCP)スコアが低下することが示されています。
サードパーティスクリプトがどのようにパフォーマンスを低下させるかを確認するには、Web Almanac 2022を参照してください。レポートによると、トップ10のサードパーティスクリプトの平均中央ブロッキング時間は1.4秒です。
🛡️ プライバシー&セキュリティ:悪を行わない?
トップ10,000サイトのうち、58%のサイトでサードパーティスクリプトが外部クッキーに保存されたトラッキングIDを交換しており、これはサードパーティクッキーが無効になっていてもサイト間でユーザーを追跡できることを意味します。
多くの場合、使用するプロバイダーに縛られていますが、可能であれば、エンドユーザーのデータ漏洩量を最小限に抑えるように努めるべきです。
プライバシーへの影響を考慮する場合でも、プライバシーポリシーでこれらを正確に伝え、GDPRなどの規制に準拠するために必要な同意管理を構築することは困難です。
サードパーティスクリプトを使用する際のセキュリティも懸念事項です。サードパーティスクリプトは悪意のある攻撃者の一般的な攻撃ベクトルであり、ほとんどのスクリプトは integrity ハッシュを提供しないため、いつでも侵害され、悪意のあるコードをアプリに注入される可能性があります。
Nuxt Scriptsはこれらの問題にどう対処しますか?
コンポーザブル:useScript
このコンポーザブルは、<script> タグと window.{thirdPartyKey} に追加される機能の間に位置します。
<script> タグについては、このコンポーザブルは
- スクリプトのロード状態とエラー状態を完全に可視化します。
- デフォルトでNuxtがアプリをハイドレートするときにスクリプトをロードし、わずかにパフォーマンスを向上させます。
- プライバシーとセキュリティを向上させるために、
crossoriginとreferrerpolicyを制限します。 - 必要になるまでスクリプトのロードを遅延させる方法を提供します。
スクリプトAPIについては、
- スクリプトの機能に関する完全な型安全を提供します。
- スクリプトが安全でないコンテキスト(SSR、スクリプトがロードされる前、スクリプトがブロックされている)で機能する場合でも、アプリが実行できるようにプロキシレイヤーを追加します。
const { proxy, onLoaded } = useScript('/hello.js', {
trigger: 'onNuxtReady',
use() {
return window.helloWorld
}
})
onLoaded(({ greeting }) => {
// ✅ script is loaded! Hooks into Vue lifecycle
})
// ✅ OR use the proxy API - SSR friendly, called when script is loaded
proxy.greeting() // Hello, World!
declare global {
interface Window {
helloWorld: {
greeting: () => 'Hello World!'
}
}
}
window.helloWorld = {
greeting() {
console.log('Hello, World!')
}
}
スクリプトレジストリ
が悪化します。スクリプトレジストリは、一般的なサードパーティスクリプト用のファーストパーティ統合のコレクションです。リリース時点で、21のスクリプトをサポートしており、今後さらに増える予定です。

これらのレジストリスクリプトは、完全な型安全、スクリプトオプションのランタイム検証(開発時のみ)、および環境変数サポートを備えた useScript の微調整されたラッパーです。
例えば、Fathom Analyticsスクリプトを見てみましょう。
const { proxy } = useScriptFathomAnalytics({
// ✅ options are validated at runtime
site: undefined
})
// ✅ typed
proxy.trackPageview()
ファサードコンポーネント
レジストリには、ファサードコンポーネントがいくつか含まれています。Googleマップ, YouTubeGlobalComponentsIntercom.
ファサードコンポーネントは、サードパーティスクリプトがロードされたときにハイドレートされる「フェイク」コンポーネントです。ファサードコンポーネントにはトレードオフがありますが、パフォーマンスを劇的に向上させることができます。詳細については、ファサードコンポーネントとは?ガイドを参照してください。
Nuxt Scriptsは、ファサードコンポーネントをアクセス可能でありながらヘッドレスとして提供します。つまり、デフォルトではスタイルが適用されませんが、必要なa16yデータが追加されます。

<script setup lang="ts">
const isLoaded = ref(false)
const isPlaying = ref(false)
const video = ref()
function play() {
video.value?.player.playVideo()
}
function stateChange(state) {
isPlaying.value = state.data === 1
}
</script>
<template>
<ScriptYouTubePlayer ref="video" video-id="d_IFKP1Ofq0" @ready="isLoaded = true" @state-change="stateChange">
<template #awaitingLoad>
<div class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 h-[48px] w-[68px]">
<svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#f00" /><path d="M 45,24 27,14 27,34" fill="#fff" /></svg>
</div>
</template>
</ScriptYouTubePlayer>
</template>
同意管理と要素イベントトリガー
useScript コンポーザブルは、カスタムの trigger を提供するか、load() 関数を手動で呼び出すことで、スクリプトのロード方法とタイミングを完全に制御できます。
これに基づいて、Nuxt Scriptsは、さらに簡単に高度なトリガーを提供します。
- 同意管理- クッキーバナーなどでユーザーが同意を与えた後にのみスクリプトをロードします。
- 要素イベントトリガー- スクロール、クリック、フォーム送信などのユーザーインタラクションに基づいてスクリプトをロードします。
const cookieConsentTrigger = useScriptTriggerConsent()
const { proxy } = useScript<{ greeting: () => void }>('/hello.js', {
// script will only be loaded once the consent has been accepted
trigger: cookieConsentTrigger
})
// ...
function acceptCookies() {
cookieConsentTrigger.accept()
}
// greeting() is queued until the user accepts cookies
proxy.greeting()
スクリプトのバンドル
多くの場合、私たちは制御できないドメインからサードパーティスクリプトをロードしています。これはいくつかの問題を引き起こす可能性があります。
- プライバシー:サードパーティスクリプトはサイト間でユーザーを追跡できます。
- セキュリティ:サードパーティスクリプトが侵害され、悪意のあるコードを注入される可能性があります。
- パフォーマンス:余分なDNSルックアップはページのロードを遅くします。
- 開発者エクスペリエンス:同意したスクリプトが広告ブロッカーによってブロックされる場合があります。
これを軽減するために、Nuxt Scriptsは、追加の作業なしでサードパーティスクリプトをパブリックディレクトリにバンドルする方法を提供します。
useScript('https://cdn.jsdelivr.net/npm/js-confetti@latest/dist/js-confetti.browser.js', {
bundle: true,
})
スクリプトは、独自のドメインの /_scripts/{hash} から提供されるようになります。
つづく
見てきたように、開発者とエンドユーザーのためにサードパーティスクリプトを改善する多くの機会があります。
Nuxt Scriptsの最初のリリースは、これらの問題のいくつかを解決しましたが、まだ多くの作業が残っています。
ロードマップの次の項目は以下のとおりです。
皆様の貢献とサポートを歓迎します。
開始する
Nuxt Scriptsを使い始めるために、チュートリアルを作成しました。ぜひご活用ください。
クレジット
- Harlan Wilton - Nuxt(著者)
- Julien Huang - Nuxt(コントリビューター)
- Daniel Roe - Nuxt(コントリビューター)
- Chrome Aurora - Google(コントリビューター)
そして、初期のコントリビューターの皆様に心から感謝いたします。
