[{"data":1,"prerenderedAt":2169},["ShallowReactive",2],{"chapter-project-replication-guide":3,"chapter-children-project-replication-guide-false":72},{"id":4,"title":5,"body":6,"category":54,"cover":51,"date":55,"description":56,"draft":57,"extension":58,"lang":59,"meta":60,"navigation":61,"path":62,"seo":63,"slug":64,"stem":65,"tags":66,"toc":61,"updated":55,"__hash__":71},"chapters/chapters/project-replication-guide.md","零基础完整复刻：Cloudflare 博客项目全流程",{"type":7,"value":8,"toc":50},"minimark",[9,13,16,29,32,44,47],[10,11,12],"p",{},"这个章节是你当前博客项目的“完整复刻手册”。",[10,14,15],{},"目标读者：",[17,18,19,23,26],"ul",{},[20,21,22],"li",{},"没有代码基础",[20,24,25],{},"第一次接触 GitHub、Cloudflare、Nuxt、Decap CMS",[20,27,28],{},"希望照着文档一步步做，最终得到与你当前项目一致的结果",[10,30,31],{},"学习方式建议：",[33,34,35,38,41],"ol",{},[20,36,37],{},"严格按顺序学习，不要跳步骤",[20,39,40],{},"每做完一节就执行“本节验收”",[20,42,43],{},"发现报错先看“常见问题”再继续",[10,45,46],{},"你可以直接从下面目录开始：",[48,49],"chapter-children",{},{"title":51,"searchDepth":52,"depth":52,"links":53},"",2,[],"Chapter","2026-02-14","面向零基础读者的完整项目复刻章节：从准备账号、搭建 Nuxt，到 Pages、Tunnel、CMS、评论、夜间模式与排障。",false,"md","zh-CN",{},true,"/chapters/project-replication-guide",{"title":5,"description":56},"project-replication-guide","chapters/project-replication-guide",[67,68,69,70],"复刻教程","Cloudflare","Nuxt","零基础","T31gU2a4Q3CvJ3Z2B2jyDvX4BtLMmICHnwzpIIudkao",[73,357,744,964,1099,1234,1531,1718,1912],{"id":74,"title":75,"body":76,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":346,"draft":57,"extension":58,"lang":59,"legacySlugs":347,"meta":348,"navigation":61,"order":182,"path":349,"seo":350,"slug":351,"stem":352,"tags":353,"toc":61,"updated":55,"__hash__":356},"chapterPosts/chapter-posts/project-replication-guide/01-overview-and-accounts.md","第 1 节：先把地基打好（目标、账号、工具）",{"type":7,"value":77,"toc":329},[78,83,86,89,100,103,109,113,116,138,141,155,159,164,167,170,190,194,197,199,219,223,226,233,235,251,255,263,266,270,273,300,303,307,311,314,318,325],[79,80,82],"h2",{"id":81},"_11-这一整个项目到底在做什么","1.1 这一整个项目到底在做什么",[10,84,85],{},"你现在要复刻的是一个“静态主站 + 私有预览后台”的博客系统。",[10,87,88],{},"系统分工如下：",[33,90,91,94,97],{},[20,92,93],{},"公开站点：给所有访客看文章，要求稳定、快、便宜。",[20,95,96],{},"私有预览：只给你自己看草稿、后台编辑，要求安全。",[20,98,99],{},"内容管理：用可视化后台写文章，但底层仍是 Git 文件，方便版本管理和回滚。",[10,101,102],{},"一句话概括：",[104,105,106],"blockquote",{},[10,107,108],{},"主站要稳，后台要安全，内容要可追溯。",[79,110,112],{"id":111},"_12-你必须准备的账号","1.2 你必须准备的账号",[10,114,115],{},"按顺序准备下面 4 类账号：",[33,117,118,126,132,135],{},[20,119,120,121,125],{},"GitHub 账号（你已经在用：",[122,123,124],"code",{},"adkeb","）",[20,127,128,129,125],{},"Cloudflare 账号（你已绑定域名 ",[122,130,131],{},"xuyangfly.site",[20,133,134],{},"域名（并且 DNS 在 Cloudflare 管理）",[20,136,137],{},"giscus 所需 GitHub 仓库权限（评论功能）",[10,139,140],{},"为什么必须先准备账号：",[17,142,143,146,149,152],{},[20,144,145],{},"没有 GitHub：无法做代码仓库与自动部署",[20,147,148],{},"没有 Cloudflare：无法托管 Pages、Tunnel、Access",[20,150,151],{},"没有域名：无法做正式地址与 HTTPS",[20,153,154],{},"没有仓库权限：CMS/OAuth/评论全都做不通",[79,156,158],{"id":157},"_13-你必须安装的本地工具","1.3 你必须安装的本地工具",[160,161,163],"h3",{"id":162},"git","Git",[10,165,166],{},"作用：把代码提交到 GitHub。",[10,168,169],{},"检查命令：",[171,172,176],"pre",{"className":173,"code":174,"language":175,"meta":51,"style":51},"language-bash shiki shiki-themes github-light github-dark","git --version\n","bash",[122,177,178],{"__ignoreMap":51},[179,180,183,186],"span",{"class":181,"line":182},"line",1,[179,184,162],{"class":185},"sScJk",[179,187,189],{"class":188},"sj4cs"," --version\n",[160,191,193],{"id":192},"nodejs建议-20","Node.js（建议 20+）",[10,195,196],{},"作用：运行 Nuxt 项目、安装依赖。",[10,198,169],{},[171,200,202],{"className":173,"code":201,"language":175,"meta":51,"style":51},"node -v\nnpm -v\n",[122,203,204,212],{"__ignoreMap":51},[179,205,206,209],{"class":181,"line":182},[179,207,208],{"class":185},"node",[179,210,211],{"class":188}," -v\n",[179,213,214,217],{"class":181,"line":52},[179,215,216],{"class":185},"npm",[179,218,211],{"class":188},[160,220,222],{"id":221},"wranglercloudflare-cli","Wrangler（Cloudflare CLI）",[10,224,225],{},"作用：部署 Decap OAuth Worker。",[10,227,228,229,232],{},"你可以不全局安装，用 ",[122,230,231],{},"npx wrangler ..."," 临时调用。",[10,234,169],{},[171,236,238],{"className":173,"code":237,"language":175,"meta":51,"style":51},"npx wrangler --version\n",[122,239,240],{"__ignoreMap":51},[179,241,242,245,249],{"class":181,"line":182},[179,243,244],{"class":185},"npx",[179,246,248],{"class":247},"sZZnC"," wrangler",[179,250,189],{"class":188},[79,252,254],{"id":253},"_14-你的项目目录结构你将频繁看到","1.4 你的项目目录结构（你将频繁看到）",[171,256,261],{"className":257,"code":259,"language":260,"meta":51},[258],"language-text","content/\n  posts/                  # 普通文章\n  chapters/               # 章节父文\n  chapter-posts/          # 章节子文章\npublic/admin/config.yml   # Decap CMS 配置\nops/decap-oauth/worker.js # OAuth Worker\npages/                    # 前端路由页面\nserver/routes/            # RSS/Sitemap/Search API\nassets/css/main.css       # 全局样式（含夜间模式变量）\n","text",[122,262,259],{"__ignoreMap":51},[10,264,265],{},"你现在先不用死记，后面每节会反复用到。",[79,267,269],{"id":268},"_15-本节验收你必须确认","1.5 本节验收（你必须确认）",[10,271,272],{},"请逐项确认：",[33,274,275,278,285,295],{},[20,276,277],{},"你可以登录 GitHub 和 Cloudflare。",[20,279,280,281,284],{},"你能看到仓库 ",[122,282,283],{},"adkeb/blog","。",[20,286,287,288,291,292,284],{},"本地能执行 ",[122,289,290],{},"git --version","、",[122,293,294],{},"node -v",[20,296,287,297,284],{},[122,298,299],{},"npx wrangler --version",[10,301,302],{},"只要这 4 项都完成，你就具备继续复刻的基础条件。",[79,304,306],{"id":305},"_16-常见问题","1.6 常见问题",[160,308,310],{"id":309},"问我不会命令行能复刻吗","问：我不会命令行，能复刻吗？",[10,312,313],{},"可以。你只需要复制命令执行，不需要理解每个参数的全部细节。",[160,315,317],{"id":316},"问我用的是-conda-base-环境会冲突吗","问：我用的是 Conda base 环境，会冲突吗？",[10,319,320,321,324],{},"不会。你当前环境已经能跑 ",[122,322,323],{},"npx wrangler","，说明链路可用。",[326,327,328],"style",{},"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}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 .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":51,"searchDepth":52,"depth":52,"links":330},[331,332,333,339,340,341],{"id":81,"depth":52,"text":82},{"id":111,"depth":52,"text":112},{"id":157,"depth":52,"text":158,"children":334},[335,337,338],{"id":162,"depth":336,"text":163},3,{"id":192,"depth":336,"text":193},{"id":221,"depth":336,"text":222},{"id":253,"depth":52,"text":254},{"id":268,"depth":52,"text":269},{"id":305,"depth":52,"text":306,"children":342},[343,344],{"id":309,"depth":336,"text":310},{"id":316,"depth":336,"text":317},"Guide","你要先准备哪些账号和工具，为什么必须先做这一步，以及每个工具在项目里的职责。",[],{},"/chapter-posts/project-replication-guide/01-overview-and-accounts",{"title":75,"description":346},"01-overview-and-accounts","chapter-posts/project-replication-guide/01-overview-and-accounts",[67,354,355],"入门","准备工作","CfszBs4t3aWnlVWtnHvBt_fWCo-M-1dKC87r8KEAhh8",{"id":358,"title":359,"body":360,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":734,"draft":57,"extension":58,"lang":59,"legacySlugs":735,"meta":736,"navigation":61,"order":52,"path":737,"seo":738,"slug":739,"stem":740,"tags":741,"toc":61,"updated":55,"__hash__":743},"chapterPosts/chapter-posts/project-replication-guide/02-local-dev-and-nuxt-content.md","第 2 节：本地跑起来（Nuxt + Content + 环境变量）",{"type":7,"value":361,"toc":727},[362,366,369,402,408,411,422,426,432,514,517,537,540,554,558,564,567,606,609,617,620,624,630,650,657,660,677,681,684,707,710,724],[79,363,365],{"id":364},"_21-安装依赖并启动项目","2.1 安装依赖并启动项目",[10,367,368],{},"在项目根目录执行：",[171,370,372],{"className":173,"code":371,"language":175,"meta":51,"style":51},"npm install\ncp .env.example .env\nnpm run dev\n",[122,373,374,381,392],{"__ignoreMap":51},[179,375,376,378],{"class":181,"line":182},[179,377,216],{"class":185},[179,379,380],{"class":247}," install\n",[179,382,383,386,389],{"class":181,"line":52},[179,384,385],{"class":185},"cp",[179,387,388],{"class":247}," .env.example",[179,390,391],{"class":247}," .env\n",[179,393,394,396,399],{"class":181,"line":336},[179,395,216],{"class":185},[179,397,398],{"class":247}," run",[179,400,401],{"class":247}," dev\n",[10,403,404,405,284],{},"然后打开浏览器：",[122,406,407],{},"http://localhost:3000",[10,409,410],{},"这一步成功，代表：",[33,412,413,416,419],{},[20,414,415],{},"依赖安装正常",[20,417,418],{},"Nuxt 开发服务器可运行",[20,420,421],{},"项目基础代码可读",[79,423,425],{"id":424},"_22-先理解脚本你之后会一直用","2.2 先理解脚本（你之后会一直用）",[10,427,428,431],{},[122,429,430],{},"package.json"," 里的脚本：",[171,433,437],{"className":434,"code":435,"language":436,"meta":51,"style":51},"language-json shiki shiki-themes github-light github-dark","{\n  \"dev\": \"nuxt dev\",\n  \"build\": \"nuxt build\",\n  \"generate\": \"nuxt generate\",\n  \"preview\": \"nuxt preview\",\n  \"check\": \"nuxt typecheck\"\n}\n","json",[122,438,439,445,459,471,484,497,508],{"__ignoreMap":51},[179,440,441],{"class":181,"line":182},[179,442,444],{"class":443},"sVt8B","{\n",[179,446,447,450,453,456],{"class":181,"line":52},[179,448,449],{"class":188},"  \"dev\"",[179,451,452],{"class":443},": ",[179,454,455],{"class":247},"\"nuxt dev\"",[179,457,458],{"class":443},",\n",[179,460,461,464,466,469],{"class":181,"line":336},[179,462,463],{"class":188},"  \"build\"",[179,465,452],{"class":443},[179,467,468],{"class":247},"\"nuxt build\"",[179,470,458],{"class":443},[179,472,474,477,479,482],{"class":181,"line":473},4,[179,475,476],{"class":188},"  \"generate\"",[179,478,452],{"class":443},[179,480,481],{"class":247},"\"nuxt generate\"",[179,483,458],{"class":443},[179,485,487,490,492,495],{"class":181,"line":486},5,[179,488,489],{"class":188},"  \"preview\"",[179,491,452],{"class":443},[179,493,494],{"class":247},"\"nuxt preview\"",[179,496,458],{"class":443},[179,498,500,503,505],{"class":181,"line":499},6,[179,501,502],{"class":188},"  \"check\"",[179,504,452],{"class":443},[179,506,507],{"class":247},"\"nuxt typecheck\"\n",[179,509,511],{"class":181,"line":510},7,[179,512,513],{"class":443},"}\n",[10,515,516],{},"逐条解释：",[33,518,519,525,531],{},[20,520,521,524],{},[122,522,523],{},"dev","：本地开发，改代码会热更新。",[20,526,527,530],{},[122,528,529],{},"generate","：生成静态站（Cloudflare Pages 用这个）。",[20,532,533,536],{},[122,534,535],{},"check","：类型检查，防止明显代码错误。",[10,538,539],{},"你要形成习惯：",[17,541,542,548],{},[20,543,544,545],{},"每次关键改动后跑 ",[122,546,547],{},"npm run check",[20,549,550,551],{},"准备推送前跑 ",[122,552,553],{},"npm run generate",[79,555,557],{"id":556},"_23-环境变量为什么这么重要","2.3 环境变量为什么这么重要",[10,559,560,563],{},[122,561,562],{},".env"," 是项目行为总开关。",[10,565,566],{},"你项目中的关键变量：",[33,568,569,579,588,594,600],{},[20,570,571,574,575,578],{},[122,572,573],{},"SITE_URL"," / ",[122,576,577],{},"NUXT_PUBLIC_SITE_URL","：正式站地址",[20,580,581,574,584,587],{},[122,582,583],{},"PREVIEW_URL",[122,585,586],{},"NUXT_PUBLIC_PREVIEW_URL","：预览地址",[20,589,590,593],{},[122,591,592],{},"NUXT_PUBLIC_SHOW_DRAFTS","：是否显示草稿",[20,595,596,599],{},[122,597,598],{},"GISCUS_*","：评论系统配置",[20,601,602,605],{},[122,603,604],{},"CF_ACCESS_AUD","：Cloudflare Access 拓展鉴权字段",[10,607,608],{},"最常见错误：",[17,610,611,614],{},[20,612,613],{},"变量只填了 Production，没填 Preview",[20,615,616],{},"public 与非 public 混用，导致客户端拿不到值",[10,618,619],{},"你的项目已经采用“双写兼容”方式，降低此类风险。",[79,621,623],{"id":622},"_24-内容模型为什么你的文章能变成页面","2.4 内容模型：为什么你的文章能变成页面",[10,625,626,629],{},[122,627,628],{},"content.config.ts"," 定义了 3 套内容集合：",[33,631,632,638,644],{},[20,633,634,637],{},[122,635,636],{},"posts","：普通文章",[20,639,640,643],{},[122,641,642],{},"chapters","：章节父文",[20,645,646,649],{},[122,647,648],{},"chapterPosts","：章节子文章",[10,651,652,653,656],{},"系统会把 Markdown frontmatter 字段（例如 ",[122,654,655],{},"title/date/tags","）解析成可查询数据。",[10,658,659],{},"你看到的页面路由是：",[17,661,662,667,672],{},[20,663,664],{},[122,665,666],{},"/posts/:slug",[20,668,669],{},[122,670,671],{},"/chapters/:chapterSlug",[20,673,674],{},[122,675,676],{},"/chapters/:chapterSlug/:slug",[79,678,680],{"id":679},"_25-本节验收","2.5 本节验收",[10,682,683],{},"执行并确认：",[171,685,687],{"className":173,"code":686,"language":175,"meta":51,"style":51},"npm run check\nnpm run generate\n",[122,688,689,698],{"__ignoreMap":51},[179,690,691,693,695],{"class":181,"line":182},[179,692,216],{"class":185},[179,694,398],{"class":247},[179,696,697],{"class":247}," check\n",[179,699,700,702,704],{"class":181,"line":52},[179,701,216],{"class":185},[179,703,398],{"class":247},[179,705,706],{"class":247}," generate\n",[10,708,709],{},"验收标准：",[33,711,712,715,718],{},[20,713,714],{},"两条命令都通过",[20,716,717],{},"本地页面可正常打开",[20,719,720,721,723],{},"你能看懂 ",[122,722,562],{}," 每个字段大概作用",[326,725,726],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":51,"searchDepth":52,"depth":52,"links":728},[729,730,731,732,733],{"id":364,"depth":52,"text":365},{"id":424,"depth":52,"text":425},{"id":556,"depth":52,"text":557},{"id":622,"depth":52,"text":623},{"id":679,"depth":52,"text":680},"从零启动本地站点，理解 .env、内容模型、页面路由和构建脚本。",[],{},"/chapter-posts/project-replication-guide/02-local-dev-and-nuxt-content",{"title":359,"description":734},"02-local-dev-and-nuxt-content","chapter-posts/project-replication-guide/02-local-dev-and-nuxt-content",[67,69,742],"环境变量","gOmH9AS2UrLEZ73n0vFL9_RNxvaWrYWbSXr6PLbCQWI",{"id":745,"title":746,"body":747,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":953,"draft":57,"extension":58,"lang":59,"legacySlugs":954,"meta":955,"navigation":61,"order":336,"path":956,"seo":957,"slug":958,"stem":959,"tags":960,"toc":61,"updated":55,"__hash__":963},"chapterPosts/chapter-posts/project-replication-guide/03-github-and-cloudflare-pages.md","第 3 节：连接 GitHub 与 Cloudflare Pages（自动部署主链路）",{"type":7,"value":748,"toc":946},[749,753,758,761,775,778,784,787,791,794,819,823,826,845,848,857,869,873,876,882,885,894,897,905,909,915,929,932,943],[79,750,752],{"id":751},"_31-先确认代码已在-github","3.1 先确认代码已在 GitHub",[10,754,755,756,284],{},"你的目标仓库是：",[122,757,283],{},[10,759,760],{},"本地执行：",[171,762,764],{"className":173,"code":763,"language":175,"meta":51,"style":51},"git remote -v\n",[122,765,766],{"__ignoreMap":51},[179,767,768,770,773],{"class":181,"line":182},[179,769,162],{"class":185},[179,771,772],{"class":247}," remote",[179,774,211],{"class":188},[10,776,777],{},"应看到：",[171,779,782],{"className":780,"code":781,"language":260,"meta":51},[258],"origin git@github.com:adkeb/blog.git\n",[122,783,781],{"__ignoreMap":51},[10,785,786],{},"如果不是这个地址，先修正 remote 再继续。",[79,788,790],{"id":789},"_32-在-cloudflare-创建-pages-项目","3.2 在 Cloudflare 创建 Pages 项目",[10,792,793],{},"操作路径（新版控制台）：",[33,795,796,802,808,813],{},[20,797,798,799],{},"进入 ",[122,800,801],{},"Workers & Pages",[20,803,804,805],{},"选择 ",[122,806,807],{},"Import an existing Git repository",[20,809,810,811],{},"选择 GitHub 账号与仓库 ",[122,812,283],{},[20,814,815,816],{},"生产分支选 ",[122,817,818],{},"main",[79,820,822],{"id":821},"_33-构建参数必须这样填","3.3 构建参数必须这样填",[10,824,825],{},"这一项非常关键，填错就会失败：",[33,827,828,834,839],{},[20,829,830,831],{},"Framework preset：",[122,832,833],{},"Nuxt.js",[20,835,836,837],{},"Build command：",[122,838,553],{},[20,840,841,842],{},"Build output directory：",[122,843,844],{},"dist",[10,846,847],{},"你之前踩过的坑：",[17,849,850],{},[20,851,852,853,856],{},"填成 ",[122,854,855],{},".output/public","，会报 “build output directory not found”",[10,858,859,860,863,864,866,867,284],{},"原因：",[122,861,862],{},"nuxt generate"," 产物在 ",[122,865,844],{},"，而不是 ",[122,868,855],{},[79,870,872],{"id":871},"_34-你曾遇到的典型错误是怎么来的","3.4 你曾遇到的典型错误是怎么来的",[10,874,875],{},"报错：",[171,877,880],{"className":878,"code":879,"language":260,"meta":51},[258],"The name 'ASSETS' is reserved in Pages projects.\n",[122,881,879],{"__ignoreMap":51},[10,883,884],{},"本质原因：",[17,886,887],{},[20,888,889,890,893],{},"把 Worker 的 ",[122,891,892],{},"wrangler deploy"," 混进了 Pages 的构建流程",[10,895,896],{},"正确做法：",[33,898,899,902],{},[20,900,901],{},"Pages 只做站点构建与静态发布",[20,903,904],{},"Worker（如 OAuth）单独在本地/CI 用 wrangler 部署",[79,906,908],{"id":907},"_35-验收方法","3.5 验收方法",[10,910,911,912,914],{},"当你 push 到 ",[122,913,818],{}," 后：",[33,916,917,920,923],{},[20,918,919],{},"Cloudflare 自动出现新 deployment",[20,921,922],{},"状态为 Success（绿色）",[20,924,925,928],{},[122,926,927],{},"www.xuyangfly.site"," 可访问",[10,930,931],{},"部署失败时，优先查看：",[17,933,934,937,940],{},[20,935,936],{},"Build command",[20,938,939],{},"Output directory",[20,941,942],{},"是否有额外 deploy 命令误加",[326,944,945],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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);}",{"title":51,"searchDepth":52,"depth":52,"links":947},[948,949,950,951,952],{"id":751,"depth":52,"text":752},{"id":789,"depth":52,"text":790},{"id":821,"depth":52,"text":822},{"id":871,"depth":52,"text":872},{"id":907,"depth":52,"text":908},"把仓库 adkeb/blog 接入 Pages，设置正确构建参数，避开常见部署报错。",[],{},"/chapter-posts/project-replication-guide/03-github-and-cloudflare-pages",{"title":746,"description":953},"03-github-and-cloudflare-pages","chapter-posts/project-replication-guide/03-github-and-cloudflare-pages",[67,961,962],"GitHub","Cloudflare Pages","LLAZYoqNkeb-e__OjK3h8vv8ZEdVqyLnVI-RE8JShJ0",{"id":965,"title":966,"body":967,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":1088,"draft":57,"extension":58,"lang":59,"legacySlugs":1089,"meta":1090,"navigation":61,"order":473,"path":1091,"seo":1092,"slug":1093,"stem":1094,"tags":1095,"toc":61,"updated":55,"__hash__":1098},"chapterPosts/chapter-posts/project-replication-guide/04-domain-dns-and-redirect.md","第 4 节：域名、DNS 与 301 跳转（主域统一）",{"type":7,"value":968,"toc":1082},[969,973,976,979,990,994,997,1023,1029,1033,1036,1039,1050,1054,1057,1064,1067,1075],[79,970,972],{"id":971},"_41-为什么要做裸域-301-到-www","4.1 为什么要做裸域 301 到 www",[10,974,975],{},"统一主域可以减少 SEO 分裂和链接重复。",[10,977,978],{},"你的目标是：",[17,980,981],{},[20,982,983,986,987],{},[122,984,985],{},"https://xuyangfly.site/xxx"," 永久跳到 ",[122,988,989],{},"https://www.xuyangfly.site/xxx",[79,991,993],{"id":992},"_42-跳转规则怎么填","4.2 跳转规则怎么填",[10,995,996],{},"在 Cloudflare 中创建转发规则：",[33,998,999,1005,1011,1017],{},[20,1000,1001,1002],{},"URL 匹配：",[122,1003,1004],{},"xuyangfly.site/*",[20,1006,1007,1008],{},"类型：",[122,1009,1010],{},"Forwarding URL",[20,1012,1013,1014],{},"状态码：",[122,1015,1016],{},"301 - Permanent Redirect",[20,1018,1019,1020],{},"目标：",[122,1021,1022],{},"https://www.xuyangfly.site/$1",[10,1024,1025,1028],{},[122,1026,1027],{},"$1"," 代表原路径后半段，会被完整保留。",[79,1030,1032],{"id":1031},"_43-为什么你会看到rule-may-not-apply-to-traffic","4.3 为什么你会看到“rule may not apply to traffic”",[10,1034,1035],{},"这提示表示：当前流量没走 Cloudflare 代理层。",[10,1037,1038],{},"修复：",[33,1040,1041,1044,1047],{},[20,1042,1043],{},"到 DNS 列表确认根域记录是橙云（Proxied）",[20,1045,1046],{},"如果没有合适记录，创建一个 A 记录占位并开启代理",[20,1048,1049],{},"保存后等待 1~5 分钟再测",[79,1051,1053],{"id":1052},"_44-验证命令","4.4 验证命令",[10,1055,1056],{},"在浏览器访问：",[17,1058,1059],{},[20,1060,1061],{},[122,1062,1063],{},"https://xuyangfly.site/test?a=1",[10,1065,1066],{},"期望：",[17,1068,1069],{},[20,1070,1071,1072],{},"地址栏最终变成 ",[122,1073,1074],{},"https://www.xuyangfly.site/test?a=1",[10,1076,1077,1078,1081],{},"如果是连接失败（如 ",[122,1079,1080],{},"ERR_CONNECTION_CLOSED","），优先回到 DNS 检查代理状态。",{"title":51,"searchDepth":52,"depth":52,"links":1083},[1084,1085,1086,1087],{"id":971,"depth":52,"text":972},{"id":992,"depth":52,"text":993},{"id":1031,"depth":52,"text":1032},{"id":1052,"depth":52,"text":1053},"把裸域 xuyangfly.site 301 到 www，解决规则不生效与代理记录问题。",[],{},"/chapter-posts/project-replication-guide/04-domain-dns-and-redirect",{"title":966,"description":1088},"04-domain-dns-and-redirect","chapter-posts/project-replication-guide/04-domain-dns-and-redirect",[67,1096,1097],"DNS",301,"578oUC4KJGN4YYl6zTyB-MLXMLtuDPxHNbfKQbOntiI",{"id":1100,"title":1101,"body":1102,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":1223,"draft":57,"extension":58,"lang":59,"legacySlugs":1224,"meta":1225,"navigation":61,"order":486,"path":1226,"seo":1227,"slug":1228,"stem":1229,"tags":1230,"toc":61,"updated":55,"__hash__":1233},"chapterPosts/chapter-posts/project-replication-guide/05-preview-tunnel-and-access.md","第 5 节：预览链路（Cloudflare Tunnel + Access）",{"type":7,"value":1103,"toc":1216},[1104,1108,1111,1128,1132,1135,1149,1152,1156,1159,1162,1170,1174,1177,1180,1191,1195,1198],[79,1105,1107],{"id":1106},"_51-架构目标","5.1 架构目标",[10,1109,1110],{},"你要达到下面 2 条：",[33,1112,1113,1119],{},[20,1114,1115,1116,125],{},"主站永远公开可用（",[122,1117,1118],{},"www",[20,1120,1121,1122,574,1125,125],{},"预览与运维私有访问（",[122,1123,1124],{},"preview",[122,1126,1127],{},"ops",[79,1129,1131],{"id":1130},"_52-草稿显示机制","5.2 草稿显示机制",[10,1133,1134],{},"通过变量控制：",[17,1136,1137,1143],{},[20,1138,1139,1140],{},"Production：",[122,1141,1142],{},"NUXT_PUBLIC_SHOW_DRAFTS=false",[20,1144,1145,1146],{},"Preview：",[122,1147,1148],{},"NUXT_PUBLIC_SHOW_DRAFTS=true",[10,1150,1151],{},"这样同一套代码在不同环境会得到不同可见性。",[79,1153,1155],{"id":1154},"_53-tunnel-的职责","5.3 Tunnel 的职责",[10,1157,1158],{},"Tunnel 不是托管主站内容，而是把本地预览服务安全暴露出去。",[10,1160,1161],{},"典型用途：",[17,1163,1164,1167],{},[20,1165,1166],{},"草稿内容预览",[20,1168,1169],{},"私有后台入口",[79,1171,1173],{"id":1172},"_54-access-的职责","5.4 Access 的职责",[10,1175,1176],{},"Access 是“谁能进来”的门禁系统。",[10,1178,1179],{},"你应配置：",[33,1181,1182,1185,1188],{},[20,1183,1184],{},"只允许你的邮箱登录",[20,1186,1187],{},"会话有效期缩短（例如 1~8 小时）",[20,1189,1190],{},"打开审计日志",[79,1192,1194],{"id":1193},"_55-验收测试","5.5 验收测试",[10,1196,1197],{},"必须做这 3 条：",[33,1199,1200,1206,1213],{},[20,1201,1202,1203,1205],{},"关闭本地 Tunnel 后，",[122,1204,1118],{}," 仍能访问。",[20,1207,1208,1209,1212],{},"未授权访问 ",[122,1210,1211],{},"preview.*","，看到拦截页。",[20,1214,1215],{},"授权后能访问预览站，并看到草稿。",{"title":51,"searchDepth":52,"depth":52,"links":1217},[1218,1219,1220,1221,1222],{"id":1106,"depth":52,"text":1107},{"id":1130,"depth":52,"text":1131},{"id":1154,"depth":52,"text":1155},{"id":1172,"depth":52,"text":1173},{"id":1193,"depth":52,"text":1194},"把草稿预览和后台放到私有入口，确保 Tunnel 失效不影响公开主站。",[],{},"/chapter-posts/project-replication-guide/05-preview-tunnel-and-access",{"title":1101,"description":1223},"05-preview-tunnel-and-access","chapter-posts/project-replication-guide/05-preview-tunnel-and-access",[67,1231,1232],"Tunnel","Zero Trust","xw4xbvKHiLSWUi6NwiRDw5FtQ_GiERPmprH3_HLe6fU",{"id":1235,"title":1236,"body":1237,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":1519,"draft":57,"extension":58,"lang":59,"legacySlugs":1520,"meta":1521,"navigation":61,"order":499,"path":1522,"seo":1523,"slug":1524,"stem":1525,"tags":1526,"toc":61,"updated":55,"__hash__":1530},"chapterPosts/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker.md","第 6 节：Decap CMS 与 GitHub OAuth Worker",{"type":7,"value":1238,"toc":1511},[1239,1243,1250,1253,1270,1273,1277,1282,1348,1352,1358,1375,1378,1411,1422,1426,1432,1446,1449,1453,1484,1487,1491,1508],[79,1240,1242],{"id":1241},"_61-为什么要单独部署-oauth-worker","6.1 为什么要单独部署 OAuth Worker",[10,1244,1245,1246,1249],{},"你遇到过默认 Netlify OAuth 回调不可用问题（",[122,1247,1248],{},"Not Found","）。",[10,1251,1252],{},"因此项目采用自建方案：",[17,1254,1255,1261],{},[20,1256,1257,1260],{},[122,1258,1259],{},"ops/decap-oauth/worker.js"," 处理 GitHub OAuth",[20,1262,1263,1266,1267],{},[122,1264,1265],{},"public/admin/config.yml"," 指向你自己的 ",[122,1268,1269],{},"base_url",[10,1271,1272],{},"这让登录链路完全可控。",[79,1274,1276],{"id":1275},"_62-cms-配置必须与项目一致","6.2 CMS 配置（必须与项目一致）",[10,1278,1279,1281],{},[122,1280,1265],{}," 核心段：",[171,1283,1287],{"className":1284,"code":1285,"language":1286,"meta":51,"style":51},"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",[122,1288,1289,1298,1308,1318,1328,1338],{"__ignoreMap":51},[179,1290,1291,1295],{"class":181,"line":182},[179,1292,1294],{"class":1293},"s9eBZ","backend",[179,1296,1297],{"class":443},":\n",[179,1299,1300,1303,1305],{"class":181,"line":52},[179,1301,1302],{"class":1293},"  name",[179,1304,452],{"class":443},[179,1306,1307],{"class":247},"github\n",[179,1309,1310,1313,1315],{"class":181,"line":336},[179,1311,1312],{"class":1293},"  repo",[179,1314,452],{"class":443},[179,1316,1317],{"class":247},"adkeb/blog\n",[179,1319,1320,1323,1325],{"class":181,"line":473},[179,1321,1322],{"class":1293},"  branch",[179,1324,452],{"class":443},[179,1326,1327],{"class":247},"main\n",[179,1329,1330,1333,1335],{"class":181,"line":486},[179,1331,1332],{"class":1293},"  base_url",[179,1334,452],{"class":443},[179,1336,1337],{"class":247},"https://decap-github-oauth.xuyang020128.workers.dev\n",[179,1339,1340,1343,1345],{"class":181,"line":499},[179,1341,1342],{"class":1293},"  auth_endpoint",[179,1344,452],{"class":443},[179,1346,1347],{"class":247},"auth\n",[79,1349,1351],{"id":1350},"_63-worker-环境变量与密钥","6.3 Worker 环境变量与密钥",[10,1353,1354,1357],{},[122,1355,1356],{},"ops/decap-oauth/wrangler.toml"," 里是公开配置：",[17,1359,1360,1365,1370],{},[20,1361,1362],{},[122,1363,1364],{},"CMS_ORIGIN",[20,1366,1367],{},[122,1368,1369],{},"GITHUB_REDIRECT_URI",[20,1371,1372],{},[122,1373,1374],{},"GITHUB_CLIENT_ID",[10,1376,1377],{},"密钥必须用 secret：",[171,1379,1381],{"className":173,"code":1380,"language":175,"meta":51,"style":51},"npx wrangler secret put GITHUB_CLIENT_SECRET\nnpx wrangler secret put OAUTH_STATE_SECRET\n",[122,1382,1383,1398],{"__ignoreMap":51},[179,1384,1385,1387,1389,1392,1395],{"class":181,"line":182},[179,1386,244],{"class":185},[179,1388,248],{"class":247},[179,1390,1391],{"class":247}," secret",[179,1393,1394],{"class":247}," put",[179,1396,1397],{"class":247}," GITHUB_CLIENT_SECRET\n",[179,1399,1400,1402,1404,1406,1408],{"class":181,"line":52},[179,1401,244],{"class":185},[179,1403,248],{"class":247},[179,1405,1391],{"class":247},[179,1407,1394],{"class":247},[179,1409,1410],{"class":247}," OAUTH_STATE_SECRET\n",[10,1412,1413,1417,1418,1421],{},[1414,1415,1416],"strong",{},"注意","：",[122,1419,1420],{},"GITHUB_CLIENT_SECRET"," 绝对不能写入 git。",[79,1423,1425],{"id":1424},"_64-worker-路由逻辑读懂就够不用会写","6.4 Worker 路由逻辑（读懂就够，不用会写）",[10,1427,1428,1431],{},[122,1429,1430],{},"worker.js"," 做两件事：",[33,1433,1434,1440],{},[20,1435,1436,1439],{},[122,1437,1438],{},"/auth","：发起 GitHub 授权",[20,1441,1442,1445],{},[122,1443,1444],{},"/callback","：换 token 并回传给 Decap 窗口",[10,1447,1448],{},"你项目中还做了弹窗握手与 postMessage 回传，解决了“登录成功但 CMS 不更新”的常见问题。",[79,1450,1452],{"id":1451},"_65-部署命令完整","6.5 部署命令（完整）",[171,1454,1456],{"className":173,"code":1455,"language":175,"meta":51,"style":51},"cd ops/decap-oauth\nnpx wrangler whoami\nnpx wrangler deploy\n",[122,1457,1458,1466,1475],{"__ignoreMap":51},[179,1459,1460,1463],{"class":181,"line":182},[179,1461,1462],{"class":188},"cd",[179,1464,1465],{"class":247}," ops/decap-oauth\n",[179,1467,1468,1470,1472],{"class":181,"line":52},[179,1469,244],{"class":185},[179,1471,248],{"class":247},[179,1473,1474],{"class":247}," whoami\n",[179,1476,1477,1479,1481],{"class":181,"line":336},[179,1478,244],{"class":185},[179,1480,248],{"class":247},[179,1482,1483],{"class":247}," deploy\n",[10,1485,1486],{},"部署成功会返回你的 workers.dev 地址。",[79,1488,1490],{"id":1489},"_66-验收标准","6.6 验收标准",[33,1492,1493,1499,1502,1505],{},[20,1494,1495,1496],{},"打开 ",[122,1497,1498],{},"https://www.xuyangfly.site/admin",[20,1500,1501],{},"点“使用 GitHub 登录”",[20,1503,1504],{},"授权后可进入 CMS 内容列表",[20,1506,1507],{},"新建文章后能触发 Git 提交",[326,1509,1510],{},"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":51,"searchDepth":52,"depth":52,"links":1512},[1513,1514,1515,1516,1517,1518],{"id":1241,"depth":52,"text":1242},{"id":1275,"depth":52,"text":1276},{"id":1350,"depth":52,"text":1351},{"id":1424,"depth":52,"text":1425},{"id":1451,"depth":52,"text":1452},{"id":1489,"depth":52,"text":1490},"从 Netlify 失败场景迁移到 Cloudflare Worker OAuth 网关，打通 /admin 可视化编辑。",[],{},"/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",{"title":1236,"description":1519},"06-decap-cms-and-oauth-worker","chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",[67,1527,1528,1529],"Decap CMS","OAuth","Worker","CftJ87f8FswywDArDHUTg3sgFZwMb6KyNdd-iw7FgN8",{"id":1532,"title":1533,"body":1534,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":1707,"draft":57,"extension":58,"lang":59,"legacySlugs":1708,"meta":1709,"navigation":61,"order":510,"path":1710,"seo":1711,"slug":1712,"stem":1713,"tags":1714,"toc":61,"updated":55,"__hash__":1717},"chapterPosts/chapter-posts/project-replication-guide/07-giscus-and-comment-fix.md","第 7 节：评论系统 giscus 与空白问题修复",{"type":7,"value":1535,"toc":1698},[1536,1540,1543,1565,1570,1574,1577,1585,1590,1593,1601,1605,1608,1619,1626,1680,1684],[79,1537,1539],{"id":1538},"_71-giscus-必备参数","7.1 giscus 必备参数",[10,1541,1542],{},"你需要从 giscus 配置页记录：",[33,1544,1545,1550,1555,1560],{},[20,1546,1547],{},[122,1548,1549],{},"repo",[20,1551,1552],{},[122,1553,1554],{},"repoId",[20,1556,1557],{},[122,1558,1559],{},"category",[20,1561,1562],{},[122,1563,1564],{},"categoryId",[10,1566,1567,1568,284],{},"你的当前值是基于仓库 ",[122,1569,283],{},[79,1571,1573],{"id":1572},"_72-环境变量要在两个环境都填","7.2 环境变量要在两个环境都填",[10,1575,1576],{},"Cloudflare Pages 里：",[17,1578,1579,1582],{},[20,1580,1581],{},"Production 环境变量",[20,1583,1584],{},"Preview 环境变量",[10,1586,1587,1588,284],{},"都要填同样的 ",[122,1589,598],{},[10,1591,1592],{},"否则表现会是：",[17,1594,1595,1598],{},[20,1596,1597],{},"线上能加载、预览不加载",[20,1599,1600],{},"或者反过来",[79,1602,1604],{"id":1603},"_73-你遇到的评论空白问题","7.3 你遇到的评论空白问题",[10,1606,1607],{},"问题现象：",[33,1609,1610,1613,1616],{},[20,1611,1612],{},"登录 GitHub 回来后评论区空白",[20,1614,1615],{},"刷新当前页面后又空白",[20,1617,1618],{},"需要手动关弹窗/重进才恢复",[160,1620,1622,1623,125],{"id":1621},"修复点componentsgiscuscommentsclientvue","修复点（",[122,1624,1625],{},"components/GiscusComments.client.vue",[33,1627,1628,1643,1654,1669],{},[20,1629,1630,1631,1634,1635,1638],{},"监听 ",[122,1632,1633],{},"focus"," 和 ",[122,1636,1637],{},"visibilitychange",[17,1639,1640],{},[20,1641,1642],{},"从 GitHub 授权窗口返回时，自动重新挂载 giscus。",[20,1644,1645,1646,1649],{},"把加载策略改为 ",[122,1647,1648],{},"eager",[17,1650,1651],{},[20,1652,1653],{},"避免懒加载时机导致 iframe 空白。",[20,1655,1656,1657,1660,1661,1664],{},"路由监听从 ",[122,1658,1659],{},"fullPath"," 收敛到 ",[122,1662,1663],{},"path",[17,1665,1666],{},[20,1667,1668],{},"减少不必要重挂载。",[20,1670,1671,1672,1675],{},"主题切换时向 iframe ",[122,1673,1674],{},"postMessage",[17,1676,1677],{},[20,1678,1679],{},"避免夜间模式切换导致评论状态不一致。",[79,1681,1683],{"id":1682},"_74-验收步骤","7.4 验收步骤",[33,1685,1686,1689,1692,1695],{},[20,1687,1688],{},"打开任意文章页，确认评论可见。",[20,1690,1691],{},"点击登录并完成 GitHub 授权。",[20,1693,1694],{},"回到页面后无需手动刷新即可评论。",[20,1696,1697],{},"手动刷新页面，评论区仍正常渲染。",{"title":51,"searchDepth":52,"depth":52,"links":1699},[1700,1701,1702,1706],{"id":1538,"depth":52,"text":1539},{"id":1572,"depth":52,"text":1573},{"id":1603,"depth":52,"text":1604,"children":1703},[1704],{"id":1621,"depth":336,"text":1705},"修复点（components/GiscusComments.client.vue）",{"id":1682,"depth":52,"text":1683},"配置 giscus 参数、环境变量同步，并修复登录后评论空白、刷新后评论空白问题。",[],{},"/chapter-posts/project-replication-guide/07-giscus-and-comment-fix",{"title":1533,"description":1707},"07-giscus-and-comment-fix","chapter-posts/project-replication-guide/07-giscus-and-comment-fix",[67,1715,1716],"giscus","评论系统","Q3kyHNdaPbn0boCYo_SD58Gnw4JEPaGtjktQD-56xa8",{"id":1719,"title":1720,"body":1721,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":1900,"draft":57,"extension":58,"lang":59,"legacySlugs":1901,"meta":1902,"navigation":61,"order":1903,"path":1904,"seo":1905,"slug":1906,"stem":1907,"tags":1908,"toc":61,"updated":55,"__hash__":1911},"chapterPosts/chapter-posts/project-replication-guide/08-chapter-system-and-route-migration.md","第 8 节：章节体系（父文 + 子文 + 旧链接 301）",{"type":7,"value":1722,"toc":1893},[1723,1727,1730,1747,1750,1764,1768,1774,1780,1783,1797,1800,1804,1807,1823,1834,1838,1845,1861,1864,1868,1871,1879,1882,1890],[79,1724,1726],{"id":1725},"_81-章节体系是什么","8.1 章节体系是什么",[10,1728,1729],{},"你当前项目有 3 类内容：",[33,1731,1732,1737,1742],{},[20,1733,1734,1735],{},"普通文章 ",[122,1736,636],{},[20,1738,1739,1740],{},"章节父文 ",[122,1741,642],{},[20,1743,1744,1745],{},"章节子文章 ",[122,1746,648],{},[10,1748,1749],{},"路由分别是：",[17,1751,1752,1756,1760],{},[20,1753,1754],{},[122,1755,666],{},[20,1757,1758],{},[122,1759,671],{},[20,1761,1762],{},[122,1763,676],{},[79,1765,1767],{"id":1766},"_82-目录约束为什么重要","8.2 目录约束为什么重要",[10,1769,1770,1771,1417],{},"子文章文件路径必须匹配 frontmatter 的 ",[122,1772,1773],{},"chapterSlug",[171,1775,1778],{"className":1776,"code":1777,"language":260,"meta":51},[258],"content/chapter-posts/\u003CchapterSlug>/\u003Cpost>.md\n",[122,1779,1777],{"__ignoreMap":51},[10,1781,1782],{},"比如：",[17,1784,1785,1791],{},[20,1786,1787,1788],{},"路径：",[122,1789,1790],{},"content/chapter-posts/machine-learning/linear-regression.md",[20,1792,1793,1794],{},"frontmatter：",[122,1795,1796],{},"chapterSlug: machine-learning",[10,1798,1799],{},"如果不一致，构建阶段直接报错，阻止脏数据上线。",[79,1801,1803],{"id":1802},"_83-章节正文插目录占位符","8.3 章节正文插目录占位符",[10,1805,1806],{},"章节正文里插入：",[171,1808,1811],{"className":1809,"code":1810,"language":58,"meta":51,"style":51},"language-md shiki shiki-themes github-light github-dark","::chapter-children\n::\n",[122,1812,1813,1818],{"__ignoreMap":51},[179,1814,1815],{"class":181,"line":182},[179,1816,1817],{"class":443},"::chapter-children\n",[179,1819,1820],{"class":181,"line":52},[179,1821,1822],{"class":443},"::\n",[10,1824,1825,1826,1829,1830,1833],{},"渲染时会由 ",[122,1827,1828],{},"components/content/ChapterChildren.vue"," 自动拉取同章节子文章并按 ",[122,1831,1832],{},"order"," 排序。",[79,1835,1837],{"id":1836},"_84-旧链接迁移301","8.4 旧链接迁移（301）",[10,1839,1840,1841,1844],{},"当历史链接还是 ",[122,1842,1843],{},"/posts/old-slug"," 时，系统会：",[33,1846,1847,1850,1856],{},[20,1848,1849],{},"先查普通文章",[20,1851,1852,1853],{},"查不到再查章节子文章的 ",[122,1854,1855],{},"legacySlugs",[20,1857,1858,1859],{},"命中则 301 到新地址 ",[122,1860,676],{},[10,1862,1863],{},"这样迁移不会让旧外链失效。",[79,1865,1867],{"id":1866},"_85-当前策略子文章只在章节体系内出现","8.5 当前策略：子文章只在章节体系内出现",[10,1869,1870],{},"根据你的新要求，项目已调整为：",[17,1872,1873,1876],{},[20,1874,1875],{},"子文章不进入首页、全站列表、标签页等全局流",[20,1877,1878],{},"子文章只通过章节页目录进入",[10,1880,1881],{},"这让信息结构更清晰：",[17,1883,1884,1887],{},[20,1885,1886],{},"首页展示“文章/章节”",[20,1888,1889],{},"深度内容在章节内展开",[326,1891,1892],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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);}",{"title":51,"searchDepth":52,"depth":52,"links":1894},[1895,1896,1897,1898,1899],{"id":1725,"depth":52,"text":1726},{"id":1766,"depth":52,"text":1767},{"id":1802,"depth":52,"text":1803},{"id":1836,"depth":52,"text":1837},{"id":1866,"depth":52,"text":1867},"实现章节化写作、章节目录占位符、子文章路由与 legacySlugs 迁移跳转。",[],{},8,"/chapter-posts/project-replication-guide/08-chapter-system-and-route-migration",{"title":1720,"description":1900},"08-chapter-system-and-route-migration","chapter-posts/project-replication-guide/08-chapter-system-and-route-migration",[67,1909,1910],"章节体系","路由迁移","09lBKEy9m61KQ_TiC-FjEgHv0NK9QVPQjZPYyqfn_v0",{"id":1913,"title":1914,"body":1915,"category":345,"chapterSlug":64,"cover":51,"date":55,"description":2157,"draft":57,"extension":58,"lang":59,"legacySlugs":2158,"meta":2159,"navigation":61,"order":2160,"path":2161,"seo":2162,"slug":2163,"stem":2164,"tags":2165,"toc":61,"updated":55,"__hash__":2168},"chapterPosts/chapter-posts/project-replication-guide/09-dark-mode-and-final-checklist.md","第 9 节：夜间模式、最终检查与上线清单",{"type":7,"value":1916,"toc":2150},[1917,1921,1924,1983,1987,1990,2001,2005,2008,2072,2075,2079,2121,2125,2128,2145,2148],[79,1918,1920],{"id":1919},"_91-夜间模式实现点","9.1 夜间模式实现点",[10,1922,1923],{},"本项目夜间模式不是“切一段类名”这么简单，而是完整主题体系：",[33,1925,1926,1946,1956,1973],{},[20,1927,1928,1931],{},[122,1929,1930],{},"composables/useTheme.ts",[17,1932,1933,1940,1943],{},[20,1934,1935,1936,1939],{},"维护 ",[122,1937,1938],{},"light/dark"," 状态",[20,1941,1942],{},"读取系统偏好",[20,1944,1945],{},"localStorage 持久化",[20,1947,1948,1951],{},[122,1949,1950],{},"plugins/theme.client.ts",[17,1952,1953],{},[20,1954,1955],{},"页面启动时初始化主题，减少闪屏",[20,1957,1958,1961],{},[122,1959,1960],{},"assets/css/main.css",[17,1962,1963],{},[20,1964,1965,1968,1969,1972],{},[122,1966,1967],{},":root"," 与 ",[122,1970,1971],{},":root[data-theme=\"dark\"]"," 双变量集",[20,1974,1975,1978],{},[122,1976,1977],{},"components/SiteHeader.vue",[17,1979,1980],{},[20,1981,1982],{},"提供“夜间/日间”切换按钮",[79,1984,1986],{"id":1985},"_92-为什么这种做法更稳","9.2 为什么这种做法更稳",[10,1988,1989],{},"优点：",[33,1991,1992,1995,1998],{},[20,1993,1994],{},"不绑定具体页面组件，任何页面都自动继承主题。",[20,1996,1997],{},"主题变量统一管理，后续改色只改一处。",[20,1999,2000],{},"与 giscus 评论联动，避免评论 iframe 主题不同步。",[79,2002,2004],{"id":2003},"_93-发布前最终命令清单","9.3 发布前最终命令清单",[10,2006,2007],{},"每次发布前执行：",[171,2009,2011],{"className":173,"code":2010,"language":175,"meta":51,"style":51},"npm run check\nnpm run generate\ngit status\ngit add .\ngit commit -m \"your message\"\ngit push origin main\n",[122,2012,2013,2021,2029,2036,2046,2059],{"__ignoreMap":51},[179,2014,2015,2017,2019],{"class":181,"line":182},[179,2016,216],{"class":185},[179,2018,398],{"class":247},[179,2020,697],{"class":247},[179,2022,2023,2025,2027],{"class":181,"line":52},[179,2024,216],{"class":185},[179,2026,398],{"class":247},[179,2028,706],{"class":247},[179,2030,2031,2033],{"class":181,"line":336},[179,2032,162],{"class":185},[179,2034,2035],{"class":247}," status\n",[179,2037,2038,2040,2043],{"class":181,"line":473},[179,2039,162],{"class":185},[179,2041,2042],{"class":247}," add",[179,2044,2045],{"class":247}," .\n",[179,2047,2048,2050,2053,2056],{"class":181,"line":486},[179,2049,162],{"class":185},[179,2051,2052],{"class":247}," commit",[179,2054,2055],{"class":188}," -m",[179,2057,2058],{"class":247}," \"your message\"\n",[179,2060,2061,2063,2066,2069],{"class":181,"line":499},[179,2062,162],{"class":185},[179,2064,2065],{"class":247}," push",[179,2067,2068],{"class":247}," origin",[179,2070,2071],{"class":247}," main\n",[10,2073,2074],{},"然后去 Cloudflare Pages 看 deployment 是否成功。",[79,2076,2078],{"id":2077},"_94-线上验收清单逐条打勾","9.4 线上验收清单（逐条打勾）",[33,2080,2081,2086,2094,2100,2103,2106,2112,2115,2118],{},[20,2082,2083,928],{},[122,2084,2085],{},"https://www.xuyangfly.site",[20,2087,2088,2091,2092],{},[122,2089,2090],{},"https://xuyangfly.site"," 会 301 到 ",[122,2093,1118],{},[20,2095,2096,2099],{},[122,2097,2098],{},"/admin"," 可以登录并发布",[20,2101,2102],{},"评论区加载正常，登录后不会空白",[20,2104,2105],{},"夜间模式可切换，刷新后记住状态",[20,2107,2108,2111],{},[122,2109,2110],{},"/chapters"," 能看到章节目录",[20,2113,2114],{},"章节内子文章可访问并有上下篇",[20,2116,2117],{},"普通文章链路不受影响",[20,2119,2120],{},"RSS / Sitemap / Search Index 可访问",[79,2122,2124],{"id":2123},"_95-你已经得到什么","9.5 你已经得到什么",[10,2126,2127],{},"到这一步，你拥有的是一个可以长期迭代的博客系统，而不是一次性演示页：",[33,2129,2130,2133,2136,2139,2142],{},[20,2131,2132],{},"有稳定发布路径",[20,2134,2135],{},"有安全边界",[20,2137,2138],{},"有可视化运营后台",[20,2140,2141],{},"有评论互动",[20,2143,2144],{},"有章节化知识沉淀结构",[10,2146,2147],{},"这正是“可持续维护”的技术项目形态。",[326,2149,945],{},{"title":51,"searchDepth":52,"depth":52,"links":2151},[2152,2153,2154,2155,2156],{"id":1919,"depth":52,"text":1920},{"id":1985,"depth":52,"text":1986},{"id":2003,"depth":52,"text":2004},{"id":2077,"depth":52,"text":2078},{"id":2123,"depth":52,"text":2124},"完成夜间模式与主题持久化，给出发布前最终检查清单，确保你能稳定长期维护。",[],{},9,"/chapter-posts/project-replication-guide/09-dark-mode-and-final-checklist",{"title":1914,"description":2157},"09-dark-mode-and-final-checklist","chapter-posts/project-replication-guide/09-dark-mode-and-final-checklist",[67,2166,2167],"夜间模式","验收","DboPhn-EXjKFLtWP6yV2iw8FlZMQObgE7QyRDhXPHeo",1771232915860]