2026 完整指南:从零搭建 Vue 3 + VuePress 2 个人技术博客(HTTPS/PWA/SEO/广告/评论全栈)

写在前面

这是一篇我用 90 天时间,把一个 2018 年起步的旧博客升级成 2026 版 VuePress 2 站点的完整复盘

全程踩过的坑:CSP 与广告联盟冲突、PWA 预缓存吞掉新 CSP、PWA 预缓存 404、SAN 证书签发、theme-reco 默认页脚 ICP 不是原生 <a>……一篇文章给你全部答案。

博客线上地址https://www.lxc666.cnopen in new window(你正在看的这个站)

1. 为什么选 VuePress 2

2026 年还有人写个人技术博客吗?有,而且活得很好。但选什么框架,主流已经从 5 年前的「Hexo / Hugo」分化出更多选择。我做选型时对比了 4 个主流方案:

框架语言主题生态适合人群短板
VuePress 2Node.js + Vue 3中文圈丰富(theme-reco、theme-hope)前端 / Vue 开发者启动稍慢
HexoNode.js老牌主题多但偏老老博客迁移Vue 3 集成不友好
HugoGo国际化主题多追求极致构建速度模板语法门槛
AstroTypeScript现代化、支持 React/Vue 组件岛想玩前沿中文资料较少
Next.jsReactApp Router + ISR同时做应用 + 博客杀鸡用牛刀

我选 VuePress 2 的 4 个理由

  1. 写文章 = 写 Markdown,没有任何额外学习成本;前端基础够用就能改主题。
  2. Vue 3 原生:可以在 Markdown 里直接写 <MyVueComponent />,组件能力比 Hexo 强很多。
  3. theme-reco 2.x 的「博客模式」开箱即用:首页 BannerBrand、文章列表、归档时间线、分类标签 4 件套都齐了。
  4. 构建产物纯静态,扔给 Nginx 就能跑,部署成本几乎为零。

2026

VuePress 2 目前仍在 RC(release candidate)阶段,截至本文写作时最新为 2.0.0-rc.18,theme-reco 为 2.0.0-rc.25。RC 不代表不能用,本博客已经在 rc.18 稳定运行 3 个月 0 崩溃,只是注意锁版本,别 ^2.0.0 这种写法。


2. 环境准备

2.1 Node.js 18+

VuePress 2 的 engines 字段要求 Node 18.16+:

{
  "engines": {
    "node": ">=18.16.0"
  }
}

为什么不是 20 或 22 LTS?因为 2.0.0-rc.x 阶段对 Node 22 的 ESM 加载偶尔有怪问题,Node 18.16 ~ 20.x 是最稳的甜区

推荐用 nvm-windowsfnm 管理多版本:

# Windows
choco install nvm

nvm install 18.20.4
nvm use 18.20.4
node -v   # v18.20.4

2.2 包管理器

npm 够用,但如果你电脑磁盘紧张,pnpm 通过硬链接共享依赖能显著节省 node_modules 体积(多项目并行开发时尤为明显):

npm install -g pnpm

本博客统一用 npm,因为后面要配合 patch-package 改主题源码,npm 兼容性最好。

2.3 Git + 仓库

把你的博客托管到 Gitee 或 GitHub。Gitee 国内拉取快(本博客就放 Gitee:luoxuancong/blog),GitHub 配合 GitHub Pages 也方便。

mkdir my-blog
cd my-blog
git init
git remote add origin https://gitee.com/<your-name>/blog.git

3. 项目脚手架

3.1 npm init 三连

npm init -y
npm install -D vuepress@2.0.0-rc.18 vuepress-theme-reco@2.0.0-rc.25
npm install -D @vuepress/bundler-vite@2.0.0-rc.18
npm install vue@^3.5.13

必须锁版本

VuePress 2 的 plugin 和 theme-reco 的版本号必须互相对应(一般保持小版本一致:rc.18rc.61 / rc.25)。不锁版本以后跑 npm install 会被升到新 rc,主题报错你能查到天亮。

3.2 完整目录结构

最终我推荐的项目结构如下:

my-blog/
├── docs/
│   ├── .vuepress/
│   │   ├── config.ts            # VuePress 主配置
│   │   └── public/              # 静态资源
│   │       ├── favicon.ico
│   │       ├── logo.png
│   │       ├── ads.txt          # AdSense(后面会讲)
│   │       └── js/
│   │           └── baidu.js     # 百度统计
│   ├── blogs/                   # 所有博客文章
│   │   ├── Vue/
│   │   ├── JavaScript/
│   │   └── AI/
│   ├── about.md                 # 关于我
│   ├── privacy.md               # 隐私政策(AdSense 要求)
│   ├── disclaimer.md            # 免责声明
│   └── README.md                # 首页
├── patches/                     # patch-package 补丁(后面会讲)
├── package.json
└── tsconfig.json

3.3 package.json scripts

{
  "scripts": {
    "dev": "vuepress dev docs",
    "build": "vuepress build docs",
    "preview": "vuepress build docs && http-server public -p 8000 -c-1",
    "clean": "rimraf docs/.vuepress/.temp docs/.vuepress/.cache public",
    "postinstall": "patch-package"
  }
}

注意 dest: 'public' 默认会把构建产物放到 docs/.vuepress/dist,我们改到根目录的 public/,部署时直接 rsync public/ server:/var/www/blog/ 一行搞定。


4. 选主题

4.1 三大主题横评

主题风格博客模式中文社区我的评分
theme-default简洁文档型❌ 需要自己加⭐⭐60 分(纯文档站才选)
theme-reco博客 + 文档混合✅ 一键开启⭐⭐⭐⭐⭐90 分
theme-hope功能最全✅ 内置博客⭐⭐⭐⭐85 分(功能过多反而复杂)

结论:个人博客首选 theme-reco,功能刚刚好,BannerBrand / Blog / MdContent / Footer 四大模块覆盖 90% 需求。

4.2 安装与启用

npm install -D vuepress-theme-reco@2.0.0-rc.25

docs/.vuepress/config.ts

import { defineUserConfig } from 'vuepress'
import { viteBundler } from '@vuepress/bundler-vite'
import recoTheme from 'vuepress-theme-reco'

export default defineUserConfig({
  lang: 'zh-CN',
  title: 'luoxuancong',
  description: '前端开发博客 | AI工具教程 — 平安喜乐',
  dest: 'public',
  bundler: viteBundler(),
  theme: recoTheme({
    // 头像 / 站点信息 / 导航 / 公告 / 友链 等都在这里配
    autoSetBlogCategories: true,
    autoSetSeries: true,
  })
})

autoSetBlogCategories: true 是关键,它会扫描 docs/blogs/<分类>/xxx.md,自动把目录名变成分类。你不需要在每篇文章 frontmatter 里手写 categories


5. 5 个必装插件深度配置

这一节是本文最干货的部分。

5.1 @vuepress/plugin-sitemap — SEO 基石

import { sitemapPlugin } from '@vuepress/plugin-sitemap'

sitemapPlugin({
  hostname: 'https://www.lxc666.cn',
  excludePaths: ['/404.html'],
  changefreq: 'weekly',
  // 优先用 frontmatter.date,否则回退到 git
  modifyTimeGetter: (page) => {
    const fmDate = (page.frontmatter as Record<string, unknown>).date
    if (fmDate instanceof Date) return fmDate.toISOString()
    if (typeof fmDate === 'string') {
      const d = new Date(fmDate)
      if (!isNaN(d.getTime())) return d.toISOString()
    }
    const gitTime = (page.data as { git?: { updatedTime?: number } }).git?.updatedTime
    return gitTime ? new Date(gitTime).toISOString() : ''
  }
})

构建后 public/sitemap.xml 会自动包含所有页面 + lastmod 时间戳。提交给百度站长 / Bing 站长,1-3 天内开始收录。

5.2 @vuepress/plugin-slimsearch — 中文友好的站内搜索

社区常用 @vuepress/plugin-search不支持中文分词,搜「Vue 组件」搜不到「Vue 的组件」。slimsearch 用 segmentit 做中文分词,体验完胜:

import { slimsearchPlugin } from '@vuepress/plugin-slimsearch'

slimsearchPlugin({
  indexContent: true,
  hotReload: false,
  suggestion: true,
  searchDelay: 200,
  queryHistoryCount: 5,
  resultHistoryCount: 5,
  filter: (page) => page.frontmatter.search !== false
})

构建后会生成 searchIndex-*.js,首次加载约 200KB(gzip 后 ~70KB)。如果你文章很多(>200 篇),可以关掉 indexContent,只索引标题。

5.3 @vuepress/plugin-feed — 一键生成 RSS / Atom / JSON Feed

import { feedPlugin } from '@vuepress/plugin-feed'

feedPlugin({
  hostname: 'https://www.lxc666.cn',
  atom: true,
  json: true,
  rss: true,
  count: 30,
  image: 'https://www.lxc666.cn/logo.png',
  channel: {
    title: 'luoxuancong 博客',
    description: '前端开发博客 | AI工具教程',
    copyright: `© ${new Date().getFullYear()} luoxuancong | CC BY-NC-SA 4.0`,
    author: { name: 'luoxuancong', url: 'https://github.com/luoxuancong' }
  },
  // 仅订阅 blogs/ 目录下文章
  filter: ({ filePathRelative, frontmatter }) =>
    !!filePathRelative
    && filePathRelative.startsWith('blogs/')
    && frontmatter.feed !== false
})

输出 3 个文件:/rss.xml /atom.xml /feed.json,并在 HTML 头部自动注入 <link rel="alternate">,RSS 阅读器可以一键订阅。

5.4 @vuepress/plugin-pwa — 离线访问 + 桌面安装

import { pwaPlugin } from '@vuepress/plugin-pwa'

pwaPlugin({
  showInstall: true,
  cacheHTML: false,           // 关键:HTML 不预缓存(详见踩坑 2)
  cacheImage: false,           // 不预缓存大图:首次加载更快
  maxSize: 1024,
  maxImageSize: 512,
  themeColor: '#667eea',
  favicon: '/favicon.ico',
  apple: {
    icon: '/logo.png',
    statusBarColor: 'black-translucent'
  },
  update: 'available',
  generateSWConfig: {
    cleanupOutdatedCaches: true,           // 新 SW 激活时清掉上一版整包 precache
    runtimeCaching: [
      {
        urlPattern: ({ request }) => request.destination === 'document',
        handler: 'NetworkFirst',           // HTML 改走 NetworkFirst:每次都拉最新
        options: {
          cacheName: 'html-runtime',
          networkTimeoutSeconds: 3,         // 弱网 3 秒后落回缓存
          expiration: { maxEntries: 50, maxAgeSeconds: 7 * 24 * 60 * 60 }
        }
      }
    ]
  },
  manifest: {
    name: 'luoxuancong 博客',
    short_name: 'LXC Blog',
    theme_color: '#667eea',
    background_color: '#0a0a1a',
    display: 'standalone',
    start_url: '/',
    icons: [
      { src: '/logo.png', sizes: 'any', type: 'image/png', purpose: 'any' }
    ]
  }
})

踩坑

默认 Nginx 配置写 location = /404.html { internal; },会导致 Workbox 抓不到这个文件,构建后报 bad-precaching-response

解决:把 internal; 删了,加上 Cache-Control: no-cache

error_page 404 /404.html;
location = /404.html {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    access_log off;
}

踩坑

现象:你在 Nginx 给 CSP connect-src 加了一个新域名(例如对接 AdSense 时新增 https://*.adtrafficquality.google),刷新发布后用 curl -I 看响应头明明是新的,但老用户浏览器还是报旧 CSP 拦截,且不会自动好

根因cacheHTML: true 让 Workbox 通过 precacheAndRoute 把每张 HTML 的完整响应(含响应头!)存入 Cache Storage。Service Worker 拦截请求后从 Cache 返回,Nginx 改的新 CSP 根本到不了浏览器。即便 /service-worker.jsno-cache、新 SW 已经在跑,precache 只在文件 revision hash 变化时才刷新,响应头变化不算 revision 变 —— 这个旧响应可能在用户浏览器里待上几个月

修复(前面 5.4 节代码已经体现):

选项作用
cacheHTML: falseHTML 不再进入预缓存清单
generateSWConfig.runtimeCachingrequest.destination === 'document' 改走 NetworkFirst,每次都尝试新响应
generateSWConfig.cleanupOutdatedCaches: true新 SW 激活时强制清掉上一版整包 precache

部署后老用户首次访问会自动激活新 SW + 清旧 precache → CSP 同步生效;想立刻验证就 F12 → Application → Service Workers → Unregister + Clear site data + 硬刷新。

经验沉淀

场景适合 precache 吗
带 hash 的静态资源(JS / CSS / 图片)✅ 完美:内容不变 hash 不变
HTML 页面(路径稳定但响应头 / 内容会动)不要预缓存,走 NetworkFirst
Service Worker 自己❌ 强制 Cache-Control: no-cache

一句话总结:Workbox precache 锁的是「URL + revision」二元组,响应头变化不触发 revision 更新。任何只在 Nginx 加响应头的安全增强,对 cacheHTML=true 的 PWA 都对老用户无效。

5.5 vuepress-plugin-oh-my-live2d — 看板娘装饰

锦上添花的小插件,左下角放一只看板娘小猫:

import { oml2dPlugin } from 'vuepress-plugin-oh-my-live2d'

oml2dPlugin({
  dockedPosition: 'left',
  models: [
    {
      path: 'https://model.hacxy.cn/cat-black/model.json',
      scale: 0.1,
      position: [0, 30],
      stageStyle: { height: 280, width: 280 }
    }
  ],
  mobileDisplay: false   // 移动端隐藏,避免遮挡内容
})

踩坑

官方教程让你用 model.oml2d.com这个域名 2025 年已过期,所有看板娘模型 404。改用社区维护的 model.hacxy.cn,本博客就在用,稳定。


6. 写文章 / 首页配置

6.1 文章 frontmatter 模板

新建 docs/blogs/Vue/my-first-article.md

---
title: 我的第一篇 Vue 3 文章
date: 2026-05-12
isOriginal: true
author: 你的名字
description: 一句话概括文章内容,会出现在首页卡片
tags:
  - Vue3
  - Composition API
sitemap:
  priority: 0.9
keywords: Vue3, Composition API, ref, reactive
---

## 1. 引言

正文……

关键字段:

  • isOriginal: true — theme-reco 会在文章页显示「原创」徽章
  • sitemap.priority — 重要文章给 0.9,普通 0.7
  • keywords — 给搜索引擎的关键词(theme-reco 会注入 <meta name="keywords">
  • tags — 与 categories 分开,更细粒度
  • categories 不写:靠 autoSetBlogCategories: true 用目录名自动归类

6.2 首页 frontmatter(含 ICP 备案号)

docs/README.md

---
home: true
modules:
  - BannerBrand
  - Blog
  - MdContent
  - Footer
bannerBrand:
  title: luoxuancong
  description: 平安 喜乐
  tagline: 专注前端开发 · 分享实用工具
  buttons:
    - { text: '🚀 开始阅读', link: '/posts.html', type: 'primary' }
    - { text: '⏰ 时间线', link: '/timeline.html', type: 'plain' }
  socialLinks:
    - { icon: 'Github', link: 'https://github.com/your-name' }
footer:
  record: 粤ICP备XXXXX号
  recordLink: https://beian.miit.gov.cn/
  startYear: 2018
---

踩坑

1.x 是 themeConfig.record,2.x 改成了 frontmatter.footer.record,社区很多旧教程没更新。如果你写在 themeConfig 里页脚不会显示。

6.3 让 ICP 链接变成原生 <a>(百度联盟必需)

theme-reco 默认页脚的 ICP 用 <Xicons onclick> 渲染,百度联盟 / 百度爬虫识别不了。需要用 patch-package 改主题源码:

npm install -D patch-package postinstall-postinstall

修改 node_modules/vuepress-theme-reco/lib/client/components/Home/Footer.vue,把 <Xicons> 替换为原生 <a> 标签:

<span class="icp-anchor-wrapper" v-show="frontmatter?.footer?.record">
  <component class="xicon-icon" :is="IconSecurity" style="width:18px;height:18px" />
  <a
    :href="frontmatter?.footer?.recordLink || 'https://beian.miit.gov.cn/'"
    target="_blank"
    rel="noopener noreferrer"
    class="icp-anchor"
  >{{ frontmatter?.footer?.record }}</a>
</span>

然后:

npx patch-package vuepress-theme-reco

会在 patches/ 目录生成 vuepress-theme-reco+2.0.0-rc.25.patchpackage.json 加上 "postinstall": "patch-package",之后任何机器跑 npm install 都会自动应用补丁。


7. 部署上线

7.1 本地构建

npm run build
# 产物在 public/ 目录

7.2 Nginx 完整配置

服务器:Windows Server + Nginx 1.20,目录 C:\nginx-1.20.2\

nginx.conf 关键 server block:

# HTTP → HTTPS
server {
    listen 80;
    server_name www.lxc666.cn lxc666.cn;

    # Let's Encrypt 验证目录(必须在 80 端口)
    location /.well-known/acme-challenge/ {
        root C:/nginx-1.20.2/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS 主服务
server {
    listen 443 ssl http2;
    server_name www.lxc666.cn lxc666.cn;

    ssl_certificate     C:/nginx-1.20.2/ssl/www.lxc666.cn-chain.pem;
    ssl_certificate_key C:/nginx-1.20.2/ssl/www.lxc666.cn-key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    root C:/www/blog;
    index index.html;

    # PWA 修复:404.html 不能用 internal
    error_page 404 /404.html;
    location = /404.html {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    # 静态资源长缓存
    location ~* \.(?:css|js|woff2?|png|jpg|svg|gif|ico)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # HTML 不缓存(每次都拉新版)
    location ~* \.html$ {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }
}

7.3 Let's Encrypt + win-acme 自动续签

Windows 上用 win-acmeopen in new window 是最佳选择:

# 下载 win-acme(解压到 C:\win-acme)
# 申请覆盖 www + apex 的 SAN 证书
C:\win-acme\wacs.exe `
  --target manual `
  --host "www.lxc666.cn,lxc666.cn" `
  --commonname "www.lxc666.cn" `
  --validation http-01 `
  --webroot C:\nginx-1.20.2\html `
  --emailaddress your@email.com `
  --accepttos `
  --installation script `
  --script "C:\nginx-1.20.2\reload.bat"

踩坑

早期我只签发了 www.lxc666.cn 的证书,导致 https://lxc666.cn/ 浏览器报「证书不匹配」。

Google AdSense 的爬虫直接访问 apex 域时也会拿不到证书,导致网站验证失败

解决--host "www.lxc666.cn,lxc666.cn" 一次签发覆盖两个域名的 SAN 证书。

win-acme 会自动在 Windows 任务计划程序里创建续签任务(每天检查,到期前 30 天自动续)。

7.4 Apex 域处理

很多人配置时只让 www 工作,让 apex 301 跳到 www。但实测时发现,部分 Google AdSense 验证场景下,爬虫并不跟随 301 重定向——如果你绑定的是 apex 域名(如 lxc666.cn),就必须让 apex 直接 200 响应

# ✅ 正确:两个域名共用同一个 server block,直接 200
server {
    listen 443 ssl http2;
    server_name www.lxc666.cn lxc666.cn;  # 两个域名
    # ... 直接服务内容
}

# ❌ 错误:apex 301 到 www,AdSense 可能验证失败
server {
    listen 443 ssl http2;
    server_name lxc666.cn;
    return 301 https://www.lxc666.cn$request_uri;
}

DNS 这一侧也要确认:阿里云 / 腾讯云 DNS 控制台同时给 @www 加 A 记录,都指向同一台服务器。


8. SEO 全攻略

8.1 三件套自动注入

由插件全自动完成:

  • Sitemap → /sitemap.xml(plugin-sitemap)
  • RSS / Atom / JSON Feed → /rss.xml /atom.xml /feed.json(plugin-feed)
  • PWA manifest → /manifest.webmanifest(plugin-pwa)

8.2 Open Graph & Twitter Card

config.tshead 字段手动写:

head: [
  ['meta', { property: 'og:type', content: 'website' }],
  ['meta', { property: 'og:site_name', content: 'luoxuancong' }],
  ['meta', { property: 'og:locale', content: 'zh_CN' }],
  ['meta', { property: 'og:title', content: 'luoxuancong | 前端开发博客' }],
  ['meta', { property: 'og:description', content: '前端开发博客 | AI工具教程' }],
  ['meta', { property: 'og:url', content: 'https://www.lxc666.cn' }],
  ['meta', { property: 'og:image', content: 'https://www.lxc666.cn/logo.png' }],
  ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
  ['meta', { name: 'twitter:title', content: 'luoxuancong | 前端开发博客' }],
  ['meta', { name: 'twitter:description', content: '前端开发博客 | AI工具教程' }],
  ['meta', { name: 'twitter:image', content: 'https://www.lxc666.cn/logo.png' }]
]

发到微信 / Telegram / Twitter 时会自动展示卡片。

8.3 结构化数据 JSON-LD

帮助 Google / 百度理解站点元信息,提高富片段(Rich Result)出现概率:

['script', { type: 'application/ld+json' }, JSON.stringify({
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "luoxuancong 博客",
  "url": "https://www.lxc666.cn",
  "inLanguage": "zh-CN",
  "description": "前端开发博客",
  "author": {
    "@type": "Person",
    "name": "罗玄聪",
    "url": "https://github.com/luoxuancong"
  }
})]

8.4 CSP 不能阻挡 SEO

Content Security Policy 是必要的安全头,但写得太严会让 Google 抓不到内容、广告跑不起来。本博客实战后的 CSP 模板:

add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval'
    https://hm.baidu.com
    https://pagead2.googlesyndication.com
    https://*.googlesyndication.com
    https://googleads.g.doubleclick.net
    https://adtrafficquality.google
    https://*.adtrafficquality.google;
  connect-src 'self'
    https://comment.lxc666.cn
    https://hm.baidu.com
    https://pagead2.googlesyndication.com
    https://*.googlesyndication.com
    https://googleads.g.doubleclick.net
    https://www.google.com
    https://*.adtrafficquality.google
    https://csi.gstatic.com;
  img-src 'self' data: https:;
  style-src 'self' 'unsafe-inline';
  frame-src https://googleads.g.doubleclick.net https://*.googlesyndication.com https://www.google.com https://*.adtrafficquality.google;
" always;

关键技巧

*.adtrafficquality.google 通配符可以一次覆盖 ep1.ep2.tpc. 等子域名,省得每次 AdSense 出新子域名都改 CSP。

8.5 提交收录

构建上线后,立刻去:

  1. 百度站长平台https://ziyuan.baidu.comopen in new window → 添加网站 → 提交 sitemap.xml
  2. Google Search Consolehttps://search.google.com/search-consoleopen in new window → 添加资源 → 提交 sitemap
  3. Bing 站长https://www.bing.com/webmastersopen in new window(也是必应中文搜索的来源,别忘)

国内一般 3-7 天百度开始收录,Google 24 小时内能搜到首页。


9. 进阶:让博客真正活起来

到这里你的博客已经可以跑了,但还不够。这一节讲让博客「有人评论、能赚钱、看着舒服」的最后一公里。

9.1 评论系统 Waline 自建

vuepress-plugin-comments + Waline 是最佳组合,不依赖第三方账号,数据存在自己的 Vercel / 服务器:

  1. fork Waline 官方仓库open in new window
  2. 用 Vercel 一键部署(数据库选 LeanCloud / Supabase)
  3. config.ts 主题配置里:
commentConfig: {
  type: 'waline',
  options: {
    serverURL: 'https://comment.lxc666.cn',  // 自定义域名
    pageview: true
  }
}

小技巧

给 Waline 绑定自定义域名(如 comment.your-blog.com),可以绕开 vercel.app 域名在国内被墙的问题。

9.2 Google AdSense 接入

简要步骤(详细踩坑记录见本文下半段「踩坑提示框」):

  1. 申请 Google AdSenseopen in new window 账号,绑定 lxc666.cn
  2. config.ts 注入:
['script', {
  async: 'true',
  src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX',
  crossorigin: 'anonymous'
}]
  1. docs/.vuepress/public/ads.txt 写入:
google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0
  1. Nginx CSP 放行 AdSense 域名(参考第 8.4 节)
  2. 等 1-14 天 Google 内容审核

重要

审核期间务必新增 /privacy.html/disclaimer.html,否则二轮人工审核会被卡。

9.3 百度统计 / Google Analytics

国内访问数据用百度统计(hm.baidu.com),海外用 Google Analytics(gtag)。

百度统计:

// docs/.vuepress/public/js/baidu.js
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?YOUR_BAIDU_ID";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();

config.ts 中:

['script', { src: '/js/baidu.js', defer: 'true' }]

9.4 性能优化清单

  • ✅ Nginx 开 gzipbrotli(brotli 比 gzip 小 20%)
  • ✅ 静态资源 30 天缓存 + immutable
  • ✅ HTML 不缓存(保证内容及时更新)
  • ✅ DNS prefetch 第三方域(<link rel="dns-prefetch">
  • defer / async 加载所有 JS(避免阻塞渲染)
  • ✅ 关闭 VuePress 自带 prefetch(与 PWA Service Worker 冲突):
export default defineUserConfig({
  shouldPrefetch: false,
  // ...
})

Lighthouse 跑分目标:性能 ≥ 90、SEO ≥ 95、最佳实践 ≥ 95、无障碍 ≥ 90。


10. 总结 & 完整源码

到这里你的博客应该已经具备:

  • ✅ Vue 3 + VuePress 2 + theme-reco 现代化技术栈
  • ✅ HTTPS(含 apex 域 SAN 证书 + 自动续签)
  • ✅ PWA 离线可用 + 桌面安装
  • ✅ 全文搜索(中文分词)
  • ✅ RSS / Atom / JSON Feed 订阅
  • ✅ Open Graph / Twitter Card / 结构化数据
  • ✅ ICP 备案号原生 <a> 合规
  • ✅ Google AdSense + 百度联盟 接入条件
  • ✅ Waline 自建评论
  • ✅ Lighthouse ≥ 90

完整依赖清单

{
  "engines": { "node": ">=18.16.0" },
  "scripts": {
    "dev": "vuepress dev docs",
    "build": "vuepress build docs",
    "postinstall": "patch-package"
  },
  "devDependencies": {
    "@vuepress/plugin-feed": "2.0.0-rc.61",
    "@vuepress/plugin-pwa": "2.0.0-rc.61",
    "@vuepress/plugin-sitemap": "2.0.0-rc.61",
    "@vuepress/plugin-slimsearch": "2.0.0-rc.61",
    "patch-package": "^8.0.1",
    "vuepress": "2.0.0-rc.18",
    "vuepress-theme-reco": "^2.0.0-rc.25"
  },
  "dependencies": {
    "@vuepress/bundler-vite": "2.0.0-rc.18",
    "vue": "^3.5.13",
    "vuepress-plugin-oh-my-live2d": "^0.19.3"
  }
}

参考资料

写在最后

我从 2018 年开始写这个博客,最早用的是 Hexo,2021 年换 VuePress 1,2026 年初彻底重写到 VuePress 2 + theme-reco 2.x。这一路最大的感受是:

个人博客不是为了流量,而是为了沉淀。每解决一个工程问题就写一篇,3 年后你会有几百篇带搜索权重的「私人文档」——遇到问题搜自己的博客比翻笔记快多了。

如果你正在搭建第一个博客,希望本文能帮你少走 90 天的弯路。

本站源码https://gitee.com/luoxuancong/blogopen in new window(v2 分支)

联系方式:可在 关于我 页面留言、或评论区互动。

—— luoxuancong,2026 年 5 月写于深圳

Last Updated 2026/5/12 16:15:48
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8