<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Lawson_Hui</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://lawsonhui.com/</id>
  <link href="https://lawsonhui.com/" rel="alternate"/>
  <link href="https://lawsonhui.com/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Lawson_Hui</rights>
  <subtitle>记录代码、游戏与日常</subtitle>
  <title>Lawson_Hui的博客</title>
  <updated>2026-10-07T14:10:00.000Z</updated>
  <entry>
    <author>
      <name>Lawson_Hui</name>
    </author>
    <category term="随笔" scheme="https://lawsonhui.com/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="博客" scheme="https://lawsonhui.com/tags/%E5%8D%9A%E5%AE%A2/"/>
    <category term="Hexo" scheme="https://lawsonhui.com/tags/Hexo/"/>
    <category term="开始" scheme="https://lawsonhui.com/tags/%E5%BC%80%E5%A7%8B/"/>
    <content>
      <![CDATA[<p>折腾了很久，终于把这块地方搭起来了。它很轻：没有数据库，没有后端，只有一堆静态文件；它也很吵：背景图每次刷新都会换一张。</p><span id="more"></span><h2 id="为什么是-Hexo"><a href="#为什么是-Hexo" class="headerlink" title="为什么是 Hexo"></a>为什么是 Hexo</h2><p>理由很朴素 —— 我想把注意力放在写字上，而不是维护服务器上。</p><table><thead><tr><th>需求</th><th>Hexo 方案</th></tr></thead><tbody><tr><td>写作</td><td>纯 Markdown，扔进 <code>source/_posts</code> 就好</td></tr><tr><td>部署</td><td>生成静态文件，随便丢给 GitHub Pages</td></tr><tr><td>速度</td><td>没有接口请求，首屏就是 HTML</td></tr><tr><td>成本</td><td>零</td></tr></tbody></table><h2 id="一个最小的构建流程"><a href="#一个最小的构建流程" class="headerlink" title="一个最小的构建流程"></a>一个最小的构建流程</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npm install          <span class="comment"># 装依赖</span></span><br><span class="line">npm run images       <span class="comment"># 增量上传图片到 ImgBB，更新清单</span></span><br><span class="line">npm run build        <span class="comment"># 生成静态站点到 public/</span></span><br><span class="line">npm run publish      <span class="comment"># 一步到位：上传图片 + 构建 + 提交推送</span></span><br></pre></td></tr></table></figure><p>图片走图床的好处很直接：仓库里不会塞进几百 MB 的壁纸，clone 下来依然很快。</p><h2 id="顺手贴一段代码"><a href="#顺手贴一段代码" class="headerlink" title="顺手贴一段代码"></a>顺手贴一段代码</h2><p>写博客总要贴代码，这里验证一下高亮效果。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pathlib <span class="keyword">import</span> Path</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">walk_images</span>(<span class="params">root: Path, exts: <span class="built_in">set</span>[<span class="built_in">str</span>]</span>) -&gt; <span class="built_in">list</span>[Path]:</span><br><span class="line">    <span class="string">&quot;&quot;&quot;列出目录下所有图片，忽略隐藏文件。&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">sorted</span>(</span><br><span class="line">        path</span><br><span class="line">        <span class="keyword">for</span> path <span class="keyword">in</span> root.rglob(<span class="string">&quot;*&quot;</span>)</span><br><span class="line">        <span class="keyword">if</span> path.is_file()</span><br><span class="line">        <span class="keyword">and</span> path.suffix.lower() <span class="keyword">in</span> exts</span><br><span class="line">        <span class="keyword">and</span> <span class="keyword">not</span> path.name.startswith(<span class="string">&quot;.&quot;</span>)</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="keyword">for</span> image <span class="keyword">in</span> walk_images(Path(<span class="string">&quot;img&quot;</span>), &#123;<span class="string">&quot;.png&quot;</span>, <span class="string">&quot;.jpg&quot;</span>, <span class="string">&quot;.webp&quot;</span>&#125;):</span><br><span class="line">        <span class="built_in">print</span>(image)</span><br></pre></td></tr></table></figure><p>Java 也来一段：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">record</span> <span class="title class_">Link</span><span class="params">(String name, String url)</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Link</span> <span class="title function_">of</span><span class="params">(String name, String url)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Link</span>(name, url == <span class="literal">null</span> ? <span class="string">&quot;&quot;</span> : url.trim());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>写下来的东西不一定要给别人看，但一定要给未来的自己看。</p></blockquote><h2 id="图片走图床的样子"><a href="#图片走图床的样子" class="headerlink" title="图片走图床的样子"></a>图片走图床的样子</h2><p>下面这张图并不是塞在仓库里的，而是构建时上传到 ImgBB 之后写进页面的链接 —— 用 <code>imgx</code> 标签引用本地路径即可，构建脚本会自动换成图床地址：</p><figure class="md-figure"><img src="/img/personal_img/bf4c3759123c6a8a93e6a48a8d4fbbf6.JPG" alt="用 imgx 标签引用的图床图片" loading="lazy" decoding="async"><figcaption>用 imgx 标签引用的图床图片</figcaption></figure><h2 id="接下来想写什么"><a href="#接下来想写什么" class="headerlink" title="接下来想写什么"></a>接下来想写什么</h2><ul><li>一些 Python 的小工具，以及踩过的坑</li><li>Minecraft 里自己盖的东西</li><li>Blue Archive 的剧情碎碎念</li><li>用 Claude Code、Codex 这些 Agent 干活的记录</li></ul><p>写博客这件事，最重要的从来不是工具，而是<strong>真的动手写</strong>。</p>]]>
    </content>
    <id>https://lawsonhui.com/2026/10/07/hello-world/</id>
    <link href="https://lawsonhui.com/2026/10/07/hello-world/"/>
    <published>2026-10-07T13:30:00.000Z</published>
    <summary>用 Hexo 搭起自己的小站，写下第一行字。</summary>
    <title>Hello World：我的第一篇博客</title>
    <updated>2026-10-07T14:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Lawson_Hui</name>
    </author>
    <category term="折腾" scheme="https://lawsonhui.com/categories/%E6%8A%98%E8%85%BE/"/>
    <category term="Hexo" scheme="https://lawsonhui.com/tags/Hexo/"/>
    <category term="ImgBB" scheme="https://lawsonhui.com/tags/ImgBB/"/>
    <category term="自动化" scheme="https://lawsonhui.com/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    <category term="Node.js" scheme="https://lawsonhui.com/tags/Node-js/"/>
    <content>
      <![CDATA[<p>GitHub 对「仓库里全是图片」的项目不太友好，体积大、clone 慢，还容易被当成图床。这个站点把所有图片都放在本地 <code>img/</code> 目录（已被 <code>.gitignore</code> 排除），构建时再增量上传到 ImgBB。</p><span id="more"></span><h2 id="增量上传是怎么做的"><a href="#增量上传是怎么做的" class="headerlink" title="增量上传是怎么做的"></a>增量上传是怎么做的</h2><p>核心是一个清单文件 <code>tools/image-manifest.json</code>，它以「相对路径」为键，记录图片的内容哈希和上传后的链接：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;img/bg_img/theme_ba/pc/139649.webp&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;sha256&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0f3c…&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;url&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://i.ibb.co/xxxx/139649.webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;thumb&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://i.ibb.co/xxxx/139649.webp&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;uploadedAt&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2026-10-06T12:00:00.000Z&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>于是上传逻辑就变成三句话：</p><ol><li>扫描 <code>img/</code> 下的所有图片，算出 sha256；</li><li>清单里有相同哈希 → 直接跳过；文件变了或没记录 → 上传；</li><li>上传完校验一次链接是否可访问，坏掉的条目从清单里删掉，下次自动重传。</li></ol><h2 id="页面是怎么拿到链接的"><a href="#页面是怎么拿到链接的" class="headerlink" title="页面是怎么拿到链接的"></a>页面是怎么拿到链接的</h2><p>构建阶段，Hexo 脚本读取清单，把每个皮肤、每种设备的背景图整理成一个数组塞进页面：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// scripts/lib/image-index.js（节选）</span></span><br><span class="line"><span class="keyword">const</span> entry = manifest.<span class="property">images</span>[relPath];</span><br><span class="line"><span class="keyword">if</span> (entry &amp;&amp; entry.<span class="property">url</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123; <span class="attr">path</span>: relPath, <span class="attr">url</span>: entry.<span class="property">url</span>, <span class="attr">uploaded</span>: <span class="literal">true</span> &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 没传过也不怕：退化成本地路径，构建收尾会把文件复制进 public/</span></span><br><span class="line"><span class="keyword">return</span> &#123; <span class="attr">path</span>: relPath, <span class="attr">url</span>: <span class="title function_">encodeLocalPath</span>(relPath), <span class="attr">uploaded</span>: <span class="literal">false</span> &#125;;</span><br></pre></td></tr></table></figure><p>这样即使某次上传失败、或者你刚 clone 完还没有图片，站点也不会出现空白背景或坏图。</p><h2 id="上传失败怎么办"><a href="#上传失败怎么办" class="headerlink" title="上传失败怎么办"></a>上传失败怎么办</h2><p>脚本带了三层保险：</p><ul><li>网络错误与 429&#x2F;5xx 会指数退避重试；</li><li>单张失败不影响其它图片，重新执行一次即可续传；</li><li><code>npm run verify</code> 可以单独体检所有链接，<code>--fix</code> 会把坏链接标记为待重传。</li></ul><blockquote><p>静态站点最大的好处是：构建产物就是最终产物。只要构建时确认链接可用，上线之后就不会有「图片加载失败」这种意外。</p></blockquote><h2 id="顺手记一下命令"><a href="#顺手记一下命令" class="headerlink" title="顺手记一下命令"></a>顺手记一下命令</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">node tools/upload-images.mjs --dry-run    <span class="comment"># 只看这次会上传哪些</span></span><br><span class="line">node tools/upload-images.mjs --<span class="built_in">limit</span>=5    <span class="comment"># 先试传 5 张</span></span><br><span class="line">node tools/upload-images.mjs --force      <span class="comment"># 忽略缓存全部重传</span></span><br><span class="line">node tools/verify-images.mjs --fix        <span class="comment"># 体检 + 标记坏链接</span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://lawsonhui.com/2026/10/06/hexo-imgbb-pipeline/</id>
    <link href="https://lawsonhui.com/2026/10/06/hexo-imgbb-pipeline/"/>
    <published>2026-10-06T12:15:00.000Z</published>
    <summary>仓库里不放图片，构建时把图片增量丢给图床，再把链接写回页面。</summary>
    <title>让静态博客不丢图：Hexo + ImgBB 增量上传方案</title>
    <updated>2026-10-06T16:27:25.355Z</updated>
  </entry>
</feed>
