[{"data":1,"prerenderedAt":434},["ShallowReactive",2],{"\u002F2026\u002F10005-blog-giscus-comment":3,"surround-\u002F2026\u002F10005-blog-giscus-comment":428},{"id":4,"title":5,"body":6,"categories":394,"date":396,"description":397,"draft":398,"extension":399,"hidden":398,"image":400,"meta":401,"navigation":403,"path":404,"permalink":405,"published":405,"readingTime":406,"recommend":411,"references":412,"seo":418,"sitemap":419,"stem":420,"tags":421,"type":426,"updated":396,"__hash__":427},"content\u002Fposts\u002F2026\u002F10005-blog-giscus-comment.md","静态博客零后端评论方案:从 Twikoo 迁移到 Giscus 全记录",{"type":7,"value":8,"toc":382},"minimark",[9,13,25,51,60,73,76,101,105,113,214,221,243,247,254,264,268,279,287,290,326,330,333,341,348,351,358,363,366,373,376],[10,11,12],"h3",{"id":12},"前言",[14,15,16,17,24],"p",{},"博客之前的评论系统是 ",[18,19,23],"a",{"href":20,"rel":21},"https:\u002F\u002Ftwikoo.js.org\u002F",[22],"nofollow","Twikoo",",自部署在 HuggingFace Space 上。用了一段时间,痛点越来越明显:",[26,27,28,39,45],"ul",{},[29,30,31,35,38],"li",{},[32,33,34],"strong",{},"要维护一个活着的服务",[36,37],"space",{}," 休眠后第一位评论的访客要等冷启动,体验全看运气",[29,40,41,44],{},[32,42,43],{},"架构上不匹配",":博客是纯静态站点(Cloudflare Pages),评论区却拖着一个外部后端",[29,46,47,50],{},[32,48,49],{},"数据在别处",":评论存在第三方平台上,迁移备份都不顺手",[14,52,53,54,59],{},"直到重新评估 ",[18,55,58],{"href":56,"rel":57},"https:\u002F\u002Fgiscus.app\u002Fzh-CN",[22],"Giscus",",才发现它和静态博客简直是绝配:",[61,62,66],"alert",{"title":63,"type":64,":card":65},"Giscus 的核心思路","tip","true",[14,67,68,69,72],{},"评论直接存进",[32,70,71],{},"博客源码仓库的 GitHub Discussions","。不需要数据库、不需要服务端 API、不需要任何环境变量——静态部署的博客天然满足全部条件。",[10,74,75],{"id":75},"接入前的三个前提",[77,78,79,85,98],"ol",{},[29,80,81,84],{},[32,82,83],{},"仓库必须公开",",并且开启 Discussions(仓库 Settings → Features → Discussions)",[29,86,87,88,93,94,97],{},"为仓库安装 ",[18,89,92],{"href":90,"rel":91},"https:\u002F\u002Fgithub.com\u002Fapps\u002Fgiscus",[22],"Giscus GitHub App",",",[32,95,96],{},"只授权需要接收评论的仓库",",别图省事给全部仓库",[29,99,100],{},"访客需要登录 GitHub 才能评论——这是门槛也是过滤,技术博客的读者基本都有账号",[10,102,104],{"id":103},"第一步在-giscusapp-生成配置","第一步:在 giscus.app 生成配置",[14,106,107,108,112],{},"打开 ",[18,109,111],{"href":56,"rel":110},[22],"giscus.app\u002Fzh-CN",",填入仓库名,页面会实时校验是否满足前提。我的选择:",[114,115,116,132],"table",{},[117,118,119],"thead",{},[120,121,122,126,129],"tr",{},[123,124,125],"th",{},"配置项",[123,127,128],{},"值",[123,130,131],{},"理由",[133,134,135,151,164,175,188,201],"tbody",{},[120,136,137,141,148],{},[138,139,140],"td",{},"映射方式",[138,142,143,147],{},[144,145,146],"code",{"code":146},"pathname"," + 严格映射",[138,149,150],{},"每篇文章路径对应一个 Discussion,干净直观",[120,152,153,156,161],{},[138,154,155],{},"Discussion 分类",[138,157,158],{},[144,159,160],{"code":160},"Announcements",[138,162,163],{},"该分类只有仓库维护者能开新帖,防止 Discussion 区被灌水",[120,165,166,169,172],{},[138,167,168],{},"反应",[138,170,171],{},"开启",[138,173,174],{},"不登录也能点个表情,降低互动门槛",[120,176,177,180,185],{},[138,178,179],{},"输入框位置",[138,181,182],{},[144,183,184],{"code":184},"bottom",[138,186,187],{},"先读评论再写评论",[120,189,190,193,198],{},[138,191,192],{},"主题",[138,194,195],{},[144,196,197],{"code":197},"light",[138,199,200],{},"博客已固定亮色主题",[120,202,203,206,211],{},[138,204,205],{},"语言",[138,207,208],{},[144,209,210],{"code":210},"zh-CN",[138,212,213],{},"—",[14,215,216,217,220],{},"填完后页面底部会生成一段 ",[144,218,219],{"code":219},"\u003Cscript>"," 配置,关键是里面这两个 ID:",[61,222,225],{"title":223,"type":224},"repoId \u002F categoryId 不是凭据","info",[14,226,227,230,231,234,235,238,239,242],{},[144,228,229],{"code":229},"repoId"," 和 ",[144,232,233],{"code":233},"categoryId"," 是 GitHub 的",[32,236,237],{},"公开标识符",",出现在前端产物里没有任何问题。但",[32,240,241],{},"千万不要","把 GitHub Personal Access Token 之类的凭据写进配置——Giscus 根本不需要它。",[10,244,246],{"id":245},"第二步写进-blogconfigts","第二步:写进 blog.config.ts",[14,248,249,250,253],{},"把配置收敛到 ",[144,251,252],{"code":252},"blog.config.ts",",统一管理:",[255,256,262],"pre",{"className":257,"code":259,"language":260,"meta":261},[258],"language-ts","\u002F** Giscus 评论配置;所有字段均为公开前端配置 *\u002F\ngiscus: {\n\tcategory: 'Announcements',\n\tcategoryId: 'DIC_kwDOSLLDgs4DCd0M',\n\tinputPosition: 'bottom',\n\tlang: 'zh-CN',\n\tmapping: 'pathname',\n\treactionsEnabled: '1',\n\trepo: 'Sakimu99\u002Fblog-v3',\n\trepoId: 'R_kgDOSLLDgg',\n\tstrict: '1',\n\ttheme: 'light',\n},\n","ts","",[144,263,259],{"__ignoreMap":261},[10,265,267],{"id":266},"第三步重写评论组件","第三步:重写评论组件",[14,269,270,271,274,275,278],{},"原来的 ",[144,272,273],{"code":273},"Comment.vue"," 有 250 多行(Twikoo 初始化 + 链接守卫 + 一大坨样式覆盖),换成 Giscus 后核心逻辑只有一件事:",[32,276,277],{},"在客户端动态注入 script","。",[255,280,285],{"className":281,"code":283,"language":284,"meta":261},[282],"language-vue","\u003Cscript setup lang=\"ts\">\nconst appConfig = useAppConfig()\nconst commentEl = useTemplateRef\u003CHTMLDivElement>('comment')\n\nonMounted(() => {\n\tif (!commentEl.value)\n\t\treturn\n\n\t\u002F\u002F Giscus 会根据页面路径加载或创建对应的 GitHub Discussion\n\tconst { giscus } = appConfig\n\tconst script = document.createElement('script')\n\n\t\u002F\u002F 仅在客户端动态注入,保持 SSG 产物不依赖评论后端\n\tscript.src = 'https:\u002F\u002Fgiscus.app\u002Fclient.js'\n\tscript.crossOrigin = 'anonymous'\n\tscript.async = true\n\n\t\u002F\u002F repoId 与 categoryId 是公开标识,不包含 GitHub Token 等敏感信息\n\tObject.entries({\n\t\tcategory: giscus.category,\n\t\tcategoryId: giscus.categoryId,\n\t\t\u002F\u002F ...其余配置项\n\t}).forEach(([key, value]) => script.dataset[key] = value)\n\n\t\u002F\u002F 清空服务端占位文本,并防止客户端重复挂载 iframe\n\tcommentEl.value.replaceChildren(script)\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n\u003Csection id=\"comments\" class=\"z-comment\">\n\t\u003Ch3 class=\"text-creative\">评论区\u003C\u002Fh3>\n\t\u003Cdiv ref=\"comment\" class=\"giscus\">\n\t\t\u003Cp>评论加载中...\u003C\u002Fp>\n\t\u003C\u002Fdiv>\n\u003C\u002Fsection>\n\u003C\u002Ftemplate>\n","vue",[144,286,283],{"__ignoreMap":261},[14,288,289],{},"几个值得说的细节:",[26,291,292,308,317],{},[29,293,294,299,300,303,304,307],{},[32,295,296,297],{},"为什么动态注入而不是直接写 ",[144,298,219],{"code":219},":博客是 ",[144,301,302],{"code":302},"nuxt generate"," 的纯静态产物,构建期不应该依赖评论服务;",[144,305,306],{"code":306},"onMounted"," 里注入保证只在浏览器端执行",[29,309,310,316],{},[32,311,312,315],{},[144,313,314],{"code":314},"replaceChildren(script)"," 的妙用",":一行代码同时完成\"清空 SSR 占位文本\"和\"防止客户端重复挂载 iframe\"",[29,318,319,322,325],{},[32,320,321],{},"组件从 250 行瘦到 60 行",[323,324],"twikoo",{}," 时代的链接守卫弹窗、样式深覆盖全部删掉,Giscus 的 iframe 样式本来就够用",[10,327,329],{"id":328},"第四步清理-twikoo-痕迹","第四步:清理 Twikoo 痕迹",[14,331,332],{},"换评论系统最容易留尾巴,我清了这四处:",[255,334,339],{"className":335,"code":337,"language":338,"meta":261},[336],"language-text","blog.config.ts   → 移除 twikoo.min.js 脚本引用和 twikoo 配置块\napp\u002Ftypes\u002F       → 删除 Window.twikoo 的全局类型声明\nnuxt.config.ts   → 移除 twikoo 域名的 preconnect\nToc.vue          → 目录锚点从 #twikoo 改成 #comments\n","text",[144,340,337],{"__ignoreMap":261},[61,342,345],{"title":343,"type":344},"历史评论不会自动迁移","warning",[14,346,347],{},"Twikoo 里的旧评论存在原服务里,切换到 Giscus 后不会显示。我的博客评论量不大,直接放弃了迁移;如果你的历史评论很珍贵,需要先研究 Twikoo 导出 → Discussions 的映射方案。",[10,349,350],{"id":350},"效果",[14,352,353,354,357],{},"本地 ",[144,355,356],{"code":356},"pnpm dev"," 跑起来,文章底部已经是熟悉的 GitHub Discussions 画风:",[359,360],"pic",{"caption":361,"src":362},"接入后的评论区,未登录状态显示\"使用 GitHub 登录\"","assets\u002Fblog_image\u002F10005-01.png",[10,364,365],{"id":365},"结语",[14,367,368,369,372],{},"这次迁移最爽的点在于",[32,370,371],{},"架构自洽",":博客内容是 Git 仓库里的 Markdown,评论是同一个仓库里的 Discussions,静态托管到哪里,评论系统就跟到哪里,没有任何外部状态需要操心。",[14,374,375],{},"如果你的博客也是静态托管 + GitHub 托管源码,Giscus 基本是评论系统的标准答案;唯一要掂量的,就是读者必须有 GitHub 账号这件事。",[377,378],"link-card",{"description":379,"icon":380,"link":56,"title":381},"在线生成配置,支持多种映射方式和主题","https:\u002F\u002Fgiscus.app\u002Ffavicon.ico","Giscus 官网",{"title":261,"searchDepth":383,"depth":383,"links":384},4,[385,387,388,389,390,391,392,393],{"id":12,"depth":386,"text":12},3,{"id":75,"depth":386,"text":75},{"id":103,"depth":386,"text":104},{"id":245,"depth":386,"text":246},{"id":266,"depth":386,"text":267},{"id":328,"depth":386,"text":329},{"id":350,"depth":386,"text":350},{"id":365,"depth":386,"text":365},[395],"开发","2026-08-02 02:30:00","自建 Twikoo 要维护服务、还会休眠,静态博客能不能拥有\"零后端\"评论区?答案是 Giscus——把评论存进 GitHub Discussions。记录 blog-v3 的完整接入过程。",false,"md","assets\u002Fcover\u002Fcover-giscus-comment.png",{"slots":402},{},true,"\u002F2026\u002F10005-blog-giscus-comment",null,{"text":407,"minutes":408,"time":409,"words":410},"6 min read",5.71,342600,1142,50,[413,415],{"title":414,"link":56},"Giscus 官网(配置生成器)",{"title":416,"link":417},"giscus 组件源码","https:\u002F\u002Fgithub.com\u002Fgiscus\u002Fgiscus-component",{"title":5,"description":397},{"loc":404},"posts\u002F2026\u002F10005-blog-giscus-comment",[58,422,423,424,425],"Nuxt","博客","评论系统","GitHub","tech","TUQ79x7XfaroAm2puUuRztXvSUcZF0_qBiVi-J0Nj3U",[429,405],{"title":430,"path":431,"stem":432,"date":433,"type":426,"children":-1},"把微信变成家庭运维入口:树莓派部署 Hermes 微信机器人全记录","\u002F2026\u002F10004-weixin-hermes-bot","posts\u002F2026\u002F10004-weixin-hermes-bot","2026-08-02 01:40:00",1786956885700]