[{"data":1,"prerenderedAt":1000},["ShallowReactive",2],{"post-\u002Fposts\u002Fzero-hardcode":3,"post-nav-\u002Fposts\u002Fzero-hardcode":963,"post-related-\u002Fposts\u002Fzero-hardcode":982},{"id":4,"title":5,"body":6,"category":948,"cover":949,"date":950,"description":951,"draft":952,"extension":953,"featured":952,"meta":954,"navigation":110,"path":955,"pinned":952,"seo":956,"stem":957,"tags":958,"updated":949,"__hash__":962},"posts\u002Fposts\u002Fzero-hardcode.md","一个配置文件能解决多少问题",{"type":7,"value":8,"toc":938},"minimark",[9,13,16,23,27,30,41,44,162,166,169,217,220,223,227,234,335,346,350,353,356,373,376,410,413,559,565,569,576,674,677,754,761,771,779,782,785,799,812,818,824,830,837,840,847,850,911,914,917,920,928,931,934],[10,11,12],"p",{},"「零硬编码」这句话很容易被当成洁癖。",[10,14,15],{},"毕竟写死一个站名能出什么问题？改的时候全局替换一下不就完了。",[10,17,18,19],{},"我做这个博客的时候，把这条规则当成了硬性架构约束。半年后的结论是：",[20,21,22],"strong",{},"它带来的收益远超预期，而且和代码整洁没什么关系。",[24,25,26],"h2",{"id":26},"四层配置",[10,28,29],{},"我把所有可变内容分成四层：",[31,32,37],"pre",{"className":33,"code":35,"language":36},[34],"language-text","app\u002Fblog.config.ts     站点身份、feed、search\napp\u002Ftheme.config.ts    设计 token（颜色、字号、间距、圆角、动效）\napp\u002Fpages.config.ts    逐路由的业务参数\napp\u002Fdata\u002F*.ts          友链、关于页元数据、系统文案\n","text",[38,39,35],"code",{"__ignoreMap":40},"",[10,42,43],{},"组件里一行硬编码都不许有。",[31,45,49],{"className":46,"code":47,"language":48,"meta":40,"style":40},"language-vue shiki shiki-themes github-light github-dark","\u003C!-- 禁止 -->\n\u003Ch1>喵洛阁\u003C\u002Fh1>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fkemiaosw\">GitHub\u003C\u002Fa>\n\n\u003C!-- 允许 -->\n\u003Ch1>{{ site.name }}\u003C\u002Fh1>\n\u003Ca :href=\"social.url\">{{ social.label }}\u003C\u002Fa>\n","vue",[38,50,51,60,79,105,112,118,132],{"__ignoreMap":40},[52,53,56],"span",{"class":54,"line":55},"line",1,[52,57,59],{"class":58},"sJ8bj","\u003C!-- 禁止 -->\n",[52,61,63,67,71,74,76],{"class":54,"line":62},2,[52,64,66],{"class":65},"sVt8B","\u003C",[52,68,70],{"class":69},"s9eBZ","h1",[52,72,73],{"class":65},">喵洛阁\u003C\u002F",[52,75,70],{"class":69},[52,77,78],{"class":65},">\n",[52,80,82,84,87,91,94,98,101,103],{"class":54,"line":81},3,[52,83,66],{"class":65},[52,85,86],{"class":69},"a",[52,88,90],{"class":89},"sScJk"," href",[52,92,93],{"class":65},"=",[52,95,97],{"class":96},"sZZnC","\"https:\u002F\u002Fgithub.com\u002Fkemiaosw\"",[52,99,100],{"class":65},">GitHub\u003C\u002F",[52,102,86],{"class":69},[52,104,78],{"class":65},[52,106,108],{"class":54,"line":107},4,[52,109,111],{"emptyLinePlaceholder":110},true,"\n",[52,113,115],{"class":54,"line":114},5,[52,116,117],{"class":58},"\u003C!-- 允许 -->\n",[52,119,121,123,125,128,130],{"class":54,"line":120},6,[52,122,66],{"class":65},[52,124,70],{"class":69},[52,126,127],{"class":65},">{{ site.name }}\u003C\u002F",[52,129,70],{"class":69},[52,131,78],{"class":65},[52,133,135,137,139,142,145,147,150,153,155,158,160],{"class":54,"line":134},7,[52,136,66],{"class":65},[52,138,86],{"class":69},[52,140,141],{"class":65}," :",[52,143,144],{"class":89},"href",[52,146,93],{"class":65},[52,148,149],{"class":96},"\"",[52,151,152],{"class":65},"social.url",[52,154,149],{"class":96},[52,156,157],{"class":65},">{{ social.label }}\u003C\u002F",[52,159,86],{"class":69},[52,161,78],{"class":65},[24,163,165],{"id":164},"收益一改一处全站同步","收益一：改一处，全站同步",[10,167,168],{},"最直接的收益是这个。举个真实例子：我想把「归档」改成「时间线」。",[31,170,174],{"className":171,"code":172,"language":173,"meta":40,"style":40},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F 改这一行\nnav: [\n  { label: '时间线', to: '\u002Farchive', icon: 'tabler:archive' },\n]\n","ts",[38,175,176,181,189,212],{"__ignoreMap":40},[52,177,178],{"class":54,"line":55},[52,179,180],{"class":58},"\u002F\u002F 改这一行\n",[52,182,183,186],{"class":54,"line":62},[52,184,185],{"class":89},"nav",[52,187,188],{"class":65},": [\n",[52,190,191,194,197,200,203,206,209],{"class":54,"line":81},[52,192,193],{"class":65},"  { label: ",[52,195,196],{"class":96},"'时间线'",[52,198,199],{"class":65},", to: ",[52,201,202],{"class":96},"'\u002Farchive'",[52,204,205],{"class":65},", icon: ",[52,207,208],{"class":96},"'tabler:archive'",[52,210,211],{"class":65}," },\n",[52,213,214],{"class":54,"line":107},[52,215,216],{"class":65},"]\n",[10,218,219],{},"改完，桌面导航、平板汉堡菜单、移动端底部 Tab 栏，三处同时更新。",[10,221,222],{},"如果这些 label 是硬编码在三处的，我至少要改三个文件，而且很可能漏掉移动端（因为它在另一个组件里，平时不怎么看）。",[24,224,226],{"id":225},"收益二配置即文档","收益二：配置即文档",[10,228,229,230,233],{},"打开 ",[38,231,232],{},"blog.config.ts","，你立刻知道这个站有哪些页面、有哪些社交链接、RSS 开没开。",[31,235,237],{"className":171,"code":236,"language":173,"meta":40,"style":40},"export default defineAppConfig({\n  site: {\n    name: '喵洛阁',\n    nav: [\n      { label: '首页', to: '\u002F', icon: 'tabler:home' },\n      { label: '归档', to: '\u002Farchive', icon: 'tabler:archive' },\n      \u002F\u002F ...\n    ],\n  },\n})\n",[38,238,239,254,259,270,275,295,312,317,323,329],{"__ignoreMap":40},[52,240,241,245,248,251],{"class":54,"line":55},[52,242,244],{"class":243},"szBVR","export",[52,246,247],{"class":243}," default",[52,249,250],{"class":89}," defineAppConfig",[52,252,253],{"class":65},"({\n",[52,255,256],{"class":54,"line":62},[52,257,258],{"class":65},"  site: {\n",[52,260,261,264,267],{"class":54,"line":81},[52,262,263],{"class":65},"    name: ",[52,265,266],{"class":96},"'喵洛阁'",[52,268,269],{"class":65},",\n",[52,271,272],{"class":54,"line":107},[52,273,274],{"class":65},"    nav: [\n",[52,276,277,280,283,285,288,290,293],{"class":54,"line":114},[52,278,279],{"class":65},"      { label: ",[52,281,282],{"class":96},"'首页'",[52,284,199],{"class":65},[52,286,287],{"class":96},"'\u002F'",[52,289,205],{"class":65},[52,291,292],{"class":96},"'tabler:home'",[52,294,211],{"class":65},[52,296,297,299,302,304,306,308,310],{"class":54,"line":120},[52,298,279],{"class":65},[52,300,301],{"class":96},"'归档'",[52,303,199],{"class":65},[52,305,202],{"class":96},[52,307,205],{"class":65},[52,309,208],{"class":96},[52,311,211],{"class":65},[52,313,314],{"class":54,"line":134},[52,315,316],{"class":58},"      \u002F\u002F ...\n",[52,318,320],{"class":54,"line":319},8,[52,321,322],{"class":65},"    ],\n",[52,324,326],{"class":54,"line":325},9,[52,327,328],{"class":65},"  },\n",[52,330,332],{"class":54,"line":331},10,[52,333,334],{"class":65},"})\n",[10,336,337,338,341,342,345],{},"这比翻 15 个 ",[38,339,340],{},".vue"," 文件去找 ",[38,343,344],{},"to=\"\u002Farchive\""," 快得多。",[24,347,349],{"id":348},"收益三功能开关变成真的开关","收益三：功能开关变成真的开关",[10,351,352],{},"这是我最没想到的收益。",[10,354,355],{},"提示词的验收标准里有一条：",[357,358,359],"blockquote",{},[10,360,361,364,365,368,369,372],{},[38,362,363],{},"feed"," \u002F ",[38,366,367],{},"search"," 任一 ",[38,370,371],{},"enabled: false"," 后：入口消失、对应路由 404、head 无相关注入",[10,374,375],{},"如果没有配置层，这个需求要改 6 个地方：",[377,378,379,383,393,398,404,407],"ol",{},[380,381,382],"li",{},"删掉 footer 的 RSS 链接",[380,384,385,386,389,390],{},"删掉 ",[38,387,388],{},"\u003Chead>"," 的 ",[38,391,392],{},"\u003Clink rel=\"alternate\">",[380,394,385,395],{},[38,396,397],{},"server\u002Froutes\u002Frss.xml.get.ts",[380,399,400,401],{},"改 ",[38,402,403],{},"nitro.prerender.routes",[380,405,406],{},"删掉搜索按钮",[380,408,409],{},"解绑快捷键",[10,411,412],{},"有了配置层，它们全都读同一个字段：",[31,414,416],{"className":171,"code":415,"language":173,"meta":40,"style":40},"const { feed, search } = useSiteConfig()\n\n\u002F\u002F footer\n\u003CNuxtLink v-if=\"feed.rss.enabled\" :to=\"feed.rss.path\">RSS\u003C\u002FNuxtLink>\n\n\u002F\u002F head\nif (feed.rss.enabled) links.push({ rel: 'alternate', ... })\n\n\u002F\u002F 路由\nif (!feed.rss.enabled) throw createError({ statusCode: 404 })\n",[38,417,418,445,449,454,489,493,498,523,527,532],{"__ignoreMap":40},[52,419,420,423,426,429,432,434,437,439,442],{"class":54,"line":55},[52,421,422],{"class":243},"const",[52,424,425],{"class":65}," { ",[52,427,363],{"class":428},"sj4cs",[52,430,431],{"class":65},", ",[52,433,367],{"class":428},[52,435,436],{"class":65}," } ",[52,438,93],{"class":243},[52,440,441],{"class":89}," useSiteConfig",[52,443,444],{"class":65},"()\n",[52,446,447],{"class":54,"line":62},[52,448,111],{"emptyLinePlaceholder":110},[52,450,451],{"class":54,"line":81},[52,452,453],{"class":58},"\u002F\u002F footer\n",[52,455,456,458,461,464,467,470,472,475,478,481,484,487],{"class":54,"line":107},[52,457,66],{"class":243},[52,459,460],{"class":65},"NuxtLink v",[52,462,463],{"class":243},"-if=",[52,465,466],{"class":96},"\"feed.rss.enabled\"",[52,468,469],{"class":65}," :to",[52,471,93],{"class":243},[52,473,474],{"class":96},"\"feed.rss.path\"",[52,476,477],{"class":243},">",[52,479,480],{"class":428},"RSS",[52,482,483],{"class":243},"\u003C\u002F",[52,485,486],{"class":65},"NuxtLink",[52,488,78],{"class":243},[52,490,491],{"class":54,"line":114},[52,492,111],{"emptyLinePlaceholder":110},[52,494,495],{"class":54,"line":120},[52,496,497],{"class":58},"\u002F\u002F head\n",[52,499,500,503,506,509,512,515,517,520],{"class":54,"line":134},[52,501,502],{"class":243},"if",[52,504,505],{"class":65}," (feed.rss.enabled) links.",[52,507,508],{"class":89},"push",[52,510,511],{"class":65},"({ rel: ",[52,513,514],{"class":96},"'alternate'",[52,516,431],{"class":65},[52,518,519],{"class":243},"...",[52,521,522],{"class":65}," })\n",[52,524,525],{"class":54,"line":319},[52,526,111],{"emptyLinePlaceholder":110},[52,528,529],{"class":54,"line":325},[52,530,531],{"class":58},"\u002F\u002F 路由\n",[52,533,534,536,539,542,545,548,551,554,557],{"class":54,"line":331},[52,535,502],{"class":243},[52,537,538],{"class":65}," (",[52,540,541],{"class":243},"!",[52,543,544],{"class":65},"feed.rss.enabled) ",[52,546,547],{"class":243},"throw",[52,549,550],{"class":89}," createError",[52,552,553],{"class":65},"({ statusCode: ",[52,555,556],{"class":428},"404",[52,558,522],{"class":65},[10,560,561,564],{},[20,562,563],{},"开关的原子性","从\"靠人记得改全\"变成了\"结构上不可能不同步\"。",[24,566,568],{"id":567},"收益四主题切换不用碰组件","收益四：主题切换不用碰组件",[10,570,571,572,575],{},"设计 token 全在 ",[38,573,574],{},"theme.config.ts","：",[31,577,579],{"className":171,"code":578,"language":173,"meta":40,"style":40},"theme: {\n  accent: { light: '#a94f33', dark: '#cc785c' },\n  radius: '0.5rem',\n  contentMaxWidth: '764px',\n  animation: { duration: 200, easing: 'ease-out' },\n}\n",[38,580,581,589,618,630,642,669],{"__ignoreMap":40},[52,582,583,586],{"class":54,"line":55},[52,584,585],{"class":89},"theme",[52,587,588],{"class":65},": {\n",[52,590,591,594,597,600,603,606,608,611,613,616],{"class":54,"line":62},[52,592,593],{"class":89},"  accent",[52,595,596],{"class":65},": { ",[52,598,599],{"class":89},"light",[52,601,602],{"class":65},": ",[52,604,605],{"class":96},"'#a94f33'",[52,607,431],{"class":65},[52,609,610],{"class":89},"dark",[52,612,602],{"class":65},[52,614,615],{"class":96},"'#cc785c'",[52,617,211],{"class":65},[52,619,620,623,625,628],{"class":54,"line":81},[52,621,622],{"class":89},"  radius",[52,624,602],{"class":65},[52,626,627],{"class":96},"'0.5rem'",[52,629,269],{"class":65},[52,631,632,635,637,640],{"class":54,"line":107},[52,633,634],{"class":89},"  contentMaxWidth",[52,636,602],{"class":65},[52,638,639],{"class":96},"'764px'",[52,641,269],{"class":65},[52,643,644,647,649,652,654,657,659,662,664,667],{"class":54,"line":114},[52,645,646],{"class":89},"  animation",[52,648,596],{"class":65},[52,650,651],{"class":89},"duration",[52,653,602],{"class":65},[52,655,656],{"class":428},"200",[52,658,431],{"class":65},[52,660,661],{"class":89},"easing",[52,663,602],{"class":65},[52,665,666],{"class":96},"'ease-out'",[52,668,211],{"class":65},[52,670,671],{"class":54,"line":120},[52,672,673],{"class":65},"}\n",[10,675,676],{},"这些值在构建期被编译成 CSS 变量：",[31,678,682],{"className":679,"code":680,"language":681,"meta":40,"style":40},"language-css shiki shiki-themes github-light github-dark",":root {\n  --accent: #a94f33;\n  --radius: 0.5rem;\n  --content-max-width: 764px;\n  --duration-base: 200ms;\n}\n","css",[38,683,684,692,706,721,736,750],{"__ignoreMap":40},[52,685,686,689],{"class":54,"line":55},[52,687,688],{"class":89},":root",[52,690,691],{"class":65}," {\n",[52,693,694,698,700,703],{"class":54,"line":62},[52,695,697],{"class":696},"s4XuR","  --accent",[52,699,602],{"class":65},[52,701,702],{"class":428},"#a94f33",[52,704,705],{"class":65},";\n",[52,707,708,711,713,716,719],{"class":54,"line":81},[52,709,710],{"class":696},"  --radius",[52,712,602],{"class":65},[52,714,715],{"class":428},"0.5",[52,717,718],{"class":243},"rem",[52,720,705],{"class":65},[52,722,723,726,728,731,734],{"class":54,"line":107},[52,724,725],{"class":696},"  --content-max-width",[52,727,602],{"class":65},[52,729,730],{"class":428},"764",[52,732,733],{"class":243},"px",[52,735,705],{"class":65},[52,737,738,741,743,745,748],{"class":54,"line":114},[52,739,740],{"class":696},"  --duration-base",[52,742,602],{"class":65},[52,744,656],{"class":428},[52,746,747],{"class":243},"ms",[52,749,705],{"class":65},[52,751,752],{"class":54,"line":120},[52,753,673],{"class":65},[10,755,756,757,760],{},"组件里只写 ",[38,758,759],{},"var(--accent)","，不写 hex。",[10,762,763,764,767,768,770],{},"想换强调色？改两行。想换字体？改 ",[38,765,766],{},"fontFamily","。想让动画慢一点？改 ",[38,769,651],{},"。",[10,772,773],{},[20,774,775,776,778],{},"不需要在 30 个 ",[38,777,340],{}," 文件里搜索替换。",[24,780,781],{"id":781},"代价是什么",[10,783,784],{},"诚实地说，这套架构有成本：",[10,786,787,790,791,794,795,798],{},[20,788,789],{},"一、多一层间接。"," 看 ",[38,792,793],{},"{{ site.name }}"," 不如看 ",[38,796,797],{},"喵洛阁"," 直观。新人接手要先去读配置文件。",[10,800,801,804,805,808,809,811],{},[20,802,803],{},"二、类型定义要维护。"," ",[38,806,807],{},"useSiteConfig()"," 里的 interface 得和 ",[38,810,232],{}," 保持同步。",[10,813,814,817],{},[20,815,816],{},"三、过度抽象的风险。"," 如果某个值只在一个组件里用一次，且永远不会变，那抽到配置层就是浪费。",[10,819,820,821],{},"我的判断标准是：",[20,822,823],{},"如果一个值有 ≥ 2 个使用点，或者有「未来可能改」的可能，就抽出来。否则就地写死。",[10,825,826,827,770],{},"比如「回到首页」这个按钮的文案——它在 404 页和错误页都用，所以放进了 ",[38,828,829],{},"app\u002Fdata\u002Fsystem.ts",[10,831,832,833,836],{},"而 ",[38,834,835],{},"aria-hidden=\"true\""," 这种纯技术属性，就地写，不进配置。",[24,838,839],{"id":839},"怎么验证没漏",[10,841,842,843,846],{},"验收标准里有一条：",[38,844,845],{},"grep -r \"硬编码字符串\" app\u002Fcomponents app\u002Fpages"," 命中为 0。",[10,848,849],{},"我实际跑的命令是：",[31,851,855],{"className":852,"code":853,"language":854,"meta":40,"style":40},"language-bash shiki shiki-themes github-light github-dark","# 找中文字符串（排除注释和 CSS）\ngrep -rn '[\\u4e00-\\u9fa5]' app\u002Fcomponents app\u002Fpages \\\n  --include='*.vue' | grep -v '^\\s*\\*' | grep -v '\u003C!--'\n","bash",[38,856,857,862,882],{"__ignoreMap":40},[52,858,859],{"class":54,"line":55},[52,860,861],{"class":58},"# 找中文字符串（排除注释和 CSS）\n",[52,863,864,867,870,873,876,879],{"class":54,"line":62},[52,865,866],{"class":89},"grep",[52,868,869],{"class":428}," -rn",[52,871,872],{"class":96}," '[\\u4e00-\\u9fa5]'",[52,874,875],{"class":96}," app\u002Fcomponents",[52,877,878],{"class":96}," app\u002Fpages",[52,880,881],{"class":428}," \\\n",[52,883,884,887,890,893,896,899,902,904,906,908],{"class":54,"line":81},[52,885,886],{"class":428},"  --include=",[52,888,889],{"class":96},"'*.vue'",[52,891,892],{"class":243}," |",[52,894,895],{"class":89}," grep",[52,897,898],{"class":428}," -v",[52,900,901],{"class":96}," '^\\s*\\*'",[52,903,892],{"class":243},[52,905,895],{"class":89},[52,907,898],{"class":428},[52,909,910],{"class":96}," '\u003C!--'\n",[10,912,913],{},"第一次跑出来 47 处，其中 41 处是真硬编码，6 处是误报（CSS 注释里的说明文字）。",[10,915,916],{},"改完之后是 0。",[24,918,919],{"id":919},"结论",[357,921,922],{},[10,923,924,925,770],{},"零硬编码不是为了\"代码漂亮\"，是为了",[20,926,927],{},"让配置变更具备原子性",[10,929,930],{},"一个改了会漏的地方，早晚会漏。一个结构上不可能漏的地方，永远不漏。",[10,932,933],{},"这就是架构和整洁的区别。",[935,936,937],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#57606A;--shiki-dark:#9AA4B0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":40,"searchDepth":62,"depth":62,"links":939},[940,941,942,943,944,945,946,947],{"id":26,"depth":62,"text":26},{"id":164,"depth":62,"text":165},{"id":225,"depth":62,"text":226},{"id":348,"depth":62,"text":349},{"id":567,"depth":62,"text":568},{"id":781,"depth":62,"text":781},{"id":839,"depth":62,"text":839},{"id":919,"depth":62,"text":919},"工程",null,"2025-07-10","零硬编码听起来是教条，实践起来是架构约束。这篇讲我怎么用四个配置文件把全站的可变内容抽干净，以及它带来的真实收益。",false,"md",{},"\u002Fposts\u002Fzero-hardcode",{"title":5,"description":951},"posts\u002Fzero-hardcode",[959,960,961],"架构","配置","可维护性","9AG2t8j0DsJnkD8ngRToFXyo5KDPLb1saP7qsgVxqi0",{"prev":964,"next":973},{"path":965,"title":966,"description":967,"date":968,"updated":949,"tags":969,"category":948,"cover":972,"draft":952,"pinned":110,"featured":952},"\u002Fposts\u002Fxml-escaping-stress-test","特殊字符与代码块压测：& \u003C > \" ' 全都要","一篇专门用来喂 RSS\u002FAtom 校验器的文章。正文里塞满了 & \u003C > 引号、CDATA 边界、嵌套代码块和原始 HTML 片段。","2025-10-20",[480,970,971],"XML","测试","\u002Fimages\u002Fcovers\u002Fcharset.png",{"path":974,"title":975,"description":976,"date":977,"updated":949,"tags":978,"category":981,"cover":949,"draft":952,"pinned":952,"featured":952},"\u002Fposts\u002Fslow-writing","慢下来之后我才开始写得下去","追求\"高效写作\"的那几年，我一篇文章都没写完。放弃效率之后，反而写了几十篇。","2025-06-18",[979,980],"写作","反思","随笔",[983,990,998],{"path":984,"title":985,"description":986,"date":987,"updated":949,"tags":988,"category":948,"cover":949,"draft":952,"pinned":952,"featured":952},"\u002Fposts\u002Fdeleted-90-percent","我删掉了站点的 90% 功能","一个博客需要什么？列表、文章、归档、搜索、订阅。其他东西我全删了，然后发现加载时间从 2.3 秒掉到了 380 毫秒。","2025-10-12",[989,959,980],"性能",{"path":991,"title":992,"description":993,"date":994,"updated":949,"tags":995,"category":948,"cover":949,"draft":952,"pinned":952,"featured":952},"\u002Fposts\u002Fstatic-search","静态博客的搜索为什么不用后端","300KB 的索引、一次懒加载、纯前端查询。对一个几百篇文章的博客来说，这个方案比任何搜索引擎都合适。","2025-09-05",[996,959,997],"搜索","SSG",{"path":965,"title":966,"description":967,"date":968,"updated":949,"tags":999,"category":948,"cover":972,"draft":952,"pinned":110,"featured":952},[480,970,971],1794113902301]