<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>XiaoMo · 博客</title><description>XiaoMo 的个人主页：文章、小游戏与在线工具。</description><link>https://www.moiu.cn/</link><language>zh-CN</language><item><title>把一座 Three.js 浮岛搬进静态站</title><link>https://www.moiu.cn/zh/blog/aether-isle/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/aether-isle/</guid><description>浮岛页只下载自己那一份脚本。场景在运行时现算，Three.js 与整个三维世界都留在这一页的 chunk 里，首屏 HTML 里只有一个空舞台。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>建站</category><category>Astro</category><category>性能</category><category>设计</category></item><item><title>摩斯电码：一张表、两处歧义、三个实现细节</title><link>https://www.moiu.cn/zh/blog/morse-code/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/morse-code/</guid><description>摩斯电码本身很简单，麻烦都在细节里：点划的空格归属、全角符号的归一化，以及「一个单位」到底有多长。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>工具</category><category>算法</category></item><item><title>让弹球对手会算落点，但算不太准</title><link>https://www.moiu.cn/zh/blog/pong-ai/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/pong-ai/</guid><description>一个能打赢的 Pong 对手需要两件事：把球的落点算准，再故意算错一点。前者用三角波一次算完，后者每次接球重抽一个偏差。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>游戏</category><category>算法</category></item><item><title>不建模也能有体积：手工三角化一座浮岛</title><link>https://www.moiu.cn/zh/blog/procedural-island/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/procedural-island/</guid><description>岛上的岩石不是从建模软件导出的，是五层不规则环带在运行时拼出来的。顶点色加平面着色，就足够让一块几何体看起来像被凿开的石头。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>建站</category><category>设计</category></item><item><title>一千二百个实例：把花园压进几次绘制</title><link>https://www.moiu.cn/zh/blog/three-instancing/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/three-instancing/</guid><description>草叶六百、花一百二、苔石八十五、灌木四十二 —— 花园的密度不靠减数量，靠 InstancedMesh 把同一种东西合并成一次绘制。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>性能</category><category>建站</category></item><item><title>一个场景的光：三种灯与只算一次的阴影</title><link>https://www.moiu.cn/zh/blog/three-lighting/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/three-lighting/</guid><description>半球光给环境色，主光给方向与阴影，轮廓光把岛从背景里拉出来；其余六个灯笼只是点光。阴影贴图只算一次，因为它照的东西一动不动。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>设计</category><category>建站</category></item><item><title>两个着色器做水：水洼、溪流与瀑布</title><link>https://www.moiu.cn/zh/blog/three-water-shader/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/three-water-shader/</guid><description>岛上没有水面模拟，也没有反射。两个 ShaderMaterial 分别负责平躺的水与竖直落下的水，共用一组 time 与 night 变量。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>建站</category><category>设计</category></item><item><title>3D 的加载预算：分包、可见才加载、以及什么时候该停下</title><link>https://www.moiu.cn/zh/blog/webgl-loading-budget/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/webgl-loading-budget/</guid><description>一个 3D 页面有三笔成本 —— 下载、首帧编译、每帧绘制。三笔都要单独设预算，任何一笔失控都会让「好看」变成「卡」。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><category>性能</category><category>建站</category><category>Astro</category></item><item><title>原子写文件：先写临时文件，再 rename</title><link>https://www.moiu.cn/zh/blog/atomic-write/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/atomic-write/</guid><description>直接覆写会在断电、崩溃、并发读的那一刻留下半个文件。临时文件加 rename 借文件系统的原子性把「半个文件」变成不可能。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>工具</category></item><item><title>Base64：它不是加密，也不是压缩</title><link>https://www.moiu.cn/zh/blog/base64/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/base64/</guid><description>Base64 把 3 字节编码成 4 个可打印字符，体积涨三分之一。它解决的是「二进制不能安全穿过文本通道」，不是保密。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>安全</category></item><item><title>大 O 的误用：常数和前提比阶更常决定成败</title><link>https://www.moiu.cn/zh/blog/big-o-misconception/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/big-o-misconception/</guid><description>O(n log n) 的排序可能慢过 O(n²) 的插入排序，O(1) 的哈希表可能慢过数组线性扫。判断性能前先确认输入规模、常数和内存局部性。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>性能</category></item><item><title>用 @layer 把样式优先级从「比权重」变成「排顺序」</title><link>https://www.moiu.cn/zh/blog/css-cascade-layers/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/css-cascade-layers/</guid><description>样式失控的根源不是选择器写得不够具体，而是所有人都靠加权重解决问题。级联层让顺序显式化：层与层之间比顺序，层内部才比特异性。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category></item><item><title>防抖与节流：差别只在「谁决定何时执行」</title><link>https://www.moiu.cn/zh/blog/debounce-throttle/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/debounce-throttle/</guid><description>两者都是限流，区别是防抖由最后一次调用决定执行时刻，节流由固定时间窗决定。选错的典型症状是拖拽跟手但松手才更新，或者输入框该等却每 200ms 就发一次。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>性能</category></item><item><title>工期估算：为什么「大概三天」永远变成三周</title><link>https://www.moiu.cn/zh/blog/developer-estimation/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/developer-estimation/</guid><description>估的是「写代码」的时间，交出去的是「写代码 + 联调 + 评审 + 改需求 + 等别人」的时间。把不确定的部分显式列出来，比把天数乘二更有效。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>后端</category></item><item><title>功能开关：它是负债，不是配置</title><link>https://www.moiu.cn/zh/blog/feature-flags/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/feature-flags/</guid><description>每个开关都会让代码路径翻倍，而开关本身永远不会被删。给每个开关定一个移除日期，比设计一套精巧的开关系统重要得多。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>工具</category></item><item><title>游戏主循环：为什么必须用 delta time</title><link>https://www.moiu.cn/zh/blog/game-loop/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/game-loop/</guid><description>每帧固定移动 5 像素，在 60Hz 屏幕上快一倍、在 144Hz 上快两倍半。把时间差乘进去，物理才与刷新率解耦；再加一个上限，切标签页回来才不会瞬移。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>游戏</category><category>性能</category></item><item><title>git bisect：把「哪次提交弄坏的」变成一条命令</title><link>https://www.moiu.cn/zh/blog/git-bisect/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/git-bisect/</guid><description>回归排查的瓶颈不是二分本身，而是没人说得出「什么样的提交算坏」。先写出能自动判定的脚本，bisect 才能把 n 次构建压到 log n 次。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>算法</category></item><item><title>五子棋 AI：算杀层与搜索层怎么分工</title><link>https://www.moiu.cn/zh/blog/gomoku-search-engine/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/gomoku-search-engine/</guid><description>纯 alpha-beta 在五子棋上会漏掉必杀。我把决策拆成三层——成五、堵五、算杀各司其职，剩下的才交给迭代加深加置换表，快棋也能下出像样的棋。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>优雅关闭：进程退出方式决定用户看到 502 还是正常响应</title><link>https://www.moiu.cn/zh/blog/graceful-shutdown/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/graceful-shutdown/</guid><description>收到终止信号立刻 exit 会切断在途请求。正确顺序是停止接收新连接、等在途请求跑完、再释放资源、最后退出。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>建站</category></item><item><title>HTTP 缓存：Cache-Control 与 ETag 各管一半</title><link>https://www.moiu.cn/zh/blog/http-caching/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/http-caching/</guid><description>Cache-Control 决定「要不要发请求」，ETag 决定「发出去之后能不能省下响应体」。把两者混谈是缓存问题的根源：改一个参数不会同时修好两侧。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>性能</category></item><item><title>幂等键：让重试变得安全的那一次写入</title><link>https://www.moiu.cn/zh/blog/idempotency/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/idempotency/</guid><description>网络超时不代表服务端没执行。幂等键把「同一个请求」标识出来，服务端据此返回首次结果而不是再执行一遍。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>安全</category></item><item><title>JSON 规范化：为什么同样的对象算出了两个哈希</title><link>https://www.moiu.cn/zh/blog/json-canonicalization/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/json-canonicalization/</guid><description>键的顺序、数字写法、转义方式都会改变字节流。要让哈希稳定，必须在序列化这一层定死规则，而不是指望 JSON.stringify 每次都给你同一串。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>安全</category></item><item><title>内存布局：同样的算法，慢十倍往往是因为缓存</title><link>https://www.moiu.cn/zh/blog/memory-layout/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/memory-layout/</guid><description>CPU 取一次内存要几百个周期，取整个缓存行只要一次。顺序访问与随机访问的差别往往大过算法阶数。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>性能</category><category>算法</category></item><item><title>死锁的四个条件：破坏其中任意一个就够了</title><link>https://www.moiu.cn/zh/blog/mutex-deadlock/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/mutex-deadlock/</guid><description>互斥、持有并等待、不可抢占、循环等待——四个同时成立才会死锁。工程上最容易破坏的是循环等待：全局给锁定一个顺序。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>算法</category></item><item><title>N+1 查询：ORM 最典型的性能陷阱</title><link>https://www.moiu.cn/zh/blog/n-plus-one/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/n-plus-one/</guid><description>取 100 条记录再逐条查关联，就是 101 次查询。修法只有三种：预加载、批量查、或者干脆用一次 JOIN。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>性能</category></item><item><title>限流：令牌桶与漏桶的实际差别</title><link>https://www.moiu.cn/zh/blog/rate-limiting/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/rate-limiting/</guid><description>令牌桶允许突发，漏桶把流量削成恒定速率。选错的典型症状是正常用户被限、或者限流形同虚设，取决于你的下游能不能吃突发。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>性能</category></item><item><title>灾难性回溯：正则为什么会让 CPU 打满</title><link>https://www.moiu.cn/zh/blog/regex-catastrophic/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/regex-catastrophic/</guid><description>嵌套量词让匹配尝试数指数增长，(a+)+b 在一条长的不匹配输入上就能拖死进程。修法是去掉嵌套量词或给正则加超时。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>算法</category></item><item><title>iframe sandbox：它收窄能力，不是加固</title><link>https://www.moiu.cn/zh/blog/sandbox-iframe/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/sandbox-iframe/</guid><description>sandbox 属性默认剥夺一切能力，靠 allow-* 逐项放回。弄反方向是常见错误：加上 sandbox 之后脚本全不能跑了，因为那是默认值。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>建站</category></item><item><title>语义化版本：主版本号的承诺是「不会静默改变行为」</title><link>https://www.moiu.cn/zh/blog/semver/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/semver/</guid><description>MAJOR 不是「改动很大」，而是「有破坏性变更」。把重构当主版本号、把破坏性变更藏在次版本号，都会让下游的自动升级变成事故。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>建站</category></item><item><title>SQLite 索引：最左前缀不是限制，是排序的结果</title><link>https://www.moiu.cn/zh/blog/sqlite-index/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/sqlite-index/</guid><description>复合索引 (a, b) 只有先按 a 排才能按 b 排，所以「跳过 a 只用 b」自然用不上。理解成排序而非规则，就不会再背前缀口诀。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>算法</category></item><item><title>技术债的利息长什么样</title><link>https://www.moiu.cn/zh/blog/tech-debt-interest/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tech-debt-interest/</guid><description>技术债不是「代码写得丑」，而是「以后每次改动都要多付的那部分」。判断标准是可测量的：改一行要动几个文件、跑多久测试、有几处需要同时改。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>工具</category></item><item><title>时区与夏令时：存 UTC，存本地时间一定会出事</title><link>https://www.moiu.cn/zh/blog/timezone-dst/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/timezone-dst/</guid><description>夏令时会让某一天有 23 或 25 小时，且切换时刻的本地时间可能不存在或出现两次。只存 UTC 时间戳，展示时再转，是唯一稳的模型。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>后端</category><category>算法</category></item><item><title>把 AI 的思考过程做成一棵能翻的树</title><link>https://www.moiu.cn/zh/blog/tool-tree/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-tree/</guid><description>给搜索过程做可视化，难点不在画树，而在数据要是真的、面板不能把棋盘顶来顶去、以及它得按需加载不拖累不点它的人。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>Vue</category><category>游戏</category></item><item><title>Unicode 规范化：看起来一样的两个字符串为什么不相等</title><link>https://www.moiu.cn/zh/blog/unicode-normalization/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/unicode-normalization/</guid><description>é 可以是一个码点，也可以是 e 加组合重音。比较、存储、索引之前先统一成 NFC，否则同形异码会让查重和登录全部失效。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>后端</category></item><item><title>URL 编码的三个陷阱：空格、加号与双重编码</title><link>https://www.moiu.cn/zh/blog/url-encoding/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/url-encoding/</guid><description>查询串里的 + 是空格，路径里的 + 是加号；同一个字符在路径与查询里的编码规则不同；编码两次会得到看似正常却永远匹配不上的值。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>安全</category></item><item><title>写中国象棋规则，四处最容易错的地方</title><link>https://www.moiu.cn/zh/blog/xiangqi-rules/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/xiangqi-rules/</guid><description>蹩马腿、塞象眼、炮打隔子、将帅照面。我把走法生成拆成几何层与合法性层，前者只管兵种怎么走，后者统一兜住送将，四处坑各配了断言。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>手写 cron 解析器：五段、并集规则，以及 2 月 30 日</title><link>https://www.moiu.cn/zh/blog/cron-parser/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cron-parser/</guid><description>cron 的语法半小时能写完，难的是语义：日与星期同时限定时是并集而非交集，不存在的时间要有终止条件，7 与 0 都是星期天。</description><pubDate>Tue, 29 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>算法</category></item><item><title>CSV 不是「按逗号切」：RFC 4180 的引号与换行</title><link>https://www.moiu.cn/zh/blog/csv-rfc4180/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/csv-rfc4180/</guid><description>一旦字段里有引号，split 立刻出错：引号能包住逗号和换行，引号自己写成两个。三十行状态机比任何正则都可靠。</description><pubDate>Tue, 29 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>算法</category></item><item><title>黑白棋的合法落点：一次扫描，八个方向</title><link>https://www.moiu.cn/zh/blog/reversi-legal-moves/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/reversi-legal-moves/</guid><description>一个空位合法，当且仅当八个方向里至少有一个方向能夹住对方的棋子。判断与翻转用的是同一次扫描，不必先模拟再回滚。</description><pubDate>Tue, 29 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>数独生成器：挖洞、唯一解，以及一个把页面卡死的 bug</title><link>https://www.moiu.cn/zh/blog/sudoku-generator/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/sudoku-generator/</guid><description>生成器先填一个完整解，再逐格挖洞并验证唯一性。我在求解器里把「不限」写成 0，结果空盘要枚举全部解，点新局直接卡死。</description><pubDate>Tue, 29 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>一致性哈希：加一台机器为什么不用重排所有键</title><link>https://www.moiu.cn/zh/blog/consistent-hashing/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/consistent-hashing/</guid><description>取模分片在机器数变化时几乎搬走全部数据。把哈希空间首尾相接成一个环，键归顺时针第一台机器，加节点只影响一段区间 —— 代价是需要虚拟节点。</description><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>建站</category></item><item><title>五子棋的胜负判定：只查刚落下的那一点就够</title><link>https://www.moiu.cn/zh/blog/gomoku-win-detect/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/gomoku-win-detect/</guid><description>每次落子后全盘扫描是浪费：胜负只可能因为最新一手而改变。沿四个方向从落子点向两侧延伸计数，判定成本与棋盘大小无关。</description><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>滑动窗口：先定「窗口里维护什么」，再写循环</title><link>https://www.moiu.cn/zh/blog/sliding-window/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/sliding-window/</guid><description>窗口能成立的前提是「窗口是否合法」随左右边界单调。先写下维护的状态与收缩条件，双指针的两层循环自然会摊还成 O(n)。</description><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>性能</category></item><item><title>单调栈：把「下一个更大的数」从 O(n²) 拉回 O(n)</title><link>https://www.moiu.cn/zh/blog/monotonic-stack/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/monotonic-stack/</guid><description>每个元素最多进栈一次、出栈一次，所以看起来是双层循环的写法其实是线性。认出「左右第一个比自己大/小」这个形状，就能套同一个模板。</description><pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>性能</category></item><item><title>数二进制里有多少个 1：从循环到 SWAR</title><link>https://www.moiu.cn/zh/blog/popcount-bit-tricks/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/popcount-bit-tricks/</guid><description>popcount 有三种写法：按 1 的个数循环、查表、以及并行算位的 SWAR。三种复杂度差一个数量级，而 Rust 与 WebAssembly 已经把它做成了单条指令。</description><pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>性能</category></item><item><title>并查集：两行优化让每次操作几乎变成常数</title><link>https://www.moiu.cn/zh/blog/union-find/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/union-find/</guid><description>路径压缩把树压平，按大小合并让树不会长高。两个都要，复杂度才落到反阿克曼函数上 —— 也就是说 10 亿次操作也不会慢。</description><pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>性能</category></item><item><title>Rust 的 Result 里，上下文要补在出错的那一层</title><link>https://www.moiu.cn/zh/blog/rust-result-context/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/rust-result-context/</guid><description>`?` 会把错误原样上抛，不告诉你在哪一步失败。底层返回可匹配的结构化错误，应用层用 Context 补上「在做什么」和输入参数，日志里才有能定位的那一行。</description><pubDate>Sat, 26 Sep 2026 00:00:00 GMT</pubDate><category>Rust</category><category>后端</category></item><item><title>什么时候该把一个 crate 拆成 workspace</title><link>https://www.moiu.cn/zh/blog/rust-workspace-split/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/rust-workspace-split/</guid><description>拆 workspace 的触发条件是编译时间和依赖边界，不是目录好不好看。三个信号成立才拆，否则只是把一次编译换成多个包的管理成本。</description><pubDate>Sat, 26 Sep 2026 00:00:00 GMT</pubDate><category>Rust</category><category>后端</category></item><item><title>结构化日志不是把 println 换成 tracing::info</title><link>https://www.moiu.cn/zh/blog/tracing-structured-logs/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tracing-structured-logs/</guid><description>拼接字符串的日志只能被人眼读，带字段的日志才能被查询和聚合。字段、span、级别、以及别在热点路径上格式化，是四个真正要做的决定。</description><pubDate>Sat, 26 Sep 2026 00:00:00 GMT</pubDate><category>Rust</category><category>后端</category></item><item><title>Islands 不是 Web Components：两种「按需加载」根本不是一回事</title><link>https://www.moiu.cn/zh/blog/islands-vs-webcomponents/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/islands-vs-webcomponents/</guid><description>Islands 在构建期决定哪里需要 JS、什么时候水合；Web Components 在运行时给浏览器一个自带行为的元素。把它们当成同一件事，会选错工具。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate><category>Astro</category><category>性能</category></item><item><title>静态站的缓存头：带哈希的永久，HTML 一律不缓存</title><link>https://www.moiu.cn/zh/blog/nginx-cache-headers/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/nginx-cache-headers/</guid><description>缓存策略只取决于文件名是否随内容变化，与文件大小无关。HTML 长缓存会让用户拿到旧入口、指向已删除的旧 chunk，是静态站最常见的线上白屏。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>性能</category></item><item><title>WebAssembly 值得用的场合，比宣传里少得多</title><link>https://www.moiu.cn/zh/blog/wasm-where-to-use/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/wasm-where-to-use/</guid><description>WASM 的收益来自「计算密集 + 大批量数据 + 少的跨界调用」。把一个 O(n) 的 JS 循环改写成 WASM，通常只会得到更慢的加载和更难调的栈。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate><category>性能</category><category>建站</category></item><item><title>锚点跳转被页头吃掉：一次 scroll-padding-top 修全站</title><link>https://www.moiu.cn/zh/blog/anchor-scroll-padding/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/anchor-scroll-padding/</guid><description>吸顶页头会盖住锚点目标，逐个标题写 scroll-margin 迟早漏。正确的位置是滚动容器上的 scroll-padding-top，再用 ResizeObserver 把真实页头高度写回令牌。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category></item><item><title>模态框用原生 dialog：白拿的东西比想象中多</title><link>https://www.moiu.cn/zh/blog/dialog-a11y/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/dialog-a11y/</guid><description>自己搭模态要手写焦点陷阱、ESC、滚动锁与返回焦点。原生 dialog 配 showModal 全部内置，还能用 ::backdrop，代价只有一条样式继承规则。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category></item><item><title>深色模式下表单还是白的：color-scheme 才是开关</title><link>https://www.moiu.cn/zh/blog/form-color-scheme/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/form-color-scheme/</guid><description>把背景涂黑不等于原生控件跟着黑。select 的下拉、日期选择器、自动填充的底色都由 color-scheme 决定，accent-color 只管住勾选框与滑块。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category></item><item><title>页头多高不该猜：ResizeObserver 实测回写 CSS 变量</title><link>https://www.moiu.cn/zh/blog/resize-observer-layout/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/resize-observer-layout/</guid><description>导航换行、字体晚到、内容长度变化都会让元素高度和 CSS 里的常量对不上。ResizeObserver 观察元素本身，把实测值写回变量，比监听 resize 可靠。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>性能</category></item><item><title>设计令牌：一个文件管住整个站点</title><link>https://www.moiu.cn/zh/blog/design-tokens/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/design-tokens/</guid><description>为什么我把颜色、间距、圆角全部收进 _tokens.scss，以及换一套视觉方向为什么只需要改这一个文件。</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category></item><item><title>不用框架的 i18n：三语站点手写路由的代价</title><link>https://www.moiu.cn/zh/blog/manual-i18n/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/manual-i18n/</guid><description>这个站点的手写 i18n 没用框架自带的配置。说说为什么，以及代价具体出现在哪里——两次 404，和一半没翻的文章。</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>设计</category></item><item><title>2048：把四个方向归一成同一个操作</title><link>https://www.moiu.cn/zh/blog/algo-2048/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/algo-2048/</guid><description>滑动、合并、计分只需要写一遍，其余三个方向靠转置与反转复用。真正的难点是「每个方块一回合只能合并一次」，写错就得到不该出现的数字。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>扫雷：把布雷推迟到第一次点击</title><link>https://www.moiu.cn/zh/blog/algo-minesweeper/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/algo-minesweeper/</guid><description>第一下就踩雷的扫雷是没写完的扫雷。把布雷推迟到首次点击、并排除点击点周围 3×3，是这类实现最重要的一处设计。</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate><category>算法</category><category>游戏</category></item><item><title>把孔版套印的约束翻译成设计令牌</title><link>https://www.moiu.cn/zh/blog/riso-ui/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/riso-ui/</guid><description>这个站点的视觉方向是孔版套印。我真正做的事是把印刷的物理限制写成令牌，于是换观感只动了两个文件，组件一行没改。</description><pubDate>Fri, 18 Sep 2026 00:00:00 GMT</pubDate><category>设计</category><category>CSS</category></item><item><title>进制与单位换算：唯一非线性的是温度</title><link>https://www.moiu.cn/zh/blog/tool-convert/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-convert/</guid><description>2 到 36 任意进制互转要用 BigInt 兜住精度；十类单位换算中前九类是线性比例，唯独温度是仿射变换，写成一个倍率就一定会错。</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>Vue</category></item><item><title>颜色与对比度：相对亮度不是通道平均值</title><link>https://www.moiu.cn/zh/blog/tool-color/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-color/</guid><description>三种记法互转只是入口，真正容易写错的是 WCAG 对比度：先做 gamma 还原再加权求和。以及「这上面该用黑字还是白字」为什么不能看亮度是否大于 128。</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>Vue</category></item><item><title>纯静态站的全文搜索：构建期索引，运行时零后端</title><link>https://www.moiu.cn/zh/blog/pagefind-search/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/pagefind-search/</guid><description>静态站做搜索不一定非得接 Algolia。把索引放到构建期生成，搜索完全跑在浏览器里，代价只有构建慢几秒。</description><pubDate>Mon, 14 Sep 2026 00:00:00 GMT</pubDate><category>建站</category><category>性能</category></item><item><title>哈希与校验和：为什么 CRC32 和 MD5 得自己写</title><link>https://www.moiu.cn/zh/blog/tool-hash/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-hash/</guid><description>浏览器只在安全上下文提供 SHA 系列，CRC32 与 MD5 不在 Web Crypto 里。顺带解决大文件不该一次读进内存，以及校验值不该靠人眼比对。</description><pubDate>Sun, 13 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>Vue</category></item><item><title>正则测试：命中、分组与替换预览，以及零宽匹配的坑</title><link>https://www.moiu.cn/zh/blog/tool-regex-lab/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-regex-lab/</guid><description>自己写一个正则测试页要处理三件事：把命中位置和分组讲清楚、把替换结果先预览出来、以及别让零宽匹配把页面卡死。</description><pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>Vue</category></item><item><title>JSON 工作台：格式化、校验与结构对比放在同一个页面</title><link>https://www.moiu.cn/zh/blog/tool-json-studio/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/tool-json-studio/</guid><description>从反复在终端写临时命令洗 JSON 的经历出发，做一个只在浏览器里运行的工作台：格式化、压缩、排序、带行列的错误定位，以及两份 JSON 的结构差异。</description><pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate><category>工具</category><category>Vue</category></item><item><title>1059 项断言，零测试框架：纯逻辑必须零 import</title><link>https://www.moiu.cn/zh/blog/zero-import-selftest/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/zero-import-selftest/</guid><description>我的自检是 node scripts/selftest.ts 直接跑的，没有测试框架也没有依赖。代价是纯逻辑模块一个相对 import 都不能有，而这个代价换来了代码形状。</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate><category>Astro</category><category>建站</category></item><item><title>SharePoint 反序列化 RCE：CVE-2026-45659 分析</title><link>https://www.moiu.cn/zh/blog/cve-2026-45659-sharepoint/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cve-2026-45659-sharepoint/</guid><description>一个普通 Site Member 账户就足以在 SharePoint 服务器上执行任意代码。微软最初判定「利用可能性较低」，CISA 依据在野证据把它拉进了 KEV，并要求三天内完成修复。</description><pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>漏洞分析</category></item><item><title>n8n 未授权 RCE（Ni8mare）：CVE-2026-21858 分析</title><link>https://www.moiu.cn/zh/blog/cve-2026-21858-n8n/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cve-2026-21858-n8n/</guid><description>表单节点跳过了对 Content-Type 的验证，于是一个 application/json 请求就能让它去读任意文件。读出配置里的密钥后可伪造管理员 JWT，再借沙箱绕过完成 RCE。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>漏洞分析</category></item><item><title>Cisco FMC 未授权 Java 反序列化 RCE：CVE-2026-20131 分析</title><link>https://www.moiu.cn/zh/blog/cve-2026-20131-cisco-fmc/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cve-2026-20131-cisco-fmc/</guid><description>CVSS 10.0、无需认证、以 root 权限执行代码，而且已经被勒索组织当作零日用了 36 天。防火墙管理中枢本身被攻破，等于把所有策略与日志一起交出去。</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><category>安全</category><category>漏洞分析</category></item><item><title>用 Astro islands 把首屏 JS 压到零</title><link>https://www.moiu.cn/zh/blog/astro-islands/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/astro-islands/</guid><description>从「异步引入」到「按需水合」，讲清楚三层懒加载分别解决什么问题，并给出这个站点里真实在跑的代码。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate><category>Astro</category><category>性能</category><category>Vue</category></item><item><title>Next.js 增量缓存路径遍历 RCE：CVE-2026-75604 分析</title><link>https://www.moiu.cn/zh/blog/cve-2026-75604-nextjs/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cve-2026-75604-nextjs/</guid><description>一个没被转义的反斜杠，在 Windows 上把增量缓存变成任意文件读写；再用泄露的 Server Action 加密密钥伪造请求，借 React Flight 的属性链走到 Function。</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate><category>安全</category><category>漏洞分析</category></item><item><title>React Router 原型污染链式 RCE：CVE-2026-42211 分析</title><link>https://www.moiu.cn/zh/blog/cve-2026-42211-react-router/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/cve-2026-42211-react-router/</guid><description>turbo-stream v2 在 TYPE_ERROR 分支里动态调用构造函数却不校验来源。只要应用里已存在一个原型污染，这条路径就能被接上 Function，把两步中危拼成 RCE。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><category>安全</category><category>漏洞分析</category></item><item><title>head 只有一个来源：SiteHead、JSON-LD 转义与 hreflang</title><link>https://www.moiu.cn/zh/blog/head-single-source/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/head-single-source/</guid><description>三个 HTML 外壳共用一个组件输出全部 head 标签，数据在 server 层组装。以及一个必须记住的细节：JSON-LD 里的尖括号要转义成反斜杠 u003c。</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate><category>建站</category><category>性能</category></item><item><title>静态站上线不是「把文件夹传上去」：缓存、压缩、以及诚实的 404</title><link>https://www.moiu.cn/zh/blog/static-hosting-nginx/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/static-hosting-nginx/</guid><description>纯静态托管的坑几乎全在响应头上。哪些文件能永久缓存、哪些一秒都不能缓存、以及为什么静态站绝对不能做 SPA 式回退。</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate><category>建站</category><category>性能</category></item><item><title>用 View Transitions 做主题切换水波纹</title><link>https://www.moiu.cn/zh/blog/theme-ripple/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/theme-ripple/</guid><description>主题切换时用一个从点击点扩散的圆揭示新主题。半径要够到屏幕最远的角，动画结束必须清掉自定义属性，否则会污染下一次。</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate><category>CSS</category><category>设计</category><category>Vue</category></item><item><title>构建期分页：静态站的翻页为什么不该用查询参数</title><link>https://www.moiu.cn/zh/blog/build-time-pagination/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/build-time-pagination/</guid><description>列表分页在构建时切成静态页，第 N 页是一个真实路由。没有客户端分页逻辑，也不用查询串，翻页就是纯链接跳转。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate><category>Astro</category><category>性能</category></item><item><title>@/ 别名的三处配置：Vite、TypeScript 与 SCSS 缺一不可</title><link>https://www.moiu.cn/zh/blog/alias-three-places/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/alias-three-places/</guid><description>全项目禁用深层相对引入，代价是别名要在三个地方各配一次。少配一处，症状分别是编辑器报错、构建失败、样式静默丢失。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate><category>Astro</category><category>建站</category></item><item><title>zod 做 frontmatter 契约：把文章格式变成构建期错误</title><link>https://www.moiu.cn/zh/blog/zod-frontmatter/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/zod-frontmatter/</guid><description>Content Collections 的 schema 是唯一真相。标题超 120 字、日期写错、标签写成字符串，都在构建期直接失败，而不是线上少一页。</description><pubDate>Thu, 13 Aug 2026 00:00:00 GMT</pubDate><category>Astro</category><category>建站</category></item><item><title>为什么我又搭了一个个人主页</title><link>https://www.moiu.cn/zh/blog/hello-world/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/hello-world/</guid><description>不是没有地方写东西，而是没有一个地方能同时放文章、小游戏和工具。顺便说说这次的技术选型为什么是 Astro 而不是 VitePress。</description><pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate><category>建站</category><category>Astro</category></item><item><title>零配置注册表：新增一个游戏等于新建一个目录</title><link>https://www.moiu.cn/zh/blog/glob-registry/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/glob-registry/</guid><description>列表、详情路由、首页精选、sitemap 全部由 import.meta.glob 自动发现。代价是必须接受「字面量相对路径」这条 Vite 的硬规则。</description><pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate><category>Astro</category><category>建站</category></item><item><title>应用页不用 client:only：静态空壳加显式挂载</title><link>https://www.moiu.cn/zh/blog/app-shell-mount/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/app-shell-mount/</guid><description>游戏与工具页是「空壳 + createApp」，不是 client:only。加载、成功、失败三态由我自己控制，重试按钮也是真的能按。</description><pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate><category>Vue</category><category>性能</category></item><item><title>视图不存逻辑：把数据装配全部收进 src/server</title><link>https://www.moiu.cn/zh/blog/server-layer/</link><guid isPermaLink="true">https://www.moiu.cn/zh/blog/server-layer/</guid><description>页面里只剩路由导出与组件引入，取数、拼路径、算日期全部移到 src/server。说说这么分的收益，以及它逼出来的一个类型约束。</description><pubDate>Sun, 02 Aug 2026 00:00:00 GMT</pubDate><category>Astro</category><category>建站</category></item></channel></rss>