[{"data":1,"prerenderedAt":659},["ShallowReactive",2],{"\u002F2026\u002Ftypechotoblog-v3":3,"surround-\u002F2026\u002Ftypechotoblog-v3":653},{"id":4,"title":5,"body":6,"categories":628,"date":630,"description":631,"draft":632,"extension":324,"image":633,"meta":634,"navigation":533,"path":638,"permalink":633,"published":633,"readingTime":639,"recommend":633,"references":633,"seo":644,"sitemap":645,"stem":646,"tags":647,"type":651,"updated":633,"__hash__":652},"content\u002Fposts\u002F2026\u002Ftypechotoblog-v3.md","从 Typecho 迁移到 blog-v3：把动态博客变成静态站",{"type":7,"value":8,"toc":612},"minimark",[9,17,20,27,33,39,43,46,49,68,73,76,126,141,145,165,168,171,186,193,196,211,237,240,243,246,302,312,315,318,328,332,335,348,351,359,371,375,378,399,407,417,421,453,456,459,462,465,483,487,490,501,508,517,520,597,600,606,609],[10,11,13],"quote",{"icon":12},"tabler:git-branch",[14,15,16],"p",{},"以前写博客，是登录 Typecho 后台、维护 PHP 和 MySQL；迁移之后，是写 Markdown、提交 Git，再让 Vercel 自动把站点发布出去。",[14,18,19],{},"这篇记录不是一份“从零开始”的教程，而是一次迁移复盘：为什么从 Typecho 换到 blog-v3，迁移时处理了哪些内容，哪些地方容易踩坑，以及最后如何部署到 Vercel。",[21,22],"link-card",{"description":23,"icon":24,"link":25,"title":26},"基于 Nuxt Content 的静态博客项目","https:\u002F\u002Fgithub.githubassets.com\u002Ffavicons\u002Ffavicon.svg","https:\u002F\u002Fgithub.com\u002FL33Z22L11\u002Fblog-v3","blog-v3",[21,28],{"description":29,"icon":30,"link":31,"title":32},"用于部署静态站点和前端项目","https:\u002F\u002Fassets.vercel.com\u002Fimage\u002Fupload\u002Ffront\u002Ffavicon\u002Fvercel\u002F180x180.png","https:\u002F\u002Fvercel.com\u002F","Vercel",[21,34],{"description":35,"icon":36,"link":37,"title":38},"MDC 语法和 Markdown 内容能力","https:\u002F\u002Fcontent.nuxt.com\u002Ffavicon.ico","https:\u002F\u002Fcontent.nuxt.com\u002Fdocs\u002Ffiles\u002Fmarkdown#mdc-syntax","Nuxt Content Markdown",[40,41,42],"h2",{"id":42},"为什么迁移",[14,44,45],{},"Typecho 很轻，写作体验也稳定。它的问题不在“不能用”，而在维护成本会慢慢变成隐形负担：服务器环境、PHP 版本、数据库备份、主题兼容、插件更新、反垃圾评论、附件路径，这些东西都需要持续照看。",[14,47,48],{},"我后来更想要的是一种简单的发布链路：",[50,51,52,56,59,62,65],"ul",{},[53,54,55],"li",{},"文章就是 Markdown 文件。",[53,57,58],{},"历史版本交给 Git 管。",[53,60,61],{},"构建和部署交给 Vercel。",[53,63,64],{},"博客本身尽量不依赖数据库。",[53,66,67],{},"换服务器、换域名、回滚文章都更直接。",[69,70,72],"tip",{"tip":71},"它只是把动态渲染、数据库查询这些运行时工作，前移到了构建阶段。","静态博客不等于功能变少",[40,74,75],{"id":75},"迁移路线",[77,78,79,82,90,93,96,99,102,105,108,111,114,117,120,123],"timeline",{},[14,80,81],{},"{备份 Typecho 数据库和附件}",[14,83,84,85,89],{},"先保留完整数据库、",[86,87,88],"code",{"code":88},"usr\u002Fuploads"," 附件目录、主题目录和配置文件。",[14,91,92],{},"{导出文章}",[14,94,95],{},"从数据库中取出文章标题、正文、发布时间、分类、标签、slug 和永久链接。",[14,97,98],{},"{转换 Markdown}",[14,100,101],{},"把 Typecho 的 HTML 或 Markdown 内容整理成 blog-v3 能读取的 Markdown 文件。",[14,103,104],{},"{整理图片与链接}",[14,106,107],{},"统一图片目录，处理旧站内链、附件路径、相对路径和历史永久链接。",[14,109,110],{},"{本地构建}",[14,112,113],{},"在本地运行安装、开发和构建命令，确认文章、组件、RSS、站点地图都能正常生成。",[14,115,116],{},"{推送 GitHub}",[14,118,119],{},"把 blog-v3 项目推送到 GitHub，让 Vercel 接管部署流程。",[14,121,122],{},"{部署到 Vercel}",[14,124,125],{},"导入仓库，设置构建命令、环境变量和域名，等构建通过后再切换正式流量。",[127,128,131,138],"alert",{"type":129,":card":130},"warning","true",[132,133,135],"template",{"v-slot:title":134},"",[14,136,137],{},"不要急着删除旧站",[14,139,140],{},"新站第一次上线后，旧 Typecho 至少保留一段时间。先确认文章 URL、图片、RSS、站点地图、搜索引擎收录和评论系统都没问题，再考虑关闭旧环境。",[40,142,144],{"id":143},"typecho-和-blog-v3-的差异","Typecho 和 blog-v3 的差异",[146,147,149,157],"tab",{":tabs":148,":center":130},"[\"Typecho\",\"blog-v3\"]",[132,150,151,154],{"v-slot:tab1":134},[14,152,153],{},"Typecho 是动态博客系统，核心数据在 MySQL 里。它的优势是后台写作方便、生态成熟、部署在传统 PHP 主机上很直接。",[14,155,156],{},"但它也意味着每次访问都依赖运行时环境：Web 服务器、PHP、数据库、插件和主题都要保持可用。",[132,158,159,162],{"v-slot:tab2":134},[14,160,161],{},"blog-v3 更接近“内容工程化”。文章是 Markdown，配置是代码，发布靠 Git，页面在构建时生成。",[14,163,164],{},"它的优势是迁移和回滚简单，部署平台可以换，文章历史清晰；代价是写作流程从后台编辑器变成了本地文件和 Git 提交。",[40,166,167],{"id":167},"备份旧站",[14,169,170],{},"迁移第一步不是导出，而是备份。即使后面转换脚本写错、图片路径处理错、文章格式乱掉，只要备份完整，就还能重来。",[172,173,175],"folding",{"title":174,":open":130},"备份数据库和附件",[176,177,184],"pre",{"className":178,"code":180,"filename":181,"language":182,"meta":183},[179],"language-sh","# 备份数据库\nmysqldump -u typecho_user -p typecho_db > typecho-2026-05-04.sql\n\n# 备份附件\ntar -czf typecho-uploads-2026-05-04.tar.gz \u002Fpath\u002Fto\u002Ftypecho\u002Fusr\u002Fuploads\n\n# 备份主题和配置\ntar -czf typecho-site-2026-05-04.tar.gz \u002Fpath\u002Fto\u002Ftypecho\u002Fusr\u002Fthemes \u002Fpath\u002Fto\u002Ftypecho\u002Fconfig.inc.php\n","backup.sh","sh","icon=tabler:database-export",[86,185,180],{"__ignoreMap":134},[127,187,190],{"type":188,"title":189},"info","备份时我会额外留意这些字段",[14,191,192],{},"文章正文、文章 slug、创建时间、更新时间、分类、标签、自定义字段、附件路径、评论数据和旧永久链接。尤其是永久链接，后面要不要做跳转，全靠这一步记录清楚。",[40,194,195],{"id":195},"导出文章",[14,197,198,199,202,203,206,207,210],{},"Typecho 的文章主要在 ",[86,200,201],{"code":201},"typecho_contents"," 表里，分类和标签关系通常在 ",[86,204,205],{"code":205},"typecho_relationships","、",[86,208,209],{"code":209},"typecho_metas"," 里。我的处理方式是先导出结构化数据，再生成 Markdown 文件。",[172,212,214,224,227],{"title":213},"一个简化的导出思路",[176,215,222],{"className":216,"code":218,"filename":219,"language":220,"meta":221},[217],"language-sql","SELECT\n  cid,\n  title,\n  slug,\n  text,\n  created,\n  modified,\n  type,\n  status\nFROM typecho_contents\nWHERE type = 'post'\n  AND status = 'publish'\nORDER BY created ASC;\n","export-posts.sql","sql","icon=tabler:database-search",[86,223,218],{"__ignoreMap":134},[14,225,226],{},"拿到数据后，再把每篇文章转换成类似这样的文件：",[176,228,235],{"className":229,"code":231,"filename":232,"language":233,"meta":234},[230],"language-yaml","---\ntitle: 文章标题\ndescription: 文章摘要\ndate: 2026-05-04\nupdated: 2026-05-04\ntype: tech\ntags: [旧标签一, 旧标签二]\n---\n","post-frontmatter.yml","yaml","icon=catppuccin:yaml",[86,236,231],{"__ignoreMap":134},[14,238,239],{},"这里最耗时间的不是导出，而是清理正文。老文章里可能混着 HTML、短代码、相对图片、旧主题样式类名，以及一些只在 Typecho 插件里有效的写法。",[40,241,242],{"id":242},"内容清理",[14,244,245],{},"我把内容清理拆成三类。",[247,248,249],"card-list",{},[50,250,251,271,288],{},[53,252,253,254],{},"能自动替换的内容\n",[50,255,256,259,265,268],{},[53,257,258],{},"旧图片域名",[53,260,261,264],{},[86,262,263],{"code":263},"\u002Fusr\u002Fuploads\u002F"," 路径",[53,266,267],{},"常见 HTML 标签",[53,269,270],{},"站内链接",[53,272,273,274],{},"需要人工检查的内容\n",[50,275,276,279,282,285],{},[53,277,278],{},"复杂表格",[53,280,281],{},"代码块语言",[53,283,284],{},"旧短代码",[53,286,287],{},"嵌入视频",[53,289,290,291],{},"可以顺手重写的内容\n",[50,292,293,296,299],{},[53,294,295],{},"年久失效的外链",[53,297,298],{},"不准确的描述",[53,300,301],{},"已经过时的教程步骤",[127,303,304,309],{"type":129,":card":130},[132,305,306],{"v-slot:title":134},[14,307,308],{},"图片路径最容易拖慢迁移",[14,310,311],{},"如果旧文章大量使用相对路径，建议先统一成绝对路径或迁移到固定图床。静态博客部署到 Vercel 后，图片路径不会再经过 Typecho 的运行时逻辑兜底。",[14,313,314],{},"迁移时我保留了一个原则：文章正文尽量变成“普通 Markdown”。只有确实能增强阅读体验的地方，才使用 blog-v3 的 MDC 组件。",[14,316,317],{},"比如提示类内容可以改成：",[176,319,326],{"className":320,"code":322,"filename":323,"language":324,"meta":325},[321],"language-md","::alert{type=\"info\" title=\"迁移提示\"}\n如果旧站文章 URL 已经被搜索引擎收录，迁移后要么保持路径一致，要么配置 301 跳转。\n::\n","alert-example.md","md","icon=tabler:note",[86,327,322],{"__ignoreMap":134},[40,329,331],{"id":330},"配置-blog-v3","配置 blog-v3",[14,333,334],{},"blog-v3 本身是 Nuxt 项目。迁移文章之后，重点检查站点信息、导航、评论、站点地图、RSS 和代码高亮配置。",[172,336,338],{"title":337},"示例配置片段",[176,339,346],{"className":340,"code":342,"filename":343,"language":344,"meta":345},[341],"language-ts","export default {\n  site: {\n    name: '你的博客名',\n    url: 'https:\u002F\u002Fyour-domain.example',\n    description: '这里写博客描述'\n  },\n  author: {\n    name: '你的名字',\n    email: 'you@example.com'\n  }\n}\n","blog.config.ts","ts","icon=catppuccin:typescript",[86,347,342],{"__ignoreMap":134},[14,349,350],{},"本地检查时，我习惯先跑一遍安装和构建。",[176,352,357],{"className":353,"code":354,"filename":355,"language":182,"meta":356},[179],"pnpm i\npnpm init-project\npnpm generate\n","local-check.sh","icon=tabler:terminal-2",[86,358,354],{"__ignoreMap":134},[14,360,361,362,366,367,370],{},"写文章时常用的快捷键还是那几个：:key{code=\"Control\" icon} + ",[363,364],"key",{"code":365},"S"," 保存，:key{code=\"Control\" icon} + ",[363,368],{"code":369},"K"," 搜索文件，构建失败就先看终端输出。",[40,372,374],{"id":373},"部署到-vercel","部署到 Vercel",[14,376,377],{},"Vercel 部署这一步比较直接：",[379,380,381,384,387,390,393,396],"ol",{},[53,382,383],{},"把 blog-v3 项目推送到 GitHub。",[53,385,386],{},"在 Vercel 导入这个仓库。",[53,388,389],{},"Framework Preset 选择 Nuxt。",[53,391,392],{},"Build Command 使用项目默认构建命令。",[53,394,395],{},"确认 Node.js 版本和环境变量。",[53,397,398],{},"构建通过后绑定域名。",[176,400,405],{"className":401,"code":402,"filename":403,"language":182,"meta":404},[179],"git add .\ngit commit -m \"migrate blog from typecho to blog-v3\"\ngit push origin main\n","deploy-flow.sh","icon=tabler:brand-github",[86,406,402],{"__ignoreMap":134},[127,408,409,414],{"type":129,":card":130},[132,410,411],{"v-slot:title":134},[14,412,413],{},"先部署预览站，再切正式域名",[14,415,416],{},"不要一开始就把旧域名解析到新站。先用 Vercel 的预览域名检查文章、图片、RSS、站点地图和移动端样式，确认没问题后再修改 DNS。",[69,418,420],{"tip":419},"Vercel 的构建日志通常能直接定位依赖、Node 版本或环境变量问题。","部署失败先看 Build Logs",[172,422,424],{"title":423},"Vercel 检查项",[50,425,426,429,432,435,438,444,447,450],{},[53,427,428],{},"构建命令是否正确。",[53,430,431],{},"Node.js 版本是否与本地一致。",[53,433,434],{},"环境变量是否配置完整。",[53,436,437],{},"RSS 是否能访问。",[53,439,440,443],{},[86,441,442],{"code":442},"sitemap.xml"," 是否能访问。",[53,445,446],{},"文章详情页刷新是否正常。",[53,448,449],{},"旧文章链接是否需要 301 跳转。",[53,451,452],{},"图片是否存在跨域、404 或防盗链问题。",[40,454,455],{"id":455},"评论系统怎么处理",[14,457,458],{},"Typecho 的评论在数据库里，静态博客没有内置数据库，所以评论迁移要单独考虑。",[14,460,461],{},"我没有把评论迁移当成第一优先级。原因很简单：文章内容、链接和图片才是博客迁移的主体。评论可以后处理，甚至可以只保留旧站备份，不导入新系统。",[14,463,464],{},"可选方案大概有三种：",[146,466,468,473,478],{":tabs":467},"[\"不迁移\",\"静态归档\",\"迁移到新评论系统\"]",[132,469,470],{"v-slot:tab1":134},[14,471,472],{},"最简单。保留数据库备份，不在新站展示旧评论。适合评论不多，或者评论时效性较强的博客。",[132,474,475],{"v-slot:tab2":134},[14,476,477],{},"把旧评论导出成静态内容，放在文章末尾或单独页面里。优点是可长期保存，缺点是不会再参与互动。",[132,479,480],{"v-slot:tab3":134},[14,481,482],{},"迁移到 Twikoo、Waline 或其他评论系统。优点是保留互动，缺点是需要写转换脚本，并处理用户信息、时间格式和嵌套回复。",[40,484,486],{"id":485},"永久链接和-seo","永久链接和 SEO",[14,488,489],{},"如果旧 Typecho 的 URL 已经被搜索引擎收录，迁移时要特别小心。最理想的情况是新站保持旧路径不变；如果做不到，就配置跳转。",[127,491,493,498],{"type":492,":flat":130},"error",[132,494,495],{"v-slot:title":134},[14,496,497],{},"不要让旧文章大面积 404",[14,499,500],{},"404 会影响访问体验，也会让搜索引擎重新评估页面。迁移后第一周要重点看访问日志、搜索控制台和 Vercel Analytics。",[14,502,503,504,507],{},"Vercel 可以通过 ",[86,505,506],{"code":506},"vercel.json"," 配置重定向。具体规则要看旧站路径，这里只放一个示例。",[176,509,515],{"className":510,"code":512,"filename":506,"language":513,"meta":514},[511],"language-json","{\n  \"redirects\": [\n    {\n      \"source\": \"\u002Farchives\u002F:slug\",\n      \"destination\": \"\u002Fposts\u002F:slug\",\n      \"permanent\": true\n    }\n  ]\n}\n","json","icon=tabler:brand-vercel",[86,516,512],{"__ignoreMap":134},[40,518,519],{"id":519},"我的迁移检查清单",[172,521,522],{"title":519,":open":130},[50,523,526,536,545,551,557,563,569,579,585,591],{"className":524},[525],"contains-task-list",[53,527,530,535],{"className":528},[529],"task-list-item",[531,532],"input",{"disabled":533,"type":534},true,"checkbox"," Typecho 数据库已完整备份。",[53,537,539,541,542,544],{"className":538},[529],[531,540],{"disabled":533,"type":534}," ",[86,543,88],{"code":88}," 附件目录已完整备份。",[53,546,548,550],{"className":547},[529],[531,549],{"disabled":533,"type":534}," 文章标题、日期、slug、标签、分类已导出。",[53,552,554,556],{"className":553},[529],[531,555],{"disabled":533,"type":534}," Markdown front matter 能被 blog-v3 正确解析。",[53,558,560,562],{"className":559},[529],[531,561],{"disabled":533,"type":534}," 图片路径已统一处理。",[53,564,566,568],{"className":565},[529],[531,567],{"disabled":533,"type":534}," 旧站内链已替换或配置跳转。",[53,570,572,574,575,578],{"className":571},[529],[531,573],{"disabled":533,"type":534}," 本地 ",[86,576,577],{"code":577},"npm run build"," 通过。",[53,580,582,584],{"className":581},[529],[531,583],{"disabled":533,"type":534}," Vercel Preview 部署通过。",[53,586,588,590],{"className":587},[529],[531,589],{"disabled":533,"type":534}," RSS 和站点地图正常。",[53,592,594,596],{"className":593},[529],[531,595],{"disabled":533,"type":534}," 正式域名切换前已检查主要文章。",[40,598,599],{"id":599},"迁移后的感受",[10,601,603],{"icon":602},"tabler:message-2",[14,604,605],{},"Typecho 更像一个可靠的写作后台，blog-v3 更像一套把内容纳入版本管理的发布系统。",[14,607,608],{},"迁移之后，写作流程变得更“工程化”：新建 Markdown、写 front matter、提交 Git、等待 Vercel 构建。它不一定适合所有人，但很适合希望长期掌控内容、减少服务器维护、让博客更容易迁移和回滚的人。",[14,610,611],{},"最后留下一个经验：迁移博客不要追求一次性完美。先让文章、图片、链接和部署跑通，再慢慢处理评论、样式、历史短代码和旧文章修订。静态博客最大的好处，就是每一次调整都能被 Git 记录下来，也都能随时回退。",{"title":134,"searchDepth":613,"depth":613,"links":614},4,[615,617,618,619,620,621,622,623,624,625,626,627],{"id":42,"depth":616,"text":42},2,{"id":75,"depth":616,"text":75},{"id":143,"depth":616,"text":144},{"id":167,"depth":616,"text":167},{"id":195,"depth":616,"text":195},{"id":242,"depth":616,"text":242},{"id":330,"depth":616,"text":331},{"id":373,"depth":616,"text":374},{"id":455,"depth":616,"text":455},{"id":485,"depth":616,"text":486},{"id":519,"depth":616,"text":519},{"id":599,"depth":616,"text":599},[629],"技术","2026-05-04","记录一次从 Typecho 迁移到 blog-v3，并部署到 Vercel 的过程。",false,null,{"aside":635,"slots":637},[636],"toc",{},"\u002F2026\u002Ftypechotoblog-v3",{"text":640,"minutes":641,"time":642,"words":643},"12 min read",11.545,692700,2309,{"title":5,"description":631},{"loc":638},"posts\u002F2026\u002Ftypechotoblog-v3",[648,26,649,32,650],"Typecho","Nuxt","静态博客","tech","gedDnLzfpYRYL298hd8GYZZokjvMXE6Q-UJTWlgdlC8",[654,633],{"title":655,"path":656,"stem":657,"date":658,"type":651,"children":-1},"组件样式示例","\u002F2026\u002Fexample","posts\u002F2026\u002Fexample","2024-09-21 23:18:18",1777875334863]