[{"data":1,"prerenderedAt":720},["ShallowReactive",2],{"chapter-post-project-replication-guide-06-decap-cms-and-oauth-worker":3},{"chapter":4,"entry":73,"prev":391,"next":528},{"id":5,"title":6,"body":7,"category":55,"cover":52,"date":56,"description":57,"draft":58,"extension":59,"lang":60,"meta":61,"navigation":62,"path":63,"seo":64,"slug":65,"stem":66,"tags":67,"toc":62,"updated":56,"__hash__":72},"chapters/chapters/project-replication-guide.md","零基础完整复刻：Cloudflare 博客项目全流程",{"type":8,"value":9,"toc":51},"minimark",[10,14,17,30,33,45,48],[11,12,13],"p",{},"这个章节是你当前博客项目的“完整复刻手册”。",[11,15,16],{},"目标读者：",[18,19,20,24,27],"ul",{},[21,22,23],"li",{},"没有代码基础",[21,25,26],{},"第一次接触 GitHub、Cloudflare、Nuxt、Decap CMS",[21,28,29],{},"希望照着文档一步步做，最终得到与你当前项目一致的结果",[11,31,32],{},"学习方式建议：",[34,35,36,39,42],"ol",{},[21,37,38],{},"严格按顺序学习，不要跳步骤",[21,40,41],{},"每做完一节就执行“本节验收”",[21,43,44],{},"发现报错先看“常见问题”再继续",[11,46,47],{},"你可以直接从下面目录开始：",[49,50],"chapter-children",{},{"title":52,"searchDepth":53,"depth":53,"links":54},"",2,[],"Chapter","2026-02-14","面向零基础读者的完整项目复刻章节：从准备账号、搭建 Nuxt，到 Pages、Tunnel、CMS、评论、夜间模式与排障。",false,"md","zh-CN",{},true,"/chapters/project-replication-guide",{"title":6,"description":57},"project-replication-guide","chapters/project-replication-guide",[68,69,70,71],"复刻教程","Cloudflare","Nuxt","零基础","T31gU2a4Q3CvJ3Z2B2jyDvX4BtLMmICHnwzpIIudkao",{"id":74,"title":75,"body":76,"category":378,"chapterSlug":65,"cover":52,"date":56,"description":379,"draft":58,"extension":59,"lang":60,"legacySlugs":380,"meta":381,"navigation":62,"order":191,"path":382,"seo":383,"slug":384,"stem":385,"tags":386,"toc":62,"updated":56,"__hash__":390},"chapterPosts/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker.md","第 6 节：Decap CMS 与 GitHub OAuth Worker",{"type":8,"value":77,"toc":370},[78,83,91,94,111,114,118,123,200,204,210,227,230,268,279,283,289,303,306,310,342,345,349,366],[79,80,82],"h2",{"id":81},"_61-为什么要单独部署-oauth-worker","6.1 为什么要单独部署 OAuth Worker",[11,84,85,86,90],{},"你遇到过默认 Netlify OAuth 回调不可用问题（",[87,88,89],"code",{},"Not Found","）。",[11,92,93],{},"因此项目采用自建方案：",[18,95,96,102],{},[21,97,98,101],{},[87,99,100],{},"ops/decap-oauth/worker.js"," 处理 GitHub OAuth",[21,103,104,107,108],{},[87,105,106],{},"public/admin/config.yml"," 指向你自己的 ",[87,109,110],{},"base_url",[11,112,113],{},"这让登录链路完全可控。",[79,115,117],{"id":116},"_62-cms-配置必须与项目一致","6.2 CMS 配置（必须与项目一致）",[11,119,120,122],{},[87,121,106],{}," 核心段：",[124,125,129],"pre",{"className":126,"code":127,"language":128,"meta":52,"style":52},"language-yaml shiki shiki-themes github-light github-dark","backend:\n  name: github\n  repo: adkeb/blog\n  branch: main\n  base_url: https://decap-github-oauth.xuyang020128.workers.dev\n  auth_endpoint: auth\n","yaml",[87,130,131,144,156,167,178,189],{"__ignoreMap":52},[132,133,136,140],"span",{"class":134,"line":135},"line",1,[132,137,139],{"class":138},"s9eBZ","backend",[132,141,143],{"class":142},"sVt8B",":\n",[132,145,146,149,152],{"class":134,"line":53},[132,147,148],{"class":138},"  name",[132,150,151],{"class":142},": ",[132,153,155],{"class":154},"sZZnC","github\n",[132,157,159,162,164],{"class":134,"line":158},3,[132,160,161],{"class":138},"  repo",[132,163,151],{"class":142},[132,165,166],{"class":154},"adkeb/blog\n",[132,168,170,173,175],{"class":134,"line":169},4,[132,171,172],{"class":138},"  branch",[132,174,151],{"class":142},[132,176,177],{"class":154},"main\n",[132,179,181,184,186],{"class":134,"line":180},5,[132,182,183],{"class":138},"  base_url",[132,185,151],{"class":142},[132,187,188],{"class":154},"https://decap-github-oauth.xuyang020128.workers.dev\n",[132,190,192,195,197],{"class":134,"line":191},6,[132,193,194],{"class":138},"  auth_endpoint",[132,196,151],{"class":142},[132,198,199],{"class":154},"auth\n",[79,201,203],{"id":202},"_63-worker-环境变量与密钥","6.3 Worker 环境变量与密钥",[11,205,206,209],{},[87,207,208],{},"ops/decap-oauth/wrangler.toml"," 里是公开配置：",[18,211,212,217,222],{},[21,213,214],{},[87,215,216],{},"CMS_ORIGIN",[21,218,219],{},[87,220,221],{},"GITHUB_REDIRECT_URI",[21,223,224],{},[87,225,226],{},"GITHUB_CLIENT_ID",[11,228,229],{},"密钥必须用 secret：",[124,231,235],{"className":232,"code":233,"language":234,"meta":52,"style":52},"language-bash shiki shiki-themes github-light github-dark","npx wrangler secret put GITHUB_CLIENT_SECRET\nnpx wrangler secret put OAUTH_STATE_SECRET\n","bash",[87,236,237,255],{"__ignoreMap":52},[132,238,239,243,246,249,252],{"class":134,"line":135},[132,240,242],{"class":241},"sScJk","npx",[132,244,245],{"class":154}," wrangler",[132,247,248],{"class":154}," secret",[132,250,251],{"class":154}," put",[132,253,254],{"class":154}," GITHUB_CLIENT_SECRET\n",[132,256,257,259,261,263,265],{"class":134,"line":53},[132,258,242],{"class":241},[132,260,245],{"class":154},[132,262,248],{"class":154},[132,264,251],{"class":154},[132,266,267],{"class":154}," OAUTH_STATE_SECRET\n",[11,269,270,274,275,278],{},[271,272,273],"strong",{},"注意","：",[87,276,277],{},"GITHUB_CLIENT_SECRET"," 绝对不能写入 git。",[79,280,282],{"id":281},"_64-worker-路由逻辑读懂就够不用会写","6.4 Worker 路由逻辑（读懂就够，不用会写）",[11,284,285,288],{},[87,286,287],{},"worker.js"," 做两件事：",[34,290,291,297],{},[21,292,293,296],{},[87,294,295],{},"/auth","：发起 GitHub 授权",[21,298,299,302],{},[87,300,301],{},"/callback","：换 token 并回传给 Decap 窗口",[11,304,305],{},"你项目中还做了弹窗握手与 postMessage 回传，解决了“登录成功但 CMS 不更新”的常见问题。",[79,307,309],{"id":308},"_65-部署命令完整","6.5 部署命令（完整）",[124,311,313],{"className":232,"code":312,"language":234,"meta":52,"style":52},"cd ops/decap-oauth\nnpx wrangler whoami\nnpx wrangler deploy\n",[87,314,315,324,333],{"__ignoreMap":52},[132,316,317,321],{"class":134,"line":135},[132,318,320],{"class":319},"sj4cs","cd",[132,322,323],{"class":154}," ops/decap-oauth\n",[132,325,326,328,330],{"class":134,"line":53},[132,327,242],{"class":241},[132,329,245],{"class":154},[132,331,332],{"class":154}," whoami\n",[132,334,335,337,339],{"class":134,"line":158},[132,336,242],{"class":241},[132,338,245],{"class":154},[132,340,341],{"class":154}," deploy\n",[11,343,344],{},"部署成功会返回你的 workers.dev 地址。",[79,346,348],{"id":347},"_66-验收标准","6.6 验收标准",[34,350,351,357,360,363],{},[21,352,353,354],{},"打开 ",[87,355,356],{},"https://www.xuyangfly.site/admin",[21,358,359],{},"点“使用 GitHub 登录”",[21,361,362],{},"授权后可进入 CMS 内容列表",[21,364,365],{},"新建文章后能触发 Git 提交",[367,368,369],"style",{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":52,"searchDepth":53,"depth":53,"links":371},[372,373,374,375,376,377],{"id":81,"depth":53,"text":82},{"id":116,"depth":53,"text":117},{"id":202,"depth":53,"text":203},{"id":281,"depth":53,"text":282},{"id":308,"depth":53,"text":309},{"id":347,"depth":53,"text":348},"Guide","从 Netlify 失败场景迁移到 Cloudflare Worker OAuth 网关，打通 /admin 可视化编辑。",[],{},"/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",{"title":75,"description":379},"06-decap-cms-and-oauth-worker","chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",[68,387,388,389],"Decap CMS","OAuth","Worker","CftJ87f8FswywDArDHUTg3sgFZwMb6KyNdd-iw7FgN8",{"id":392,"title":393,"body":394,"category":378,"chapterSlug":65,"cover":52,"date":56,"description":517,"draft":58,"extension":59,"lang":60,"legacySlugs":518,"meta":519,"navigation":62,"order":180,"path":520,"seo":521,"slug":522,"stem":523,"tags":524,"toc":62,"updated":56,"__hash__":527},"chapterPosts/chapter-posts/project-replication-guide/05-preview-tunnel-and-access.md","第 5 节：预览链路（Cloudflare Tunnel + Access）",{"type":8,"value":395,"toc":510},[396,400,403,422,426,429,443,446,450,453,456,464,468,471,474,485,489,492],[79,397,399],{"id":398},"_51-架构目标","5.1 架构目标",[11,401,402],{},"你要达到下面 2 条：",[34,404,405,412],{},[21,406,407,408,411],{},"主站永远公开可用（",[87,409,410],{},"www","）",[21,413,414,415,418,419,411],{},"预览与运维私有访问（",[87,416,417],{},"preview"," / ",[87,420,421],{},"ops",[79,423,425],{"id":424},"_52-草稿显示机制","5.2 草稿显示机制",[11,427,428],{},"通过变量控制：",[18,430,431,437],{},[21,432,433,434],{},"Production：",[87,435,436],{},"NUXT_PUBLIC_SHOW_DRAFTS=false",[21,438,439,440],{},"Preview：",[87,441,442],{},"NUXT_PUBLIC_SHOW_DRAFTS=true",[11,444,445],{},"这样同一套代码在不同环境会得到不同可见性。",[79,447,449],{"id":448},"_53-tunnel-的职责","5.3 Tunnel 的职责",[11,451,452],{},"Tunnel 不是托管主站内容，而是把本地预览服务安全暴露出去。",[11,454,455],{},"典型用途：",[18,457,458,461],{},[21,459,460],{},"草稿内容预览",[21,462,463],{},"私有后台入口",[79,465,467],{"id":466},"_54-access-的职责","5.4 Access 的职责",[11,469,470],{},"Access 是“谁能进来”的门禁系统。",[11,472,473],{},"你应配置：",[34,475,476,479,482],{},[21,477,478],{},"只允许你的邮箱登录",[21,480,481],{},"会话有效期缩短（例如 1~8 小时）",[21,483,484],{},"打开审计日志",[79,486,488],{"id":487},"_55-验收测试","5.5 验收测试",[11,490,491],{},"必须做这 3 条：",[34,493,494,500,507],{},[21,495,496,497,499],{},"关闭本地 Tunnel 后，",[87,498,410],{}," 仍能访问。",[21,501,502,503,506],{},"未授权访问 ",[87,504,505],{},"preview.*","，看到拦截页。",[21,508,509],{},"授权后能访问预览站，并看到草稿。",{"title":52,"searchDepth":53,"depth":53,"links":511},[512,513,514,515,516],{"id":398,"depth":53,"text":399},{"id":424,"depth":53,"text":425},{"id":448,"depth":53,"text":449},{"id":466,"depth":53,"text":467},{"id":487,"depth":53,"text":488},"把草稿预览和后台放到私有入口，确保 Tunnel 失效不影响公开主站。",[],{},"/chapter-posts/project-replication-guide/05-preview-tunnel-and-access",{"title":393,"description":517},"05-preview-tunnel-and-access","chapter-posts/project-replication-guide/05-preview-tunnel-and-access",[68,525,526],"Tunnel","Zero Trust","xw4xbvKHiLSWUi6NwiRDw5FtQ_GiERPmprH3_HLe6fU",{"id":529,"title":530,"body":531,"category":378,"chapterSlug":65,"cover":52,"date":56,"description":708,"draft":58,"extension":59,"lang":60,"legacySlugs":709,"meta":710,"navigation":62,"order":711,"path":712,"seo":713,"slug":714,"stem":715,"tags":716,"toc":62,"updated":56,"__hash__":719},"chapterPosts/chapter-posts/project-replication-guide/07-giscus-and-comment-fix.md","第 7 节：评论系统 giscus 与空白问题修复",{"type":8,"value":532,"toc":699},[533,537,540,562,569,573,576,584,590,593,601,605,608,619,627,681,685],[79,534,536],{"id":535},"_71-giscus-必备参数","7.1 giscus 必备参数",[11,538,539],{},"你需要从 giscus 配置页记录：",[34,541,542,547,552,557],{},[21,543,544],{},[87,545,546],{},"repo",[21,548,549],{},[87,550,551],{},"repoId",[21,553,554],{},[87,555,556],{},"category",[21,558,559],{},[87,560,561],{},"categoryId",[11,563,564,565,568],{},"你的当前值是基于仓库 ",[87,566,567],{},"adkeb/blog","。",[79,570,572],{"id":571},"_72-环境变量要在两个环境都填","7.2 环境变量要在两个环境都填",[11,574,575],{},"Cloudflare Pages 里：",[18,577,578,581],{},[21,579,580],{},"Production 环境变量",[21,582,583],{},"Preview 环境变量",[11,585,586,587,568],{},"都要填同样的 ",[87,588,589],{},"GISCUS_*",[11,591,592],{},"否则表现会是：",[18,594,595,598],{},[21,596,597],{},"线上能加载、预览不加载",[21,599,600],{},"或者反过来",[79,602,604],{"id":603},"_73-你遇到的评论空白问题","7.3 你遇到的评论空白问题",[11,606,607],{},"问题现象：",[34,609,610,613,616],{},[21,611,612],{},"登录 GitHub 回来后评论区空白",[21,614,615],{},"刷新当前页面后又空白",[21,617,618],{},"需要手动关弹窗/重进才恢复",[620,621,623,624,411],"h3",{"id":622},"修复点componentsgiscuscommentsclientvue","修复点（",[87,625,626],{},"components/GiscusComments.client.vue",[34,628,629,644,655,670],{},[21,630,631,632,635,636,639],{},"监听 ",[87,633,634],{},"focus"," 和 ",[87,637,638],{},"visibilitychange",[18,640,641],{},[21,642,643],{},"从 GitHub 授权窗口返回时，自动重新挂载 giscus。",[21,645,646,647,650],{},"把加载策略改为 ",[87,648,649],{},"eager",[18,651,652],{},[21,653,654],{},"避免懒加载时机导致 iframe 空白。",[21,656,657,658,661,662,665],{},"路由监听从 ",[87,659,660],{},"fullPath"," 收敛到 ",[87,663,664],{},"path",[18,666,667],{},[21,668,669],{},"减少不必要重挂载。",[21,671,672,673,676],{},"主题切换时向 iframe ",[87,674,675],{},"postMessage",[18,677,678],{},[21,679,680],{},"避免夜间模式切换导致评论状态不一致。",[79,682,684],{"id":683},"_74-验收步骤","7.4 验收步骤",[34,686,687,690,693,696],{},[21,688,689],{},"打开任意文章页，确认评论可见。",[21,691,692],{},"点击登录并完成 GitHub 授权。",[21,694,695],{},"回到页面后无需手动刷新即可评论。",[21,697,698],{},"手动刷新页面，评论区仍正常渲染。",{"title":52,"searchDepth":53,"depth":53,"links":700},[701,702,703,707],{"id":535,"depth":53,"text":536},{"id":571,"depth":53,"text":572},{"id":603,"depth":53,"text":604,"children":704},[705],{"id":622,"depth":158,"text":706},"修复点（components/GiscusComments.client.vue）",{"id":683,"depth":53,"text":684},"配置 giscus 参数、环境变量同步，并修复登录后评论空白、刷新后评论空白问题。",[],{},7,"/chapter-posts/project-replication-guide/07-giscus-and-comment-fix",{"title":530,"description":708},"07-giscus-and-comment-fix","chapter-posts/project-replication-guide/07-giscus-and-comment-fix",[68,717,718],"giscus","评论系统","Q3kyHNdaPbn0boCYo_SD58Gnw4JEPaGtjktQD-56xa8",1771232916066]