svelte-meta-tags-companion について
svelte-meta-tags を使う Svelte 開発者向けのトラブルシューティング資料です。メタデータのマージ、ソーシャルタグのフォールバック、出力条件のよくある誤りを説明します。
主な機能
- 01$app/state と $props の適切な使用方法
- 02deepMerge の動作説明
- 03OpenGraph と Twitter の出力条件
- 04robots と titleTemplate の描画条件
- 05型付きメタデータ定義ヘルパーの推奨
活用シーン
- 01メタデータが出力されない原因の調査
- 02入れ子の OpenGraph マージ問題の修正
- 03ソーシャルタグのフォールバック設定確認
- 04基本レイアウトのタイトル設定確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oekazuma/ svelte-meta-tags --skill svelte-meta-tags-companionインストール後、Claude Code で/svelte-meta-tags-companionを入力して読み込まれたか確認します。
詳細
svelte-meta-tags:補足
使用する場面
よくある間違いを見つけるためのリファレンスです。セットアップガイドではありません(セットアップについては svelte-meta-tags-setup スキルを参照してください)。
よくある間違い
1. $app/state ではなく $app/stores から page をインポートする
<script>
import { page } from '$app/stores';
import { deepMerge } from 'svelte-meta-tags';
export let data;
$: metaTags = deepMerge(data.baseMetaTags, $page.data.pageMetaTags);
</script>
<script>
import { page } from '$app/state';
import { deepMerge } from 'svelte-meta-tags';
let { data } = $props();
let metaTags = $derived(deepMerge(data.baseMetaTags, page.data.pageMetaTags));
</script>
2. deepMerge を使わずに手動でマージする
// ❌ Wrong: a shallow spread does not deep-merge nested objects like `openGraph`
const metaTags = { ...baseMetaTags, ...pageMetaTags };
// ❌ Wrong: pulling in a third-party deep-merge library adds an unnecessary dependency
import extend from 'just-extend';
const metaTags = extend(true, {}, baseMetaTags, pageMetaTags);
// ✅ Correct: use the library's own deepMerge
import { deepMerge } from 'svelte-meta-tags';
const metaTags = deepMerge(baseMetaTags, pageMetaTags);
deepMerge はネストされたオブジェクトを正しくマージします(openGraph 自体と、その個々のフィールドである title や description なども対象です。フィールドは個別にマージされ、上書きによってオブジェクト全体が置き換えられることはありません)。配列は連結せずに置き換えます(例:openGraph.images)。また、すでに target にある Date や関数は、source で上書きせずに保持します。これは、通常の「source が優先される」ルールとは逆です。シャロースプレッドではネストされた上書きが黙って失われます。また、サードパーティ製のマージライブラリは、このライブラリ固有のルールを認識しません。
3. <MetaTags> に誤った prop をスプレッドする
<MetaTags {metaTags} />
<MetaTags {...metaTags} />
4. Twitter/OpenGraph のフォールバックチェーンを再実装する
// ❌ Wrong: MetaTags already does this internally
const twitterTitle = twitter?.title ?? openGraph?.title ?? title;
<MetaTags> はすでに twitter.title → openGraph.title → title の順でフォールバックします(titleTemplate を適用したタイトルを使い、description も同じ形式です)。props を渡す前に自分で計算しないでください。
5. deepMerge に 3 つ以上のオブジェクトを渡す
// ❌ Wrong: deepMerge takes exactly (target, source) — the third argument is ignored, silently
const metaTags = deepMerge(siteMetaTags, sectionMetaTags, pageMetaTags);
// ✅ Correct: chain it
const metaTags = deepMerge(deepMerge(siteMetaTags, sectionMetaTags), pageMetaTags);
TypeScript は余分な引数をエラーにするため、lang="ts" のない .svelte ファイル内でのみ、この問題が見過ごされます。レイアウトの配線処理は、まさにそのようなファイルに記述されることが多いです。
また、両方の引数がある場合、deepMerge は Object.entries で source を反復処理するため、source のシンボルキーは破棄されます。(引数が nullish の場合はマージ全体が短絡されます。deepMerge はもう一方の引数をそのまま返すか、両方が nullish なら {} を返します。)Meta タグの props は文字列キーなので、これは同じヘルパーで独自のデータをマージする場合にのみ関係します。
タグがレンダリングされない場合
これらは誤ったコードではありません。正しそうに見える props でも、出力が生成されないことがあります。ライブラリのバグを疑う前に、以下を確認してください。
og:* と twitter:* には、それぞれの prop オブジェクトが必要です
<MetaTags title="My Page" description="A short description." />
<MetaTags title="My Page" description="A short description." openGraph={{}} />
<MetaTags> は、OpenGraph ブロック全体を {#if openGraph} で、Twitter ブロック全体を {#if twitter} で保護します。ドキュメントに記載されているフォールバック(og:title → title、twitter.title → openGraph.title → title)は、それぞれのブロック内でのみ適用されます。そのため、title と description だけを設定したページでは、ソーシャルタグは一切出力されません。
titleTemplate だけでは <title> はレンダリングされません
<MetaTags titleTemplate="%s | My Site" description="About us." />
title がない場合、<MetaTags> はテンプレートだけをレンダリングするのではなく、<title> 要素自体を省略します。そのため、titleTemplate だけを設定したベースレイアウトでは、各ページで個別のタイトルが設定されていない場合、タイトルが出力されません。マージ後に必ずタイトルが存在するよう、ベースレイアウトにも title を指定してください。
additionalRobotsProps の偽値は破棄されます
<MetaTags additionalRobotsProps={{ maxSnippet: 0 }} />
<MetaTags additionalRobotsProps={{ maxSnippet: -1 }} />
各ディレクティブは、その値が truthy の場合にのみ含まれます。maxSnippet と maxVideoPreview の「制限なし」を示す値である -1 は機能しますが、0 は機能しません。
robots={false} はタグを抑制し、additionalRobotsProps も同様です
robots={false} を設定すると、<meta name="robots"> は完全に削除されます。これと additionalRobotsProps を組み合わせると console.warn が出力されますが、この警告は $effect から出るため、SSR 中には実行されません。そのため、サーバーでレンダリングされたページでは何も表示されません。どちらか一方の prop を削除してください。
openGraph.image は単一画像用のショートカットです
<MetaTags openGraph={{ image: { url: 'https://example.com/og.jpg' } }} />
すでに images 配列を作成している場合は、そのまま使ってください。ただし、画像が 1 枚だけのページでは、配列は不要です。
提案(バグではありません)
+layout.ts/+page.ts の load 関数が defineBaseMetaTags/definePageMetaTags を使わずにプレーンオブジェクトを返す場合は、型安全性と不変性(Object.freeze)のために、それらの関数への切り替えを提案してください。ただし、これは任意であり、正しさに関わる問題ではありません。
// Works, but not type-checked against MetaTagsProps and not frozen
export const load = () => ({ baseMetaTags: { title: 'My Site' } });
// Recommended: typed + frozen
import { defineBaseMetaTags } from 'svelte-meta-tags';
export const load = () => ({ ...defineBaseMetaTags({ title: 'My Site' }) });