[{"data":1,"prerenderedAt":545},["ShallowReactive",2],{"content:\u002F2026\u002Fblog-build-record":3,"surround:\u002F2026\u002Fblog-build-record":535},{"id":4,"title":5,"body":6,"categories":508,"date":510,"description":511,"draft":512,"extension":513,"image":514,"meta":515,"navigation":517,"path":518,"permalink":514,"published":514,"readingTime":519,"recommend":514,"references":514,"seo":524,"sitemap":525,"stem":526,"tags":527,"type":533,"updated":510,"__hash__":534},"content\u002Fposts\u002F2026\u002FBlog-Build-Record.md","个人博客搭建全记录：从 Fork 到上线",{"type":7,"value":8,"toc":485},"minimark",[9,13,17,21,33,37,44,47,83,102,106,115,122,192,204,208,211,215,218,241,244,258,261,275,278,293,296,322,328,332,335,345,348,386,389,392,396,403,407,424,428,438,442,449,453,460,470,473,476,479],[10,11,5],"h1",{"id":12},"个人博客搭建全记录从-fork-到上线",[14,15,16],"h2",{"id":16},"前言",[18,19,20],"p",{},"写这篇文章的时候，这个博客已经上线运行了一段时间。回头看整个过程 —— 从 Fork 一个开源主题，到逐项修改配置、接入统计和评论、部署到自己的服务器 —— 踩了不少坑，也学到了很多东西。与其让这些经验烂在脑子里，不如整理出来，给也想自己搭博客的朋友一个参考。",[22,23,25],"alert",{"type":24},"info",[18,26,27,28,32],{},"本文不是教程，是",[29,30,31],"strong",{},"复盘","。会提到具体的技术选型和操作步骤，但更想说的是每个阶段踩过的坑和当时的决策逻辑。",[14,34,36],{"id":35},"起点为什么要自己搭","起点：为什么要自己搭",[18,38,39,40,43],{},"其实本来有一个基于 Halo 的个人主站，日常写文章、发动态都在那边。但 Halo 毕竟是个 CMS，重、依赖 Java 运行时、一些定制不够灵活。想有一个",[29,41,42],{},"更轻、更可控、能当静态站部署","的地方，专门放那些需要精心排版的长文。",[18,45,46],{},"需求很明确：",[48,49,50],"card-list",{},[51,52,53,60,71,77],"ul",{},[54,55,56,59],"li",{},[29,57,58],{},"静态优先","：最好能生成纯 HTML，放 Nginx 就跑，不需要 Node 进程常驻",[54,61,62,65,66,70],{},[29,63,64],{},"Markdown 写作","：所有内容用 ",[67,68,69],"code",{"code":69},".md"," 文件管，方便 Git 版本控制",[54,72,73,76],{},[29,74,75],{},"组件丰富","：文章里能嵌入各种视觉组件（提示框、卡片、时间线、代码沙盒等）",[54,78,79,82],{},[29,80,81],{},"自己掌控部署","：不和任何平台绑定，随时搬家",[18,84,85,86,93,94,97,98,101],{},"在这个前提下，",[87,88,92],"a",{"href":89,"rel":90},"https:\u002F\u002Fcontent.nuxt.com\u002F",[91],"nofollow","Nuxt Content"," 几乎是唯一的完美选项 —— 它是 Nuxt 的内容模块，写 Markdown 就像写 Vue 组件一样，支持自定义 MDC 组件（也就是你在这个博客里看到的 ",[67,95,96],{"code":96},"::alert","、",[67,99,100],{"code":100},"::card-list"," 这些），还能一键生成静态站。",[14,103,105],{"id":104},"选主题fork-了-clarity","选主题：Fork 了 Clarity",[18,107,108,109,114],{},"确定用 Nuxt Content 之后，在 GitHub 上找到了 ",[87,110,113],{"href":111,"rel":112},"https:\u002F\u002Fgithub.com\u002FL33Z22L11\u002Fblog-v3",[91],"L33Z22L11\u002Fblog-v3","—— 也就是这个博客的「上游」。Clarity 主题的设计风格参考了 Stellar（一个 Hexo 主题），走的简洁、专注阅读的路线，和我的需求高度吻合。",[18,116,117,118,121],{},"Fork 之后的第一件事：",[29,119,120],{},"把原作者的配置全部改成自己的","。这一步看着简单，实际改了十几个文件：",[123,124,125,138],"table",{},[126,127,128],"thead",{},[129,130,131,135],"tr",{},[132,133,134],"th",{},"文件",[132,136,137],{},"改了什么",[139,140,141,152,162,172,182],"tbody",{},[129,142,143,149],{},[144,145,146],"td",{},[67,147,148],{"code":148},"blog.config.ts",[144,150,151],{},"标题、副标题、作者名、头像、邮箱、域名、建站日期",[129,153,154,159],{},[144,155,156],{},[67,157,158],{"code":158},"app\u002Fapp.config.ts",[144,160,161],{},"导航菜单、页脚社交链接、公告、GitHub 卡片、备案号",[129,163,164,169],{},[144,165,166],{},[67,167,168],{"code":168},"content\u002Fposts\u002F",[144,170,171],{},"删除原作者文章，换上自己的",[129,173,174,179],{},[144,175,176],{},[67,177,178],{"code":178},"app\u002Ffeeds.ts",[144,180,181],{},"删除原作者友链，换上自己的友链列表",[129,183,184,189],{},[144,185,186],{},[67,187,188],{"code":188},"redirects.json",[144,190,191],{},"清空原作者的重定向规则",[22,193,195],{"type":194},"warning",[18,196,197,200,201,203],{},[29,198,199],{},"一个重要的教训","：原作者的 README 里明确写了「严禁将项目内我（原作者）的文章以你的名义重新发布」。Fork 后第一步就应该把 ",[67,202,168],{"code":168}," 里的所有文章删干净，再开始写自己的。不要留着「当模板参考」—— 万一不小心推送到了公开仓库，就是版权问题。",[14,205,207],{"id":206},"自定义不只是改配置","自定义：不只是改配置",[18,209,210],{},"换完基本信息之后，开始动刀更多定制：",[212,213,214],"h3",{"id":214},"导航和侧栏",[18,216,217],{},"Clarity 默认只有「文章」「友链」「归档」三个入口。我逐步加到了 10 个 —— 即刻、标签、友圈、番剧、项目、游戏、关于。每加一个页面就配一个侧栏组件（公告卡片、一言、GitHub 卡片、最新评论等）。",[18,219,220,221,224,225,228,229,232,233,236,237,240],{},"这个过程教会我一件事：",[29,222,223],{},"Nuxt 的自动导入和约定路由太省心了","。新建 ",[67,226,227],{"code":227},"app\u002Fpages\u002Ftags.vue","，它自动就是 ",[67,230,231],{"code":231},"\u002Ftags"," 页面。新建 ",[67,234,235],{"code":235},"app\u002Fcomponents\u002Fcontent\u002F"," 下的 ",[67,238,239],{"code":239},".vue"," 文件，Markdown 里就能直接用。",[212,242,243],{"id":243},"统计和评论",[18,245,246,247,250,251,253,254,257],{},"这部分主要是接入外部服务。用了 Umami（自建统计分析）、Cloudflare Web Analytics（辅助统计）和 Twikoo（评论系统）。都是",[29,248,249],{},"浏览器端加载","的 —— 把 JS 脚本和对应的 ID\u002FToken 填进 ",[67,252,148],{"code":148}," 的 ",[67,255,256],{"code":256},"scripts"," 数组，构建时不需要它们可达。所以即使博客是纯静态站，这些动态功能一样能用 —— 评论和统计的 JS 是用户浏览器自己去请求的，不经过服务器。",[212,259,260],{"id":260},"友链系统",[18,262,263,264,267,268,271,272,274],{},"这可能是自己实现得最满意的一个功能。不想依赖外部 Friend-Circle-Lite 后端，就在 ",[67,265,266],{"code":266},"server\u002Fapi\u002Ffriend-circle.get.ts"," 里写了一个",[29,269,270],{},"构建时 RSS 聚合器","—— 读取 ",[67,273,178],{"code":178}," 里每个友链的订阅源地址，逐一抓取并解析 Atom\u002FRSS，合并成友圈数据。",[18,276,277],{},"这样做的好处：",[51,279,280,283,290],{},[54,281,282],{},"零外部依赖，不用部署任何额外后端",[54,284,285,286,289],{},"每次 ",[67,287,288],{"code":288},"bash deploy.sh"," 刷新数据",[54,291,292],{},"走同源接口，无跨域问题",[212,294,295],{"id":295},"组件库",[18,297,298,299,97,301,97,304,97,307,97,310,97,313,97,315,97,318,321],{},"这也是折腾最多的地方。Clarity 自带了不少组件（",[67,300,96],{"code":96},[67,302,303],{"code":303},"::quote",[67,305,306],{"code":306},"::pic",[67,308,309],{"code":309},"::chat",[67,311,312],{"code":312},"::timeline",[67,314,100],{"code":100},[67,316,317],{"code":317},"::tab",[67,319,320],{"code":320},"::folding"," 等），写文章时已经够用。但后来在写教程类文章时发现 —— 多层嵌套列表太长了，折叠框缩进容易出 bug，有些视觉表达没合适的组件。试着移植过 Stellar 主题的组件，踩了 MDC 语法和缩进的一堆坑。",[18,323,324,325],{},"最终的教训是：",[29,326,327],{},"不要从零手写组件然后猜样式。要么从同架构的 fork 里移植，要么从真实渲染页面截取 DOM 结构当设计稿。",[14,329,331],{"id":330},"部署从-vercel-到-1panel","部署：从 Vercel 到 1Panel",[18,333,334],{},"最初想直接推 Vercel，但考虑到自己有服务器、想完全掌控，最终还是选了自托管。",[18,336,337,338,341,342,344],{},"服务器是雨云（RainYun）的 Debian 机器，面板用的 1Panel。部署流程简化后就是：本地 ",[67,339,340],{"code":340},"git push"," → 服务器 ",[67,343,288],{"code":288},"（拉代码 → 构建 → 拷贝到 nginx 目录）。",[18,346,347],{},"几个关键配置：",[48,349,350],{},[51,351,352,361,371,377],{},[54,353,354,357,358],{},[29,355,356],{},"网站类型","：1Panel 创建时选「静态网站」，root 指到 ",[67,359,360],{"code":360},".output\u002Fpublic",[54,362,363,366,367,370],{},[29,364,365],{},"伪静态","：",[67,368,369],{"code":369},"try_files $uri $uri.html $uri\u002F \u002F404.html","（否则文章页刷新 404）",[54,372,373,376],{},[29,374,375],{},"HTTPS","：1Panel 里一键申请 Let's Encrypt + 开启强制跳转",[54,378,379,382,383],{},[29,380,381],{},"deploy.sh","：封装了 ",[67,384,385],{"code":385},"git pull && npx nuxi generate && rm -rf 目标目录\u002F* && cp",[14,387,388],{"id":388},"踩坑复盘",[18,390,391],{},"整个搭建过程踩过的坑，挑几个印象最深的：",[212,393,395],{"id":394},"坑-1服务器-node-版本太低","坑 1：服务器 Node 版本太低",[18,397,398,399,402],{},"Nuxt Content v3 需要 Node 22.5+ 才支持 ",[67,400,401],{"code":401},"node:sqlite","。服务器初始是 Node 22.0，导致内容数据库读不出来，首页一篇文章都没有。排查了很久才发现是 SQLite 连接器的问题。升级到 Node 24 后解决。",[212,404,406],{"id":405},"坑-2mdc-组件缩进","坑 2：MDC 组件缩进",[18,408,409,97,411,97,413,415,416,423],{},[67,410,317],{"code":317},[67,412,312],{"code":312},[67,414,320],{"code":320}," 这些块级组件的",[29,417,418,419,422],{},"闭合标记 ",[67,420,421],{"code":421},"::"," 必须顶格","，不能和内容对齐缩进。一旦缩进错了，MDC 解析器不会报错，只是默默地把你后面所有内容都吞掉。这是最难排查的一类 bug，因为看起来语法完全正确。",[212,425,427],{"id":426},"坑-3行内组件用单冒号","坑 3：行内组件用单冒号",[18,429,430,433,434,437],{},[67,431,432],{"code":432},"::mark"," 双冒号在 MDC 里被当成块级组件处理，不会渲染。行内组件（mark、kbd、wavy 等）必须用单冒号 ",[67,435,436],{"code":436},":mark[text]{color=red}","。",[212,439,441],{"id":440},"坑-4github-图在服务器上超时","坑 4：GitHub 图在服务器上超时",[18,443,444,445,448],{},"首页即刻卡片引用了 ",[67,446,447],{"code":447},"raw.githubusercontent.com"," 的冰山图截图。本地好好的，服务器一构建就卡住 —— 因为雨云在国内，GitHub 的 raw 域名经常不可达。后来把图片移到了自己的图床才稳定。",[212,450,452],{"id":451},"坑-5prerender-外链超时","坑 5：Prerender 外链超时",[18,454,455,456,459],{},"构建时会爬取所有外链（友链、图片、参考链接），有些友链站返回 404 或超时就把整个构建中断了。后来在 ",[67,457,458],{"code":458},"nuxt.config.ts"," 加了两个配置：",[461,462,468],"pre",{"className":463,"code":465,"language":466,"meta":467},[464],"language-ts","nitro: { prerender: { failOnError: false } },     \u002F\u002F 单页失败不中断\nlinkChecker: { skipInspections: ['no-error-response'] }, \u002F\u002F 跳过外链存活检查\n","ts","",[67,469,465],{"__ignoreMap":467},[14,471,472],{"id":472},"写在最后",[18,474,475],{},"从一个 Fork 到现在的样子，这个博客经历了十几个小时的高强度改造。但它给我带来的不仅是「有了一个博客」—— 更重要的是对自己部署链路的完整掌控，以及对 Nuxt + Nuxt Content 这个技术栈的深入理解。",[18,477,478],{},"如果你也想搭一个类似的博客，希望这篇复盘能帮你少走一些弯路。",[480,481,482],"quote",{},[18,483,484],{},"博客不只是发表文章的地方，也是记录自己成长的地方。这个博客本身，就是最好的第一篇作品。",{"title":467,"searchDepth":486,"depth":486,"links":487},4,[488,490,491,492,499,500,507],{"id":16,"depth":489,"text":16},2,{"id":35,"depth":489,"text":36},{"id":104,"depth":489,"text":105},{"id":206,"depth":489,"text":207,"children":493},[494,496,497,498],{"id":214,"depth":495,"text":214},3,{"id":243,"depth":495,"text":243},{"id":260,"depth":495,"text":260},{"id":295,"depth":495,"text":295},{"id":330,"depth":489,"text":331},{"id":388,"depth":489,"text":388,"children":501},[502,503,504,505,506],{"id":394,"depth":495,"text":395},{"id":405,"depth":495,"text":406},{"id":426,"depth":495,"text":427},{"id":440,"depth":495,"text":441},{"id":451,"depth":495,"text":452},{"id":472,"depth":489,"text":472},[509],"杂谈","2026-07-13 00:00:00","从 Fork Clarity 主题、逐项自定义站点信息、接入统计评论，到 1Panel 部署上线——记录了搭建这个博客的全过程与踩过的坑。",false,"md",null,{"slots":516},{},true,"\u002F2026\u002Fblog-build-record",{"text":520,"minutes":521,"time":522,"words":523},"10 min read",9.375,562500,1875,{"title":5,"description":511},{"loc":518},"posts\u002F2026\u002FBlog-Build-Record",[528,529,530,531,532],"博客","Nuxt","Clarity","建站","1Panel","tech","_zCGHBmfQ-ddR4PGiVLOpQpV2-3erxKXM623yUdIyXc",[536,541],{"title":537,"path":538,"stem":539,"date":540,"type":533,"children":-1},"中文文案排版指南","\u002F2026\u002Fchinese-copywriting-guidelines","posts\u002F2026\u002FChinese-Copywriting-Guidelines","2026-07-12 17:10:00",{"title":542,"path":543,"stem":544,"date":510,"type":533,"children":-1},"冰山图宇宙项目指南","\u002F2026\u002Ficebergs-guide","posts\u002F2026\u002FIcebergs-Guide",1784029686231]