搜索 K
主题
@vaultkit/vitepress-plugin-robots 是一个零配置的 robots.txt 生成器,在 VitePress buildEnd 钩子里调用:hostname 自动取自内置 sitemap 配置,缺省产出「全放行 + Sitemap: 指令」,需要时再用 rules 精细控制各家爬虫——包括屏蔽 AI 爬虫。
包体极小(一个函数、四个选项字段、零依赖),但补上的是 SEO 链路里容易被忽略的一环。这是纯构建期包,本文的产物示例全部用代码围栏呈现。
搜索引擎发现 sitemap 的标准途径,是 robots.txt 里的 Sitemap: 指令(sitemaps.org 协议)。VitePress 内置了 sitemap 生成,却不产 robots.txt——sitemap 生成了但没人知道在哪,等于白做。手动往 public/ 放一份当然可行,但 hostname 一变(换域名、多环境部署)就要记得同步改,这类「两处维护一份事实」的配置迟早会烂。
本包的解法:hostname 直接读 config.userConfig.sitemap.hostname,与内置 sitemap 同源、零重复配置;产物在构建期写进 outDir,源码里不需要任何静态文件。
pnpm add -D @vaultkit/vitepress-plugin-robots使用 @vaultkit/vitepress-theme-vault 主题则开箱即带:features.robots 缺省为 true,主题在 buildEnd 里自动调用(走缺省全放行规则)。关闭方式:
export default defineConfigWithTheme({
extends: createVaultTheme({
site: { /* ... */ },
features: { robots: false },
}),
})零配置形态——第二参数整个可省:
import { generateRobots } from '@vaultkit/vitepress-plugin-robots'
import { defineConfig } from 'vitepress'
export default defineConfig({
sitemap: { hostname: 'https://example.com' }, // hostname 从这里自动读取
async buildEnd(config) {
await generateRobots(config)
},
})产出:
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml| 导出 | 形态 | 说明 |
|---|---|---|
generateRobots | 异步函数(具名导出) | 生成入口,(config, options?) => Promise<void>,无默认导出 |
RobotsOptions | 类型 | 选项接口(全部字段可省) |
RobotsRule | 类型 | 单组爬虫规则 |
RobotsSiteConfig | 类型 | SiteConfig 的结构化子集(只消费 outDir 与 userConfig.sitemap.hostname) |
string,默认取 VitePress sitemap.hostnameSitemap: 指令的完整 URL,尾部 /(可多个)自动剥离。与 feed / llms 两包不同,这里缺 hostname 不抛错——robots.txt 的规则部分不依赖域名,缺 hostname 时仅省略 Sitemap: 指令、其余照常输出。RobotsRule[],默认 [{ userAgent: '*', allow: '/' }]rules,缺省的全放行规则不再自动附加,需要的话自己写一组 { userAgent: '*', allow: '/' }。boolean | string,默认 hostname + '/sitemap.xml'false 彻底关闭 Sitemap: 指令;字符串则覆盖为任意完整 URL(比如 sitemap 索引文件或跨域托管的地址):await generateRobots(config, { sitemap: 'https://cdn.example.com/sitemap-index.xml' })string[],默认 undefinedHost: 等非标准指令,或新出的指令(robots.txt 生态里指令一直在长):await generateRobots(config, {
extra: ['# generated at build time', 'Host: example.com'],
})| 字段 | 类型 | 必填 | 渲染为 |
|---|---|---|---|
userAgent | string | string[] | 是 | 每个 UA 一行 User-agent: <名>;数组即多 UA 共享同组规则 |
allow | string | string[] | 否 | 每个路径一行 Allow: <路径> |
disallow | string | string[] | 否 | 每个路径一行 Disallow: <路径> |
crawlDelay | number | 否 | 一行 Crawl-delay: <秒>(Google 忽略此指令,Bing/Yandex 认) |
userAgent 用 '*' 匹配所有爬虫,或写具体 UA 名如 'Googlebot'、'GPTBot'。同一块内的渲染顺序固定为 User-agent → Allow → Disallow → Crawl-delay。
不传 rules 时的完整输出(规则块与 Sitemap: 之间空行分隔,文件以换行结尾):
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml配置:
await generateRobots(config, {
rules: [
{ userAgent: '*', allow: '/' },
{ userAgent: ['GPTBot', 'CCBot', 'Google-Extended'], disallow: '/' },
],
})产出:
User-agent: *
Allow: /
User-agent: GPTBot
User-agent: CCBot
User-agent: Google-Extended
Disallow: /
Sitemap: https://example.com/sitemap.xml多 UA 数组共享一个 Disallow: /,正是 robots.txt 协议的分组语义——比逐 UA 复制三块干净得多。GPTBot(OpenAI 训练)、CCBot(Common Crawl)、Google-Extended(Gemini 训练)是目前最常见的屏蔽对象;注意这与 llms.txt 是一体两面:欢迎 AI 就给 llms.txt,谢绝 AI 就在这里 Disallow。
VitePress 会在构建时把 public/ 内容拷进 outDir,且这发生在 buildEnd 之前。插件写盘前先检查 outDir/robots.txt 是否已存在——存在即打印 [robots] 检测到已有 robots.txt(public/),跳过生成 并直接返回。这条「手写优先」原则让渐进迁移零风险:先放着手写文件,哪天删掉它插件自动接管。
feed / llms 缺 hostname 直接抛错,robots 却选择降级——因为 robots.txt 的核心价值(UA 规则)不依赖绝对 URL,只有 Sitemap: 指令需要。抛错反而会让「本地预览构建没配域名」这类场景无谓失败。三个包的差异是按各自产物语义分别裁定的,不是随意为之。
产物就是字符串拼接:每组规则一个块、块间空行、结尾换行。没有模板引擎、没有第三方 robots 库——这个问题域用 40 行代码解决是恰当的工程尺度。
Q:产物里没有 Sitemap: 行? 没配 sitemap.hostname 也没传 options.hostname(或显式 sitemap: false)。配上 hostname 即恢复。
Q:明明改了配置,robots.txt 却没变化? 检查 public/robots.txt 是否存在——它优先级最高,插件检测到就跳过生成(构建日志有提示)。删掉手写文件即可交回插件管理。
Q:Disallow: / 能阻止内容被 AI 训练吗? robots.txt 是君子协定,合规爬虫(GPTBot、CCBot 等)声明会遵守,但没有技术强制力。对抗恶意抓取需要 WAF/速率限制等服务端手段。
Q:想对某个目录单独限速? 一组规则即可:{ userAgent: 'Bingbot', crawlDelay: 10, disallow: '/attachments/' }——同一块内可同时给 disallow 与 crawlDelay。