关于 svelte-meta-tags-companion
为使用 svelte-meta-tags 的 Svelte 开发者提供常见错误参考,重点说明元标签合并、社交标签回退及渲染条件,帮助排查配置问题。
主要功能
- 01说明正确使用 $app/state 和 $props
- 02介绍 deepMerge 的合并规则
- 03解释 OpenGraph 与 Twitter 标签的输出条件
- 04指出 robots 和 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/stores 导入 page,而不是从 $app/state 导入
<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);并且会保留已存在于目标对象中的 Date 或函数,而不会让源对象覆盖它——这与其通常的“源对象优先”规则相反。浅层展开会悄悄丢弃嵌套覆盖项;第三方合并库也不了解这些库特有规则。
3. 将错误的 prop 展开到 <MetaTags> 中
<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 传入两个以上的对象
// ❌ 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 遍历源对象,因此源对象上的符号键会被丢弃。(如果参数为 nullish 值,合并会直接短路:deepMerge 会原样返回另一个参数;如果两者都是 nullish 值,则返回 {}。)Meta 标签 props 的键都是字符串,因此只有在你通过同一辅助函数合并自己的数据时才需要留意这一点。
标签为什么没有渲染
这些代码并没有错误——它们只是看起来正确的 props,却不会产生任何输出。在认定是库的 bug 之前,请先检查这些情况。
og:* 和 twitter:* 要求对应的 prop 对象必须存在
<MetaTags title="My Page" description="A short description." />
<MetaTags title="My Page" description="A short description." openGraph={{}} />
<MetaTags> 会分别通过 {#if openGraph} 和 {#if twitter} 判断是否渲染整个 OpenGraph 区块和 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 }} />
只有值为真值的指令才会被纳入。-1(maxSnippet 和 maxVideoPreview 的“无限制”值)有效;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 数组,就继续使用它;但单张图片的页面不需要数组。
建议(不是 bug)
如果 +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' }) });