はじめに
Google Tag Managerのように <script>
タグを埋め込むタイプの3rd PartyツールをNuxt3に適用するための手法を検討した。
実行環境
- MacOS 13.4.1 (Apple M1)
- Node 18.13.0
- Nuxt 3.6.2
script setupの実行場所
とのこと。実際にやってみる。
<script setup>
console.log(process.server)
console.log(process.client)
</script>
↓ http://localhost:3000/
表示
true
false
false
true
上記記事の通り、サーバとクライアント両方で実行されており、process.server
, process.client
で判定できることが確認できた。
useHead呼び出し
titleを上書き
<script setup>
const env = process.server ? 'Server' : 'Client'
useHead({
title: `TOP titled | ${env}`
})
</script>
- リロードすると一瞬は
TOP titled | Server
と表示される - すぐに
TOP titled | Client
に切り替わる
→サーバとクライアント両方で実行されている。
useServerHeadを使ってみる
useServerHead
なる関数を発見したので試してみる。
<script setup>
const env = process.server ? 'Server' : 'Client'
useServerHead({
title: `TOP titled | ${env}`
})
</script>
-
TOP titled | Server
と表示されたままである
→サーバのみで実行されるよう関数内で分岐している模様。
<script>
を挿入
<script>
タグを埋め込む場合は useHead
の引数の script
が利用できる。
tagPriority
の基準は以下の通り(数字が小さいほど優先度高)
- -2:
<meta charset ...>
- -1:
<base>
- 0:
<meta http-equiv="content-security-policy" ...>
- 10: 上記以外のタグのデフォルト値
<script setup>
const config = useRuntimeConfig()
const env = process.server ? 'Server' : 'Client'
useHead({
title: "useHeadデモ",
script: [
{
type: "text/javascript",
innerHTML: `console.log("${env} script loaded(5)")`,
tagPriority: 5
},
{
type: "text/javascript",
innerHTML: `console.log("${env} script loaded(4)")`,
tagPriority: 4
}
]
})
</script>
↓ http://localhost:3000/script-insertion
表示
script-insertion:5 Server script loaded(4)
script-insertion:6 Server script loaded(5)
chunk-VWWL2I6E.js:2710 <Suspense> is an experimental feature and its API will likely change.
VM1678:1 Client script loaded(4)
VM1679:1 Client script loaded(5)
<head>
<meta charset="utf-8">
<title>useHeadデモ</title>
<script type="text/javascript">console.log("Server script loaded(4)")</script>
<script type="text/javascript">console.log("Server script loaded(5)")</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link ...>
<script>...</script>
<style>...</style>
<script type="text/javascript">console.log("Client script loaded(4)")</script>
<script type="text/javascript">console.log("Client script loaded(5)")</script>
<!-- 以下略 -->
</head>
- Serverで追加した
<script>
は設定した優先度通り<title>
と<meta>
の間に挿入 - Clientで追加した
<script>
は初期表示時の<style>
より後に表示- Clientで追加したスクリプト同士の優先度は有効
NuxtConfigで挿入するscriptを定義
全ページ共通で挿入するscriptはNuxtConfigで定義することもできる。
export default defineNuxtConfig({
app: {
head: {
script: [
{
type: "text/javascript",
innerHTML: `console.log("Config script loaded")
window.onload = () => {console.log("page is fully loaded")}
window.addEventListener('DOMContentLoaded', () => {console.log('DOM fully loaded and parsed')})`,
tagPriority: 9
}
]
}
},
runtimeConfig: {
public: {
priorityOfBeforeCommon: PRIORITY_OF_BEFORE_COMMON
}
}
})
↓ http://localhost:3000/script-insertion
表示
script-insertion:5 Server script loaded(4)
script-insertion:6 Server script loaded(5)
script-insertion:7 Config script loaded
script-insertion:9 DOM fully loaded and parsed
script-insertion:8 page is fully loaded
chunk-VWWL2I6E.js:2710 <Suspense> is an experimental feature and its API will likely change.
VM2198:1 Client script loaded(4)
VM2199:1 Client script loaded(5)
<head>
<meta charset="utf-8">
<title>useHeadデモ</title>
<script type="text/javascript">console.log("Server script loaded(4)")</script>
<script type="text/javascript">console.log("Server script loaded(5)")</script>
<script type="text/javascript">
console.log("Config script loaded")
window.onload = () => {console.log("page is fully loaded")}
window.addEventListener('DOMContentLoaded', () => {console.log('DOM fully loaded and parsed')})
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link ...>
<script>...</script>
<style>...</style>
<script type="text/javascript">console.log("Client script loaded(4)")</script>
<script type="text/javascript">console.log("Client script loaded(5)")</script>
<!-- 以下略 -->
</head>
- Configのscriptの優先度はServerのscriptと同じレベルで判断される
- Config, ServerのscriptはDOM読み込み時にすでに存在する
- ↑
DOMContentLoaded
より前に読み込まれることから
- ↑
まとめ
サーバサイドでuseHeadするのがよさそう
補足
GTMであれば @gtm-support/vue-gtm
でもよさそう。