<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Jerome Xiong</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <icon>https://jeromexiong.github.io/images/avatar.png</icon>
  <id>https://jeromexiong.github.io/</id>
  <link href="https://jeromexiong.github.io/" rel="alternate"/>
  <link href="https://jeromexiong.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Jerome Xiong</rights>
  <subtitle>Jerome Xiong 的个人博客</subtitle>
  <title>Jerome Xiong</title>
  <updated>2026-06-16T08:17:05.715Z</updated>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="Git" scheme="https://jeromexiong.github.io/categories/%E5%B7%A5%E5%85%B7/Git/"/>
    <category term="Git" scheme="https://jeromexiong.github.io/tags/Git/"/>
    <category term="规范" scheme="https://jeromexiong.github.io/tags/%E8%A7%84%E8%8C%83/"/>
    <category term="约定式提交" scheme="https://jeromexiong.github.io/tags/%E7%BA%A6%E5%AE%9A%E5%BC%8F%E6%8F%90%E4%BA%A4/"/>
    <category term="Emoji" scheme="https://jeromexiong.github.io/tags/Emoji/"/>
    <content>
      <![CDATA[<blockquote><p>统一的 Git 提交信息规范能大幅提升代码历史的可读性，配合 AI 工具自动生成，零学习成本。</p></blockquote><h2 id="规范总览">规范总览</h2><h3 id="格式">格式</h3><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><span class="line">- &lt;emoji&gt; &lt;type&gt;(&lt;scope&gt;): &lt;subject&gt;</span><br><span class="line">- </span><br><span class="line">- &lt;body 行1&gt;</span><br><span class="line">- &lt;body 行2&gt;</span><br><span class="line">- </span><br><span class="line">- &lt;footer&gt;</span><br></pre></td></tr></tbody></table></figure><h3 id="示例">示例</h3><figure class="highlight text"><table><tbody><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></pre></td><td class="code"><pre><span class="line">- ✨ feat(api): 添加用户登录接口</span><br><span class="line">- </span><br><span class="line">- 新增 JWT 认证流程，包含 token 刷新和过期处理。</span><br><span class="line">- 使用 Redis 缓存 session 提升性能。</span><br><span class="line">- </span><br><span class="line">- Closes #42</span><br></pre></td></tr></tbody></table></figure><figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">- 🐛 fix(components): 修复日期选择器样式错乱</span><br><span class="line">- </span><br><span class="line">- Safari 下 flex 布局未正确渲染，改用 grid 布局替代。</span><br></pre></td></tr></tbody></table></figure><figure class="highlight text"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- 📝 docs: 更新 API 文档</span><br></pre></td></tr></tbody></table></figure><h2 id="Type-与-Emoji-映射">Type 与 Emoji 映射</h2><table><thead><tr><th>Emoji</th><th>Type</th><th>说明</th></tr></thead><tbody><tr><td>✨</td><td>feat</td><td>添加新功能</td></tr><tr><td>🐛</td><td>fix</td><td>修复 bug</td></tr><tr><td>📝</td><td>docs</td><td>对文档进行修改</td></tr><tr><td>♻️</td><td>refactor</td><td>代码重构</td></tr><tr><td>⚡</td><td>perf</td><td>提高性能的代码修改</td></tr><tr><td>🧑‍💻</td><td>dx</td><td>优化开发体验</td></tr><tr><td>🔨</td><td>workflow</td><td>工作流变动</td></tr><tr><td>🏷️</td><td>types</td><td>类型声明修改</td></tr><tr><td>🚧</td><td>wip</td><td>工作进行中</td></tr><tr><td>✅</td><td>test</td><td>测试用例添加及修改</td></tr><tr><td>🔨</td><td>build</td><td>构建系统或依赖变更</td></tr><tr><td>👷</td><td>ci</td><td>CI 配置变更</td></tr><tr><td>❓</td><td>chore</td><td>其它杂项修改</td></tr><tr><td>⬆️</td><td>deps</td><td>依赖项修改</td></tr><tr><td>🔖</td><td>release</td><td>发布新版本</td></tr></tbody></table><h2 id="详细规则">详细规则</h2><h3 id="Subject（必填）">Subject（必填）</h3><ul><li><strong>不超过 50 个字符</strong></li><li>使用祈使句，如"添加"而非"添加了"</li><li>结尾不使用句号</li></ul><h3 id="Body（可选）">Body（可选）</h3><ul><li>每行不超过 <strong>72 个字符</strong></li><li>详细描述更改的<strong>原因</strong>，而非"做了什么"</li><li>若无复杂逻辑可省略</li></ul><h3 id="Footer（可选）">Footer（可选）</h3><ul><li>引用 Issue：<code>Closes #123</code></li><li>重大变更（Breaking Change）在此说明</li><li>若无则省略</li></ul><h2 id="配置方式">配置方式</h2><h3 id="1-VSCode（完整配置）">1. VSCode（完整配置）</h3><p>打开 VSCode 命令面板（<code>Cmd + Shift + P</code>），执行 <code>Preferences: Open User Settings (JSON)</code>，在 <code>settings.json</code> 中添加以下配置：</p><figure class="highlight json"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">"github.copilot.chat.localeOverride"</span><span class="punctuation">:</span> <span class="string">"zh-CN"</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">"github.copilot.chat.commitMessageGeneration.instructions"</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"所有 Git 提交信息必须严格使用简体中文。"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"输出格式要求：每一行内容必须以 '- '（连字符加空格）开头。"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"结构示例：\n- &lt;emoji&gt; &lt;type&gt;(&lt;scope&gt;): &lt;subject&gt;\n- \n- &lt;body 行1&gt;\n- &lt;body 行2&gt;\n- \n- &lt;footer&gt;"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"Type 与 Emoji 映射规则（仅允许使用以下组合）：\n- ✨ feat: 添加新功能\n- 🐛 fix: 修复 bug\n- 📝 docs: 对文档进行修改\n- ♻️ refactor: 代码重构\n- ⚡ perf: 提高性能的代码修改\n- 🧑‍💻 dx: 优化开发体验\n- 🔨 workflow: 工作流变动\n- 🏷️ types: 类型声明修改\n- 🚧 wip: 工作进行中\n- ✅ test: 测试用例添加及修改\n- 🔨 build: 构建系统或依赖变更\n- 👷 ci: CI 配置变更\n- ❓ chore: 其它杂项修改\n- ⬆️ deps: 依赖项修改\n- 🔖 release: 发布新版本"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"Subject 要求：简洁明了，不超过 50 个字符；使用祈使句；结尾不使用句号。"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"Body 要求：详细描述更改原因；每行不超过 72 个字符。"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"text"</span><span class="punctuation">:</span> <span class="string">"重要约束：最终输出只包含纯文本提交信息，严禁使用 Markdown 代码块包裹，严禁包含任何解释性文字。"</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">]</span></span><br></pre></td></tr></tbody></table></figure><p>配置好之后，在 VSCode 源码管理面板（<code>Ctrl + Shift + G</code>）写提交信息时，Copilot 会自动输出符合规范的提交信息。</p><h3 id="2-Claude-Code（完整配置）">2. Claude Code（完整配置）</h3><p>在 <code>~/.claude/CLAUDE.md</code>（全局）或项目根目录的 <code>CLAUDE.md</code>（项目级）中添加：</p><figure class="highlight markdown"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">alwaysApply: true</span><br><span class="line"><span class="section">scene: git<span class="emphasis">_message</span></span></span><br><span class="line"><span class="emphasis"><span class="section">---</span></span></span><br><span class="line"><span class="emphasis"><span class="section"></span></span></span><br><span class="line"><span class="emphasis"><span class="section"># Git 提交信息规范</span></span></span><br><span class="line"><span class="emphasis"><span class="section"></span></span></span><br><span class="line"><span class="emphasis"><span class="section">- 所有 git commit message 必须使用简体中文。</span></span></span><br><span class="line"><span class="emphasis"><span class="section">- 严格使用以下格式输出：`<span class="language-xml"><span class="tag">&lt;<span class="name">emoji</span>&gt;</span></span> <span class="language-xml"><span class="tag">&lt;<span class="name">type</span>&gt;</span></span>: &lt;中文简短描述&gt;`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">- 只允许使用以下类型与前缀：</span></span></span><br><span class="line"><span class="emphasis"><span class="section"></span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `✨ feat: 添加新功能`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🐛 fix: 修复 bug`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `📝 docs: 对文档进行修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `♻️ refactor: 代码重构`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `⚡ perf: 提高性能的代码修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🧑‍💻 dx: 优化开发体验`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🔨 workflow: 工作流变动`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🏷️ types: 类型声明修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🚧 wip: 工作进行中`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `✅ test: 测试用例添加及修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🔨 build: 构建系统或依赖变更`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `👷 ci: CI 配置变更`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `❓ chore: 其它杂项修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `⬆️ deps: 依赖项修改`</span></span></span><br><span class="line"><span class="emphasis"><span class="section">  - `🔖 release: 发布新版本`</span></span></span><br><span class="line"><span class="emphasis"><span class="section"></span></span></span><br><span class="line"><span class="emphasis"><span class="section">- 需要多行时，每行以 `- ` 开头，形成一个列表。</span></span></span><br><span class="line"><span class="emphasis"><span class="section">- 第一行是摘要，后续行是详细说明（每行 ≤ 72 字符）。</span></span></span><br><span class="line"><span class="emphasis"><span class="section"></span></span></span><br><span class="line"><span class="emphasis"><span class="section">- <span class="strong">**重要约束**</span>：最终输出只包含纯文本形式的 commit message，严禁使用 Markdown 代码块包裹，严禁包含任何解释性文字。</span></span></span><br></pre></td></tr></tbody></table></figure><h3 id="3-Hermes-Agent">3. Hermes Agent</h3><p>Hermes Agent 会自动加载 <code>~/.claude/CLAUDE.md</code> 中的提交规范，生成提交信息时遵循相同的 emoji + type 格式。</p><h2 id="使用效果">使用效果</h2><p>配置后，在 VSCode 源码管理面板写提交信息时，Copilot 会自动输出符合规范的提交信息：</p><figure class="highlight text"><table><tbody><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><br><span class="line">添加登录页面</span><br><span class="line"></span><br><span class="line"># Copilot 输出：</span><br><span class="line">- ✨ feat(pages): 添加用户登录页面</span><br><span class="line">-</span><br><span class="line">- 实现手机号+验证码登录流程，包含表单校验和错误提示。</span><br></pre></td></tr></tbody></table></figure><p>在 Claude Code 中运行 <code>claude -p "提交当前更改"</code> 也会生成符合规范的提交信息。</p><h2 id="常见场景速查">常见场景速查</h2><table><thead><tr><th>场景</th><th>写法</th></tr></thead><tbody><tr><td>新功能</td><td><code>✨ feat(api): 添加商品搜索接口</code></td></tr><tr><td>修 Bug</td><td><code>🐛 fix(cart): 修复数量加减按钮失效</code></td></tr><tr><td>改文档</td><td><code>📝 docs: 更新部署说明</code></td></tr><tr><td>重构</td><td><code>♻️ refactor(auth): 提取认证中间件</code></td></tr><tr><td>性能</td><td><code>⚡ perf(list): 虚拟滚动优化长列表渲染</code></td></tr><tr><td>更新依赖</td><td><code>⬆️ deps: 升级 FastAPI 到 0.110.0</code></td></tr><tr><td>CI 配置</td><td><code>👷 ci: 添加自动化测试工作流</code></td></tr><tr><td>发布版本</td><td><code>🔖 release: v2.1.0</code></td></tr></tbody></table><hr><p><em>相关工具：<a href="https://www.conventionalcommits.org/">约定式提交规范</a></em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/Git-%E6%8F%90%E4%BA%A4%E4%BF%A1%E6%81%AF%E8%A7%84%E8%8C%83/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/Git-%E6%8F%90%E4%BA%A4%E4%BF%A1%E6%81%AF%E8%A7%84%E8%8C%83/"/>
    <published>2026-06-16T06:00:00.000Z</published>
    <summary>团队 Git 提交信息规范，使用 Emoji + Type 标准化提交信息格式，支持 VSCode Copilot、Claude Code 自动生成</summary>
    <title>Git 提交信息规范 — Emoji + Type 约定式提交</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="AI" scheme="https://jeromexiong.github.io/categories/AI/"/>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/AI/%E5%B7%A5%E5%85%B7/"/>
    <category term="Hermes" scheme="https://jeromexiong.github.io/tags/Hermes/"/>
    <category term="AI Agent" scheme="https://jeromexiong.github.io/tags/AI-Agent/"/>
    <category term="CLI" scheme="https://jeromexiong.github.io/tags/CLI/"/>
    <category term="安装配置" scheme="https://jeromexiong.github.io/tags/%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AE/"/>
    <content>
      <![CDATA[<blockquote><p>Hermes Agent 是一个基于大语言模型的 AI 智能体框架，支持 CLI、TUI、微信、Telegram 等多种交互方式。本文记录完整的安装配置流程。</p></blockquote><h2 id="安装">安装</h2><h3 id="前置条件">前置条件</h3><ul><li>Python 3.12+</li><li>macOS / Linux</li><li>Git</li></ul><h3 id="pip-安装">pip 安装</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install hermes-agent</span><br></pre></td></tr></tbody></table></figure><p>安装后初始化项目并创建配置文件：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes init</span><br></pre></td></tr></tbody></table></figure><p>这会生成 <code>~/.hermes/config.yaml</code> 主配置文件。</p><h3 id="验证安装">验证安装</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hermes --version</span><br><span class="line"><span class="comment"># Hermes Agent v0.15.1 (2026.5.29)</span></span><br></pre></td></tr></tbody></table></figure><h2 id="配置基础">配置基础</h2><h3 id="配置文件">配置文件</h3><p>主配置位于 <code>~/.hermes/config.yaml</code>，核心配置项：</p><figure class="highlight yaml"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="attr">model:</span></span><br><span class="line">  <span class="attr">default:</span> <span class="string">deepseek-v4-flash</span>        <span class="comment"># 默认模型</span></span><br><span class="line">  <span class="attr">provider:</span> <span class="string">deepseek</span>                <span class="comment"># 默认提供商</span></span><br><span class="line">  <span class="attr">base_url:</span> <span class="string">https://api.deepseek.com</span></span><br><span class="line"></span><br><span class="line"><span class="attr">agent:</span></span><br><span class="line">  <span class="attr">max_turns:</span> <span class="number">90</span>                     <span class="comment"># 单次对话最大轮次</span></span><br><span class="line">  <span class="attr">gateway_timeout:</span> <span class="number">1800</span>             <span class="comment"># 网关超时（秒）</span></span><br><span class="line">  <span class="attr">api_max_retries:</span> <span class="number">3</span>                <span class="comment"># API 重试次数</span></span><br></pre></td></tr></tbody></table></figure><h3 id="多-Profile-支持">多 Profile 支持</h3><p>支持多 Profile 隔离不同场景的配置、技能和记忆：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hermes profile list</span><br><span class="line"><span class="comment"># default    deepseek-v4-flash</span></span><br></pre></td></tr></tbody></table></figure><h2 id="CLI-基础使用">CLI 基础使用</h2><h3 id="启动会话">启动会话</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hermes                           <span class="comment"># 默认模式</span></span><br><span class="line">hermes -m <span class="string">"anthropic/claude-sonnet-4"</span>  <span class="comment"># 指定模型</span></span><br><span class="line">hermes --profile work            <span class="comment"># 指定 profile</span></span><br></pre></td></tr></tbody></table></figure><h3 id="常用命令">常用命令</h3><table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><code>/new</code></td><td>开启新对话</td></tr><tr><td><code>/skill &lt;name&gt;</code></td><td>加载指定技能</td></tr><tr><td><code>/tools</code></td><td>查看可用工具</td></tr><tr><td><code>/model</code></td><td>切换模型</td></tr><tr><td><code>/save</code></td><td>保存当前会话</td></tr><tr><td><code>/export &lt;format&gt;</code></td><td>导出会话</td></tr></tbody></table><h3 id="TUI-模式">TUI 模式</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes tui</span><br></pre></td></tr></tbody></table></figure><p>TUI 模式下支持更丰富的界面交互，包括斜杠命令快捷键、会话列表、技能面板等。</p><h2 id="模型提供商配置">模型提供商配置</h2><p>支持多模型提供商，修改 <code>config.yaml</code>：</p><figure class="highlight yaml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">model:</span></span><br><span class="line">  <span class="attr">default:</span> <span class="string">deepseek-v4-flash</span></span><br><span class="line">  <span class="attr">provider:</span> <span class="string">deepseek</span></span><br></pre></td></tr></tbody></table></figure><p>支持的提供商：OpenAI、Anthropic、DeepSeek、OpenRouter、Groq、自定义等。</p><hr><p><em>参考：<a href="https://hermes-agent.nousresearch.com/docs">Hermes Agent 官方文档</a></em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E5%AE%89%E8%A3%85%E4%B8%8E%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E5%AE%89%E8%A3%85%E4%B8%8E%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>AI 智能体 Hermes Agent 的安装、配置与日常使用指南</summary>
    <title>Hermes Agent 安装与配置指南</title>
    <updated>2026-06-16T08:17:05.711Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="AI" scheme="https://jeromexiong.github.io/categories/AI/"/>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/AI/%E5%B7%A5%E5%85%B7/"/>
    <category term="Hermes" scheme="https://jeromexiong.github.io/tags/Hermes/"/>
    <category term="Skills" scheme="https://jeromexiong.github.io/tags/Skills/"/>
    <category term="MCP" scheme="https://jeromexiong.github.io/tags/MCP/"/>
    <category term="插件" scheme="https://jeromexiong.github.io/tags/%E6%8F%92%E4%BB%B6/"/>
    <content>
      <![CDATA[<blockquote><p>Hermes Agent 的核心能力来源于**技能（Skills）**系统。每个技能是一个 markdown 文件，定义了特定场景下的行为、工作流和注意事项。</p></blockquote><h2 id="技能系统概览">技能系统概览</h2><p>技能文件存储在 <code>~/.hermes/skills/</code> 下，按类别组织：</p><figure class="highlight plaintext"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">skills/</span><br><span class="line">├── academic/           # 学术写作</span><br><span class="line">├── apple/              # Apple 生态（iMessage, 提醒事项）</span><br><span class="line">├── autonomous-ai-agents/  # AI 智能体</span><br><span class="line">│   ├── hermes-agent/   # Hermes 自身配置</span><br><span class="line">│   ├── claude-code/    # Claude Code 集成</span><br><span class="line">│   ├── codex/          # OpenAI Codex</span><br><span class="line">│   ├── karpathy-guidelines/  # Karpathy 编码准则</span><br><span class="line">│   └── ...</span><br><span class="line">├── creative/           # 创意内容（ASCII 艺术、漫画、P5.js）</span><br><span class="line">├── engineering/        # 工程开发</span><br><span class="line">├── marketing/          # 营销推广</span><br><span class="line">├── devops/             # DevOps 运维</span><br><span class="line">├── mcp/                # MCP 协议</span><br><span class="line">│   ├── native-mcp/     # 原生 MCP 客户端</span><br><span class="line">│   └── midscene-browser/  # 浏览器自动化</span><br><span class="line">├── github/             # GitHub 工作流</span><br><span class="line">├── testing/            # 软件测试</span><br><span class="line">└── ...</span><br></pre></td></tr></tbody></table></figure><p>总计 <strong>320+ 技能</strong>，覆盖 <strong>55 个类别</strong>。</p><h2 id="加载技能">加载技能</h2><p>技能会自动匹配任务场景，也可以手动加载：</p><figure class="highlight bash"><table><tbody><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="comment"># 在 Hermes 中手动加载</span></span><br><span class="line">/skill &lt;技能名&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在提示词中引用</span></span><br><span class="line">请加载 karpathy-guidelines 技能后回答</span><br></pre></td></tr></tbody></table></figure><h2 id="常用三方技能">常用三方技能</h2><h3 id="0-日常高频技能">0. 日常高频技能</h3><p>以下是我日常工作中最常用的技能，按场景分类：</p><h4 id="设计与创意">设计与创意</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>ui-ux-pro-max</code></td><td>移动端电商/应用 UI 设计，完整的组件规范和像素级页面设计</td></tr><tr><td><code>brainstorming</code></td><td>创意构思，生成产品设计和解决方案的多种可能</td></tr><tr><td><code>excalidraw</code></td><td>手绘风格架构图、流程图、时序图</td></tr><tr><td><code>architecture-diagram</code></td><td>深色主题 SVG 架构/云/基础设施图</td></tr></tbody></table><h4 id="全栈开发">全栈开发</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>reasonix</code></td><td>⭐ <strong>默认编码委托</strong> — DeepSeek 原生框架，成本比 Claude 省 97%</td></tr><tr><td><code>claude-code</code></td><td>编码委托备选（需要 Claude 特定功能时）</td></tr><tr><td><code>codex</code></td><td>编码委托</td></tr><tr><td><code>opencode</code></td><td>编码委托</td></tr><tr><td><code>engineering-senior-developer</code></td><td>Laravel/Livewire/FluxUI 全栈开发，高端 CSS、Three.js</td></tr><tr><td><code>engineering-frontend-developer</code></td><td>Vue3/React 前端开发，UI 实现与性能优化</td></tr><tr><td><code>engineering-backend-architect</code></td><td>FastAPI/后端架构设计、数据库、API 开发</td></tr><tr><td><code>engineering-code-reviewer</code></td><td>代码审查，关注正确性、可维护性、安全性</td></tr></tbody></table><h4 id="项目管理与规划">项目管理与规划</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>writing-plans</code></td><td>编写实施方案，分解为可执行步骤</td></tr><tr><td><code>project-manager-senior</code></td><td>需求拆分、任务分解、经验复盘</td></tr><tr><td><code>spike</code></td><td>快速验证想法的实验性原型</td></tr><tr><td><code>test-driven-development</code></td><td>TDD 模式：RED → GREEN → REFACTOR</td></tr></tbody></table><h4 id="调试与问题排查">调试与问题排查</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>systematic-debugging</code></td><td>系统性调试：理解问题后再修复，而非盲目尝试</td></tr><tr><td><code>python-debugpy</code></td><td>Python 远程调试（pdb + debugpy DAP）</td></tr><tr><td><code>node-inspect-debugger</code></td><td>Node.js 远程调试（Chrome DevTools Protocol）</td></tr></tbody></table><h4 id="部署与运维">部署与运维</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>yisugou-deployment</code></td><td>易速购一键部署脚本（git clone + bash <a href="http://deploy.sh">deploy.sh</a>）</td></tr><tr><td><code>yisugou-mvp-workflow</code></td><td>易速购 MVP 开发流程：后端模块 → 管理后台 → 数据入库 → 端到端测试</td></tr><tr><td><code>hexo-ci-cd</code></td><td>Hexo 博客 GitHub Actions CI/CD 构建与部署</td></tr><tr><td><code>nginx-layered-proxy</code></td><td>双层 Nginx 架构（统一入口 + Docker 内部）</td></tr><tr><td><code>mysql-operations</code></td><td>MySQL Docker 管理、密码重置、数据迁移、端口冲突处理</td></tr><tr><td><code>dockerfile-patterns</code></td><td>Dockerfile 构建优化（上下文裁剪、层缓存、apt 镜像）</td></tr></tbody></table><h4 id="浏览器与自动化测试">浏览器与自动化测试</h4><table><thead><tr><th>技能</th><th>用途</th></tr></thead><tbody><tr><td><code>midscene-browser</code></td><td>基于 MCP 的浏览器自动化，自然语言控制浏览器</td></tr><tr><td><code>testing-api-tester</code></td><td>API 全面验证、性能测试、质量保证</td></tr></tbody></table><h3 id="1-Karpathy-Guidelines">1. Karpathy Guidelines</h3><p>来源：<a href="https://github.com/multica-ai/andrej-karpathy-skills">multica-ai/andrej-karpathy-skills</a></p><p>著名的 AI 编码行为准则，包含 4 条核心原则：</p><ol><li><strong>Think Before Coding</strong> — 显式陈述假设，不默默选择</li><li><strong>Simplicity First</strong> — 只写最少代码，不过度抽象</li><li><strong>Surgical Changes</strong> — 只改必须改的行，不顺手重构</li><li><strong>Goal-Driven Execution</strong> — 先定义成功标准再执行</li></ol><h3 id="2-Claude-Code-Codex-集成">2. Claude Code / Codex 集成</h3><p>Hermes 可以委派编码任务给专用编码 Agent：</p><table><thead><tr><th>技能</th><th>用途</th><th>说明</th></tr></thead><tbody><tr><td><code>claude-code</code></td><td>编码委托</td><td>用 Claude Code CLI 处理复杂编码任务</td></tr><tr><td><code>codex</code></td><td>编码委托</td><td>用 OpenAI Codex CLI 处理编码任务</td></tr><tr><td><code>opencode</code></td><td>编码委托</td><td>用 OpenCode CLI 处理编码任务</td></tr></tbody></table><h3 id="3-浏览器自动化-Midscene-js">3. 浏览器自动化 (Midscene.js)</h3><p>基于 MCP 协议的浏览器自动化工具，用自然语言控制浏览器：</p><figure class="highlight yaml"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># config.yaml MCP 配置</span></span><br><span class="line"><span class="attr">mcp_servers:</span></span><br><span class="line">  <span class="attr">midscene-web:</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">npx</span></span><br><span class="line">    <span class="attr">args:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">'@midscene/web-bridge-mcp'</span></span><br></pre></td></tr></tbody></table></figure><p>用于：网页测试、表单填写、数据抓取、功能验证。</p><h3 id="4-Agency-Agents-—-Claude-Code-人格库">4. Agency Agents — Claude Code 人格库</h3><p>来源：<a href="https://github.com/msitarzewski/agency-agents">msitarzewski/agency-agents</a></p><p>184 个预定义的 AI Agent 人格，安装到 <code>~/.claude/agents/</code>，在 Claude Code 中用 <code>@agent-name</code> 调用：</p><table><thead><tr><th>分类</th><th>Agent 数</th><th>示例</th></tr></thead><tbody><tr><td>Engineering</td><td>18</td><td><code>@frontend-developer</code>, <code>@backend-architect</code>, <code>@code-reviewer</code></td></tr><tr><td>Design</td><td>8</td><td><code>@ui-designer</code>, <code>@ux-architect</code>, <code>@brand-guardian</code></td></tr><tr><td>Marketing</td><td>30+</td><td><code>@seo-specialist</code>, <code>@content-creator</code>, <code>@growth-hacker</code></td></tr><tr><td>Product</td><td>5</td><td><code>@product-manager</code>, <code>@sprint-prioritizer</code></td></tr><tr><td>Sales</td><td>8</td><td><code>@deal-strategist</code>, <code>@sales-engineer</code></td></tr><tr><td>Finance</td><td>8</td><td><code>@financial-analyst</code>, <code>@tax-strategist</code></td></tr><tr><td>Specialized</td><td>30+</td><td><code>@mcp-builder</code>, <code>@prompt-engineer</code>, <code>@workflow-architect</code></td></tr></tbody></table><p>安装方式：</p><figure class="highlight bash"><table><tbody><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">git <span class="built_in">clone</span> --depth 1 https://github.com/msitarzewski/agency-agents.git /tmp/agency-agents</span><br><span class="line"><span class="built_in">cd</span> /tmp/agency-agents</span><br><span class="line">bash scripts/install.sh --tool claude-code --no-interactive</span><br><span class="line"><span class="built_in">rm</span> -rf /tmp/agency-agents</span><br></pre></td></tr></tbody></table></figure><h3 id="5-Reasonix-—-DeepSeek-原生编码框架">5. Reasonix — DeepSeek 原生编码框架</h3><p>Reasonix 是基于 DeepSeek 原生 API 的编码智能体框架，特点和优势：</p><table><thead><tr><th>特性</th><th>说明</th></tr></thead><tbody><tr><td>版本</td><td>v0.50.1</td></tr><tr><td>模型</td><td>deepseek-v4-flash / deepseek-v4-pro</td></tr><tr><td>缓存</td><td>主动缓存优化（前缀共享 + 会话持久化）</td></tr><tr><td>成本</td><td>比 Claude Code 节省约 <strong>97%</strong></td></tr></tbody></table><p>命令速查：</p><table><thead><tr><th>命令</th><th>用途</th></tr></thead><tbody><tr><td><code>reasonix run "任务"</code></td><td>非交互模式，单次任务</td></tr><tr><td><code>reasonix code</code></td><td>交互模式，带缓存/成本实时面板</td></tr><tr><td><code>reasonix stats</code></td><td>查看缓存命中率和成本统计</td></tr><tr><td><code>reasonix doctor</code></td><td>检查环境配置</td></tr></tbody></table><p>与 Claude Code 的成本对比：</p><table><thead><tr><th>场景</th><th>Claude Code → DeepSeek</th><th>Reasonix (原生)</th></tr></thead><tbody><tr><td>单次调用</td><td>~$0.009</td><td>~$0.00027</td></tr><tr><td>缓存策略</td><td>服务端决定</td><td>主动前缀共享 + 会话持久化</td></tr><tr><td>交互模式</td><td><code>claude</code></td><td><code>reasonix code</code></td></tr></tbody></table><h3 id="6-Apple-生态集成">6. Apple 生态集成</h3><table><thead><tr><th>技能</th><th>功能</th></tr></thead><tbody><tr><td><code>imessage</code></td><td>发送/接收 iMessage 和 SMS</td></tr><tr><td><code>apple-reminders</code></td><td>管理 Apple 提醒事项</td></tr><tr><td><code>apple-notes</code></td><td>管理 Apple 备忘录</td></tr><tr><td><code>findmy</code></td><td>追踪 Apple 设备位置</td></tr></tbody></table><h3 id="7-MCP（Model-Context-Protocol）">7. MCP（Model Context Protocol）</h3><p>原生 MCP 客户端支持，可连接任意 MCP 服务器动态注册工具。当前配置了：</p><ul><li><code>codegraph</code> — 代码图谱分析</li><li><code>midscene-web</code> — 浏览器自动化</li></ul><h2 id="安装三方技能">安装三方技能</h2><p>从 GitHub 仓库安装技能：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 克隆仓库到 skills 目录</span></span><br><span class="line">git <span class="built_in">clone</span> &lt;repo-url&gt; ~/.hermes/skills/&lt;category&gt;/&lt;skill-name&gt;</span><br></pre></td></tr></tbody></table></figure><p>安装后重启 Hermes 即可使用。也可以使用 <code>hermes install</code> 命令（如果支持）。</p><h2 id="插件系统">插件系统</h2><p>除了技能，Hermes 还支持插件机制。当前安装的插件：</p><ul><li><code>hermes-achievements</code> — 成就系统</li></ul><hr><p><em>参考：<a href="https://hermes-agent.nousresearch.com/docs/skills">Hermes Agent 技能文档</a></em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E6%8A%80%E8%83%BD%E7%B3%BB%E7%BB%9F%E4%B8%8E%E4%B8%89%E6%96%B9%E6%8A%80%E8%83%BD/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E6%8A%80%E8%83%BD%E7%B3%BB%E7%BB%9F%E4%B8%8E%E4%B8%89%E6%96%B9%E6%8A%80%E8%83%BD/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>Hermes Agent 的技能系统详解，如何使用内置技能、安装三方技能、配置 MCP 工具</summary>
    <title>Hermes Agent 技能系统与三方技能</title>
    <updated>2026-06-16T08:17:05.711Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="AI" scheme="https://jeromexiong.github.io/categories/AI/"/>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/AI/%E5%B7%A5%E5%85%B7/"/>
    <category term="Hermes" scheme="https://jeromexiong.github.io/tags/Hermes/"/>
    <category term="微信" scheme="https://jeromexiong.github.io/tags/%E5%BE%AE%E4%BF%A1/"/>
    <category term="网关" scheme="https://jeromexiong.github.io/tags/%E7%BD%91%E5%85%B3/"/>
    <category term="定时任务" scheme="https://jeromexiong.github.io/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"/>
    <category term="工作流" scheme="https://jeromexiong.github.io/tags/%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    <content>
      <![CDATA[<blockquote><p>Hermes Agent 不仅是 CLI 工具，还支持网关模式、定时任务、多平台消息推送等生产级能力。</p></blockquote><h2 id="网关模式">网关模式</h2><p>网关模式让 Hermes 作为后台常驻服务运行，通过微信、Telegram、Discord 等平台交互。</p><h3 id="启动网关">启动网关</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes gateway</span><br></pre></td></tr></tbody></table></figure><h3 id="WeChat-集成">WeChat 集成</h3><p>通过 WeChat 网关，可以在微信中直接与 Hermes 对话：</p><ul><li>发送消息 → Hermes 处理 → 返回结果</li><li>自动识别上下文，追踪对话线程</li><li>支持文件、图片等多模态输入</li></ul><p>配置方式（<code>config.yaml</code>）：</p><figure class="highlight yaml"><table><tbody><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="comment"># 网关相关配置</span></span><br><span class="line"><span class="attr">gateway:</span></span><br><span class="line">  <span class="attr">strict:</span> <span class="literal">false</span></span><br><span class="line">  <span class="attr">trust_recent_files:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">trust_recent_files_seconds:</span> <span class="number">600</span></span><br></pre></td></tr></tbody></table></figure><h3 id="消息格式">消息格式</h3><table><thead><tr><th>内容类型</th><th>说明</th></tr></thead><tbody><tr><td>文本</td><td>直接对话</td></tr><tr><td>图片</td><td>自动 OCR/视觉分析</td></tr><tr><td>文件</td><td>代码审查、文档处理</td></tr><tr><td>URL</td><td>网页摘要、内容分析</td></tr></tbody></table><h2 id="定时任务-Cron">定时任务 (Cron)</h2><p>Hermes 内置定时任务调度器，支持：</p><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建定时任务</span></span><br><span class="line">cronjob(action=<span class="string">'create'</span>, schedule=<span class="string">'0 9 * * *'</span>, prompt=<span class="string">'每天早上9点推送新闻简报'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 列出任务</span></span><br><span class="line">cronjob(action=<span class="string">'list'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 管理任务</span></span><br><span class="line">cronjob(action=<span class="string">'pause'</span>, job_id=<span class="string">'xxx'</span>)</span><br><span class="line">cronjob(action=<span class="string">'remove'</span>, job_id=<span class="string">'xxx'</span>)</span><br></pre></td></tr></tbody></table></figure><p>支持的时间格式：</p><table><thead><tr><th>格式</th><th>说明</th></tr></thead><tbody><tr><td><code>30m</code></td><td>每30分钟执行</td></tr><tr><td><code>every 2h</code></td><td>每2小时执行</td></tr><tr><td><code>0 9 * * *</code></td><td>每天9点（cron 格式）</td></tr><tr><td><code>2026-06-01T09:00:00</code></td><td>一次性的定时任务</td></tr></tbody></table><p>定时任务可以附带技能，也可以运行自定义脚本（Watchdog 模式）。</p><h2 id="MCP-工具">MCP 工具</h2><p>Hermes 内置原生 MCP 客户端，连接 MCP 服务器即可动态注册工具。</p><h3 id="已配置的-MCP-工具">已配置的 MCP 工具</h3><p><strong>1. CodeGraph — 代码分析</strong></p><figure class="highlight yaml"><table><tbody><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"><span class="attr">mcp_servers:</span></span><br><span class="line">  <span class="attr">codegraph:</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">codegraph</span></span><br><span class="line">    <span class="attr">args:</span> [<span class="string">serve</span>, <span class="string">--mcp</span>]</span><br></pre></td></tr></tbody></table></figure><p>用于：代码结构分析、调用链路追踪、影响范围分析、搜索符号。</p><p><strong>2. Midscene Web — 浏览器自动化</strong></p><figure class="highlight yaml"><table><tbody><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"><span class="attr">mcp_servers:</span></span><br><span class="line">  <span class="attr">midscene-web:</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">npx</span></span><br><span class="line">    <span class="attr">args:</span> [<span class="string">'@midscene/web-bridge-mcp'</span>]</span><br></pre></td></tr></tbody></table></figure><p>用于：网页操作、截图验证、表单填写、功能测试。</p><h2 id="日常使用场景">日常使用场景</h2><h3 id="场景一：代码审查">场景一：代码审查</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">请求：帮我审查这个 PR 的代码</span><br><span class="line">→ 自动加载 github-code-review 技能</span><br><span class="line">→ 读取 diff → 分析代码质量 → 生成审查意见</span><br></pre></td></tr></tbody></table></figure><h3 id="场景二：文章写作">场景二：文章写作</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">请求：写一篇关于 Swift Concurrency 的文章</span><br><span class="line">→ 自动匹配写作技能</span><br><span class="line">→ 生成初稿 → 润色 → 发布到博客</span><br></pre></td></tr></tbody></table></figure><h3 id="场景三：服务器运维">场景三：服务器运维</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">请求：检查服务器状态</span><br><span class="line">→ 自动连接服务器 → 执行诊断命令 → 返回报告</span><br></pre></td></tr></tbody></table></figure><h3 id="场景四：定时新闻简报">场景四：定时新闻简报</h3><p>设定每天早上自动推送技术资讯到微信：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cronjob(action=<span class="string">'create'</span>, schedule=<span class="string">'0 8 * * *'</span>, </span><br><span class="line">        prompt=<span class="string">'搜集今天的技术热点，生成中文摘要推送到微信'</span>)</span><br></pre></td></tr></tbody></table></figure><h2 id="小贴士">小贴士</h2><blockquote><p>💡 <strong>记忆系统</strong> — Hermes 会记住你的偏好和项目配置，无需重复说明</p><p>⚠️ <strong>安全性</strong> — 敏感命令需要手动确认（删除文件、重启服务等）</p><p>🔄 <strong>持续更新</strong> — <code>hermes update</code> 拉取最新版本（当前 v0.15.1，落后 1924 commits 时有更新提示）</p></blockquote><hr><p><em>参考：<a href="https://hermes-agent.nousresearch.com/docs/gateway">Hermes Agent 文档</a></em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E6%97%A5%E5%B8%B8%E4%BD%BF%E7%94%A8%E4%B8%8E%E9%9B%86%E6%88%90/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/AI%E6%A8%A1%E5%9D%97/Hermes-Agent-%E6%97%A5%E5%B8%B8%E4%BD%BF%E7%94%A8%E4%B8%8E%E9%9B%86%E6%88%90/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>Hermes Agent 的日常使用场景，包括网关集成、定时任务、消息推送和多模态交互</summary>
    <title>Hermes Agent 日常使用与集成</title>
    <updated>2026-06-16T08:17:05.711Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="Swift" scheme="https://jeromexiong.github.io/categories/iOS/Swift/"/>
    <category term="Swift" scheme="https://jeromexiong.github.io/tags/Swift/"/>
    <category term="实战" scheme="https://jeromexiong.github.io/tags/%E5%AE%9E%E6%88%98/"/>
    <category term="iOS开发" scheme="https://jeromexiong.github.io/tags/iOS%E5%BC%80%E5%8F%91/"/>
    <content>
      <![CDATA[<blockquote><p><strong>TL;DR</strong> 本文从实际项目出发，详细记录了实现 XX 功能的完整过程，包含架构选型、关键代码、性能数据和踩坑记录。</p></blockquote><h2 id="背景">背景</h2><p>为什么要做这个功能？遇到了什么问题？</p><h2 id="最终效果">最终效果</h2><!-- 可以放 GIF 或截图 --><h2 id="方案对比">方案对比</h2><table><thead><tr><th>方案</th><th>优点</th><th>缺点</th><th>适用场景</th></tr></thead><tbody><tr><td>方案A</td><td>实现简单</td><td>扩展性差</td><td>快速验证</td></tr><tr><td>方案B</td><td>性能好</td><td>学习成本高</td><td>生产环境</td></tr><tr><td>方案C ✅</td><td>平衡两者</td><td>需要额外库</td><td>大多数场景</td></tr></tbody></table><blockquote><p>最终选择了 <strong>方案C</strong>，原因是……</p></blockquote><h2 id="核心实现">核心实现</h2><h3 id="1-架构设计">1. 架构设计</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">App层     → ViewController / View</span><br><span class="line">业务层    → Service / Manager</span><br><span class="line">数据层    → Repository / Cache</span><br></pre></td></tr></tbody></table></figure><h3 id="2-关键代码">2. 关键代码</h3><figure class="highlight swift"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// File: Sources/Feature/Manager.swift</span></span><br><span class="line"><span class="keyword">protocol</span> <span class="title class_">FeatureManagerProtocol</span> {</span><br><span class="line">    <span class="keyword">func</span> <span class="title function_">fetchData</span>(<span class="params">completion</span>: <span class="keyword">@escaping</span> (<span class="type">Result</span>&lt;[<span class="type">Model</span>], <span class="type">Error</span>&gt;) -&gt; <span class="type">Void</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">FeatureManager</span>: <span class="title class_ inherited__">FeatureManagerProtocol</span> {</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">let</span> repository: <span class="type">DataRepository</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">init</span>(<span class="params">repository</span>: <span class="type">DataRepository</span> <span class="operator">=</span> .shared) {</span><br><span class="line">        <span class="keyword">self</span>.repository <span class="operator">=</span> repository</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">func</span> <span class="title function_">fetchData</span>(<span class="params">completion</span>: <span class="keyword">@escaping</span> (<span class="type">Result</span>&lt;[<span class="type">Model</span>], <span class="type">Error</span>&gt;) -&gt; <span class="type">Void</span>) {</span><br><span class="line">        repository.load { result <span class="keyword">in</span></span><br><span class="line">            <span class="comment">// 业务处理...</span></span><br><span class="line">            completion(result)</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="3-注意要点">3. 注意要点</h3><blockquote><p>⚠️ 这里有几个容易踩的坑：</p><ol><li>注意内存泄漏 — 使用 <code>[weak self]</code></li><li>线程安全 — 回到主线程更新 UI</li><li>边界情况 — 空数据处理</li></ol></blockquote><h2 id="性能数据">性能数据</h2><table><thead><tr><th>场景</th><th>优化前</th><th>优化后</th><th>提升</th></tr></thead><tbody><tr><td>首屏加载</td><td>2.3s</td><td>0.8s</td><td>65%</td></tr><tr><td>内存占用</td><td>120MB</td><td>45MB</td><td>62%</td></tr></tbody></table><h2 id="总结">总结</h2><ul><li>✅ 实现了 XX 功能</li><li>✅ 性能满足预期</li><li>✅ 可扩展性好</li></ul>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E5%AE%9E%E6%88%98%E7%AC%94%E8%AE%B0/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E5%AE%9E%E6%88%98%E7%AC%94%E8%AE%B0/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>手把手带你实现一个完整的 XX 功能，涵盖架构设计、核心实现和常见坑点</summary>
    <title>实战笔记：从零到一搭建 XXX</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="效率" scheme="https://jeromexiong.github.io/tags/%E6%95%88%E7%8E%87/"/>
    <category term="技巧" scheme="https://jeromexiong.github.io/tags/%E6%8A%80%E5%B7%A7/"/>
    <category term="生产力" scheme="https://jeromexiong.github.io/tags/%E7%94%9F%E4%BA%A7%E5%8A%9B/"/>
    <content>
      <![CDATA[<p>把这些技巧挨个试一遍，总有几个让你惊呼"原来还能这样？"</p><h2 id="🔥-技巧-1：标题即要点">🔥 技巧 1：标题即要点</h2><blockquote><p><strong>场景</strong>：什么时候用这个技巧？<br><strong>操作</strong>：具体怎么做</p></blockquote><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 实际命令或代码</span></span><br></pre></td></tr></tbody></table></figure><h2 id="🔥-技巧-2：……">🔥 技巧 2：……</h2><table><thead><tr><th>技巧</th><th>难度</th><th>频次</th></tr></thead><tbody><tr><td>技巧1</td><td>⭐</td><td>每天</td></tr><tr><td>技巧2</td><td>⭐⭐</td><td>每周</td></tr></tbody></table><h2 id="总结清单">总结清单</h2><ul><li>[ ] 技巧1 已掌握</li><li>[ ] 技巧2 已掌握</li><li>[ ] 技巧3 已掌握</li></ul><hr><p><em>觉得有用的话可以收藏，后续还会更新更多技巧。</em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E6%8A%80%E5%B7%A7%E5%90%88%E9%9B%86/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E6%8A%80%E5%B7%A7%E5%90%88%E9%9B%86/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>整理了 XX 方面 10 个实用技巧，每一个都能提升你的工作效率</summary>
    <title>XXX 实用技巧合集</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="Swift" scheme="https://jeromexiong.github.io/categories/iOS/Swift/"/>
    <category term="iOS" scheme="https://jeromexiong.github.io/tags/iOS/"/>
    <category term="源码分析" scheme="https://jeromexiong.github.io/tags/%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
    <category term="底层原理" scheme="https://jeromexiong.github.io/tags/%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    <content>
      <![CDATA[<h2 id="一句话概括">一句话概括</h2><blockquote><p>XXX 本质上就是一个 <strong>YYY</strong>，它通过 <strong>ZZZ</strong> 机制实现了…… 如果只记住一句，就这句。</p></blockquote><h2 id="它是干什么的？">它是干什么的？</h2><p>用一句话说清楚这个技术/工具解决什么问题。</p><h2 id="源码走读">源码走读</h2><h3 id="入口">入口</h3><figure class="highlight swift"><table><tbody><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">// 关键入口方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">func</span> <span class="title function_">load</span>() {</span><br><span class="line">    <span class="comment">// 1. 检查缓存</span></span><br><span class="line">    <span class="comment">// 2. 发起请求</span></span><br><span class="line">    <span class="comment">// 3. 解析数据</span></span><br><span class="line">    <span class="comment">// 4. 回调通知</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h3 id="核心流程">核心流程</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">request → 拦截器链 → 缓存检查 → 网络请求 → 解析器 → 回调</span><br><span class="line">                    ↓</span><br><span class="line">               命中缓存→ 直接返回</span><br></pre></td></tr></tbody></table></figure><h3 id="设计亮点">设计亮点</h3><blockquote><p>💡 源码里最精彩的设计：</p></blockquote><figure class="highlight swift"><table><tbody><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="comment">// 用协议 + 泛型实现了类型安全的回调</span></span><br><span class="line"><span class="keyword">protocol</span> <span class="title class_">Handler</span>&lt;<span class="type">T</span>&gt; {</span><br><span class="line">    <span class="keyword">associatedtype</span> <span class="type">T</span></span><br><span class="line">    <span class="keyword">func</span> <span class="title function_">handle</span>(<span class="keyword">_</span> <span class="params">data</span>: <span class="type">T</span>)</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h2 id="对比其他方案">对比其他方案</h2><ul><li><strong>旧方案</strong>：XX 方式，问题是……</li><li><strong>新方案</strong>：YY 方式，优势在……</li><li><strong>本质区别</strong>：从 A 模式变成了 B 模式</li></ul><h2 id="最佳实践">最佳实践</h2><figure class="highlight swift"><table><tbody><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="comment">// 推荐的用法</span></span><br><span class="line"><span class="keyword">let</span> config <span class="operator">=</span> <span class="type">Config</span> {</span><br><span class="line">    <span class="variable">$0</span>.timeout <span class="operator">=</span> <span class="number">10</span></span><br><span class="line">    <span class="variable">$0</span>.retryCount <span class="operator">=</span> <span class="number">3</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><h2 id="常见误区">常见误区</h2><blockquote><p>❌ <strong>误区</strong>：XX 可以解决所有问题<br>✅ <strong>事实</strong>：它只适合 YY 场景，ZZ 场景应该用别的</p></blockquote>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>从源码层面剖析 XX 的实现原理，知其然更知其所以然</summary>
    <title>深入理解 XXX</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="dev" scheme="https://jeromexiong.github.io/categories/dev/"/>
    <category term="复盘" scheme="https://jeromexiong.github.io/tags/%E5%A4%8D%E7%9B%98/"/>
    <category term="项目管理" scheme="https://jeromexiong.github.io/tags/%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86/"/>
    <category term="总结" scheme="https://jeromexiong.github.io/tags/%E6%80%BB%E7%BB%93/"/>
    <content>
      <![CDATA[<h2 id="📊-本期概览">📊 本期概览</h2><table><thead><tr><th>维度</th><th>数据</th></tr></thead><tbody><tr><td>完成功能</td><td>12 个</td></tr><tr><td>修复 Bug</td><td>47 个</td></tr><tr><td>代码提交</td><td>186 次</td></tr><tr><td>迭代周期</td><td>4 个 Sprint</td></tr></tbody></table><h2 id="✅-做对了">✅ 做对了</h2><h3 id="1-架构先行">1. 架构先行</h3><p>在功能开发前花了一周做架构评审，后期几乎没有大改。</p><h3 id="2-自动化测试">2. 自动化测试</h3><p>覆盖率从 30% 提升到 85%，回归 Bug 大幅减少。</p><h2 id="❌-踩坑记录">❌ 踩坑记录</h2><h3 id="1-依赖升级过早">1. 依赖升级过早</h3><blockquote><p>第三周升级了 XXX 库到 3.0，导致兼容性问题浪费 2 天。</p></blockquote><p><strong>教训</strong>：依赖升级应该安排在迭代末尾，且必须有完整测试覆盖。</p><h3 id="2-需求理解偏差">2. 需求理解偏差</h3><blockquote><p>花了 3 天做的功能，实际上产品要的是另一种交互。</p></blockquote><p><strong>教训</strong>：开发前必须出交互原型确认，不能只看 PRD。</p><h2 id="🎯-下期计划">🎯 下期计划</h2><table><thead><tr><th>优先级</th><th>事项</th><th>预期</th></tr></thead><tbody><tr><td>P0</td><td>性能优化</td><td>首屏 &lt; 1s</td></tr><tr><td>P1</td><td>文档补全</td><td>API 文档 100%</td></tr><tr><td>P2</td><td>重构旧模块</td><td>消除技术债</td></tr></tbody></table><h2 id="💡-经验沉淀">💡 经验沉淀</h2><blockquote><p>每次复盘最有价值的不是记录做了什么，而是 <strong>总结出下次可以复用的判断标准</strong>。</p></blockquote>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E9%A1%B9%E7%9B%AE%E5%A4%8D%E7%9B%98/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/%E5%B7%A5%E5%85%B7/template-%E9%A1%B9%E7%9B%AE%E5%A4%8D%E7%9B%98/"/>
    <published>2026-06-16T04:00:00.000Z</published>
    <summary>项目季度复盘——做对了什么、踩了什么坑、下次怎么改进</summary>
    <title>2026 Q2 开发日志：XX 项目复盘</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="CI/CD" scheme="https://jeromexiong.github.io/categories/CI-CD/"/>
    <category term="Hexo" scheme="https://jeromexiong.github.io/tags/Hexo/"/>
    <category term="GitHub Actions" scheme="https://jeromexiong.github.io/tags/GitHub-Actions/"/>
    <category term="CI/CD" scheme="https://jeromexiong.github.io/tags/CI-CD/"/>
    <category term="博客" scheme="https://jeromexiong.github.io/tags/%E5%8D%9A%E5%AE%A2/"/>
    <category term="自动化部署" scheme="https://jeromexiong.github.io/tags/%E8%87%AA%E5%8A%A8%E5%8C%96%E9%83%A8%E7%BD%B2/"/>
    <content>
      <![CDATA[<p>Hexo 生成的是静态文件，传统做法是本地 <code>hexo g -d</code> 推送到 Pages 仓库。有了 GitHub Actions 后，每次 <code>git push</code> 源码仓库就能自动构建部署，解放本地环境。</p><p>本文记录完整的配置流程。</p><h2 id="整体思路">整体思路</h2><p>两个仓库分工：</p><ul><li><strong>源码仓库</strong>（<code>jeromexiong/blog</code>）— 存 Hexo 源码、文章、主题配置</li><li><strong>Pages 仓库</strong>（<code>jeromexiong/jeromexiong.github.io</code>）— 存构建产物（<code>public/</code> 目录），GitHub Pages 从这读取</li></ul><p>CI/CD 要做的就是：源码仓库收到 push → 自动构建 → 推送到 Pages 仓库。</p><h2 id="一、生成-SSH-Deploy-Key">一、生成 SSH Deploy Key</h2><p>为了让 GitHub Actions 有权限写入 Pages 仓库，需要一对 SSH 密钥。公钥给 Pages 仓库，私钥给源码仓库。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t ed25519 -f ~/blog-deploy-key -N <span class="string">""</span> -C <span class="string">"deploy"</span></span><br></pre></td></tr></tbody></table></figure><p>这会生成两个文件：</p><ul><li><code>blog-deploy-key</code> — 私钥</li><li><code>blog-deploy-key.pub</code> — 公钥</li></ul><h2 id="二、配置-GitHub">二、配置 GitHub</h2><h3 id="添加-Deploy-Key（Pages-仓库）">添加 Deploy Key（Pages 仓库）</h3><ol><li>打开 <code>https://github.com/jeromexiong/jeromexiong.github.io/settings/keys</code></li><li>点 <strong>Add deploy key</strong></li><li><strong>Title</strong>: <code>Blog CI/CD</code></li><li><strong>Key</strong>: 粘贴 <code>blog-deploy-key.pub</code> 的内容</li><li><strong>Allow write access</strong>: ✅ <strong>务必勾上</strong></li><li>点 <strong>Add key</strong></li></ol><h3 id="添加-Secret（源码仓库）">添加 Secret（源码仓库）</h3><ol><li>打开 <code>https://github.com/jeromexiong/blog/settings/secrets/actions</code></li><li>点 <strong>New repository secret</strong></li><li><strong>Name</strong>: <code>DEPLOY_KEY</code></li><li><strong>Secret</strong>: 粘贴 <code>blog-deploy-key</code>（私钥）的全部内容</li><li>点 <strong>Add secret</strong></li></ol><h2 id="三、编写-Workflow-文件">三、编写 Workflow 文件</h2><p>在源码仓库创建 <code>.github/workflows/deploy.yml</code>：</p><figure class="highlight yaml"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">Blog</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span> [<span class="string">master</span>]</span><br><span class="line">  <span class="attr">workflow_dispatch:</span></span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">build-and-deploy:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">actions/checkout@v4</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">actions/setup-node@v4</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">node-version:</span> <span class="number">20</span></span><br><span class="line">          <span class="attr">cache:</span> <span class="string">npm</span></span><br><span class="line">          <span class="attr">cache-dependency-path:</span> <span class="string">package-lock.json</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Install</span> <span class="string">dependencies</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">npm</span> <span class="string">ci</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Generate</span> <span class="string">static</span> <span class="string">files</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">npx</span> <span class="string">hexo</span> <span class="string">generate</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">to</span> <span class="string">jeromexiong.github.io</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">peaceiris/actions-gh-pages@v4</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">deploy_key:</span> <span class="string">${{</span> <span class="string">secrets.DEPLOY_KEY</span> <span class="string">}}</span></span><br><span class="line">          <span class="attr">external_repository:</span> <span class="string">jeromexiong/jeromexiong.github.io</span></span><br><span class="line">          <span class="attr">publish_dir:</span> <span class="string">./public</span></span><br><span class="line">          <span class="attr">publish_branch:</span> <span class="string">master</span></span><br><span class="line">          <span class="attr">force_orphan:</span> <span class="literal">true</span></span><br></pre></td></tr></tbody></table></figure><p>关键点说明：</p><table><thead><tr><th>配置项</th><th>含义</th></tr></thead><tbody><tr><td><code>branches: [master]</code></td><td>只在 master 分支推送时触发</td></tr><tr><td><code>workflow_dispatch</code></td><td>支持在 GitHub 页面手动触发</td></tr><tr><td><code>peaceiris/actions-gh-pages</code></td><td>社区成熟的 Pages 部署 Action</td></tr><tr><td><code>deploy_key</code></td><td>引用上一步配的 Secret</td></tr><tr><td><code>force_orphan: true</code></td><td>每次都生成独立 commit，保持产物仓库干净</td></tr></tbody></table><h2 id="四、Dependabot-自动更新依赖">四、Dependabot 自动更新依赖</h2><p>除了部署自动化，还可以通过 Dependabot 让依赖保持最新，避免 Hexo 插件因版本过旧产生安全漏洞或兼容问题。</p><p>在仓库创建 <code>.github/dependabot.yml</code>：</p><figure class="highlight yaml"><table><tbody><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="attr">version:</span> <span class="number">2</span></span><br><span class="line"><span class="attr">updates:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">package-ecosystem:</span> <span class="string">npm</span></span><br><span class="line">  <span class="attr">directory:</span> <span class="string">"/"</span></span><br><span class="line">  <span class="attr">schedule:</span></span><br><span class="line">    <span class="attr">interval:</span> <span class="string">daily</span></span><br><span class="line">  <span class="attr">open-pull-requests-limit:</span> <span class="number">20</span></span><br></pre></td></tr></tbody></table></figure><p>配置说明：</p><table><thead><tr><th>配置项</th><th>含义</th></tr></thead><tbody><tr><td><code>package-ecosystem: npm</code></td><td>监控 npm 依赖（package.json）</td></tr><tr><td><code>interval: daily</code></td><td>每天检查一次更新</td></tr><tr><td><code>open-pull-requests-limit: 20</code></td><td>最多同时开 20 个更新 PR</td></tr></tbody></table><p>Dependabot 每天自动检查依赖是否有新版本，有更新就提 PR。CI/CD 工作流会在 PR 上自动跑构建验证，通过后手动合并即可。依赖安全和自动部署就形成了一个完整的闭环。</p><h2 id="五、推送触发">五、推送触发</h2><p>把 workflow 文件和私钥保护配置一起提交：</p><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 确保私钥不被提交到仓库</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">".deploy-key"</span> &gt;&gt; .gitignore</span><br><span class="line"></span><br><span class="line">git add .gitignore .github/workflows/deploy.yml</span><br><span class="line">git commit -m <span class="string">"ci: add GitHub Actions deploy workflow"</span></span><br><span class="line">git push origin master</span><br></pre></td></tr></tbody></table></figure><p>Push 完成后，到 GitHub 仓库的 <strong>Actions</strong> 页面就能看到构建任务在跑。绿色勾表示部署成功，访问 <code>https://jeromexiong.github.io</code> 即可看到最新内容。</p><h2 id="效果">效果</h2><p>之后的工作流就是纯粹的：</p><figure class="highlight plaintext"><table><tbody><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">git add .</span><br><span class="line">git commit -m "新文章"</span><br><span class="line">git push origin master</span><br><span class="line"># 剩下的交给 Actions</span><br></pre></td></tr></tbody></table></figure><p>不用本地装 Node、不用记住 <code>hexo g -d</code>、不依赖任何本地环境。换电脑、重装系统都不影响发布。</p>]]>
    </content>
    <id>https://jeromexiong.github.io/2026/06/16/CI-CD/Hexo%E5%8D%9A%E5%AE%A2GitHub-Actions%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</id>
    <link href="https://jeromexiong.github.io/2026/06/16/CI-CD/Hexo%E5%8D%9A%E5%AE%A2GitHub-Actions%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/"/>
    <published>2026-06-16T03:00:00.000Z</published>
    <summary>通过GitHub Actions实现Hexo博客自动构建部署，push源码即可自动发布到GitHub Pages。</summary>
    <title>Hexo博客GitHub Actions自动部署指南</title>
    <updated>2026-06-16T08:17:05.711Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="创业" scheme="https://jeromexiong.github.io/categories/%E5%88%9B%E4%B8%9A/"/>
    <category term="千脉" scheme="https://jeromexiong.github.io/tags/%E5%8D%83%E8%84%89/"/>
    <category term="复盘" scheme="https://jeromexiong.github.io/tags/%E5%A4%8D%E7%9B%98/"/>
    <category term="项目" scheme="https://jeromexiong.github.io/tags/%E9%A1%B9%E7%9B%AE/"/>
    <category term="技术栈" scheme="https://jeromexiong.github.io/tags/%E6%8A%80%E6%9C%AF%E6%A0%88/"/>
    <content>
      <![CDATA[<p>本文对千脉(kilomind)科技创立以来的项目进行复盘总结，涵盖项目列表、技术栈选择与团队规范等方面。</p><h2 id="创立初期至今的项目">创立初期至今的项目</h2><blockquote><p>千脉软件下载：<a href="https://share.weiyun.com/51ji0M2">https://share.weiyun.com/51ji0M2</a> 密码：r3v1d7</p></blockquote><ul><li>[x] 星客漫游<ol><li>服务端<a href="https://gitee.com/QmaiMedia/startwork.git">PHP</a></li><li>公众号<a href="https://gitee.com/QmaiMedia/startwork.git">PHP</a></li><li>移动端<a href="https://gitee.com/QmaiMedia/StartWalkAndroid.git">Android Java</a></li><li>后台管理 <a href="https://gitee.com/QmaiMedia/startwork.git">PHP</a></li></ol></li><li>[x] <a href="https://kilomusic.cn/">乐脉</a><ol><li>服务端 <a href="https://gitee.com/QmaiMedia/KiloMusic.git">PHP</a></li><li>小程序<a href="https://gitee.com/QmaiMedia/YueMai.git">官方语言</a></li><li>前台管理<a href="https://gitee.com/QmaiMedia/QmaiMusic.git">Vue</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/Console-YueMai.git">Vue</a></li></ol></li><li>[x] 拍管家<ol><li>服务端<a href="https://gitee.com/QmaiMedia/paivipServer.git">PHP</a></li><li>H5<a href="https://gitee.com/QmaiMedia/thirds-photos-web.git">Vue</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/thirds-photos.git">Vue</a></li></ol></li><li>[x] 声动太空<ol><li>服务端 <a href="https://gitee.com/QmaiMedia/shengdongSpace.git">PHP</a></li><li>H5<a href="https://gitee.com/QmaiMedia/acoustic_spaceweb.git">Vue</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/acouistic-console.git">Vue</a></li></ol></li><li>[x] 艾宠星球<ol><li>服务端 <a href="https://gitee.com/QmaiMedia/lovePet.git">PHP</a></li><li>小程序<a href="https://gitee.com/QmaiMedia/pet-planet.git">官方语言</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/aichong-console.git">Vue</a></li></ol></li><li>[x] 久翌<ol><li>服务端 <a href="https://gitee.com/QmaiMedia/jiuyiServer.git">PHP</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/jiuyiConsole.git">Vue</a></li><li>数据抓取插件 <a href="https://gitee.com/kilomind/jiuyi_grab_data_chrome_plugin.git">Vue</a></li></ol></li><li>[x] 智能跑道<ol><li>服务端<a href="https://gitee.com/QmaiMedia/smart-runway.git">NodeJS</a></li><li>PC端<a href="https://gitee.com/QmaiMedia/LightBoardController.git">C++</a></li><li>移动端<a href="https://gitee.com/QmaiMedia/IntelligentRunwayAndroid.git">Android Java</a>、<a href="https://gitee.com/QmaiMedia/smart-runway-ios.git">iOS Swfit</a></li></ol></li><li>[x] PC录像打点<ol><li>PC端<code>C++</code></li></ol></li><li>[x] 义虎演艺<ol><li>服务端 <a href="https://gitee.com/kilomind/yihuServer.git">PHP</a></li><li>小程序<a href="https://gitee.com/kilomind/yihuMNP.git">官方语言</a></li><li>后台管理<a href="https://gitee.com/kilomind/yihuServer.git">Vue</a></li></ol></li><li>[x] AI人脸融合<ol><li>服务端 <a href="https://gitee.com/kilomind/faceMerge.git">PHP</a></li><li>H5<a href="https://gitee.com/kilomind/faceMerge-h5.git">Vue</a></li><li>后台管理<a href="https://gitee.com/QmaiMedia/faceMerge-console.git">Vue</a></li></ol></li><li>[x] 脉向太空<ol><li>服务端 <a href="https://gitee.com/QmaiMedia/qmaiSpaceServer.git">PHP</a></li><li>小程序<a href="https://gitee.com/kilomind/crowdfunding.git">官方语言</a></li></ol></li><li>[x] 广特-智能语音<ol><li>服务端 <a href="https://gitee.com/kilomind/guangte-server.git">NodeJS</a></li><li>后台管理<a href="https://gitee.com/kilomind/guangte-web.git">Vue</a></li></ol></li><li>[x] 艾宠-智能寄养宠屋<ol><li>服务端 <a href="https://gitee.com/kilomind/ihome-server.git">NodeJS</a></li><li>小程序<a href="https://gitee.com/kilomind/ihome-mnp.git">官方语言</a></li><li>硬件<a href="https://gitee.com/kilomind/ihome-Android.git">Android Java</a></li><li><a href="https://gitee.com/QmaiMedia/aichong-console.git">后台管理 同<code>艾宠星球</code></a></li></ol></li><li>[x] 一二接龙<ol><li>服务端 <a href="https://gitee.com/kilomind/solitaire-server.git">NodeJS</a></li><li>小程序<a href="https://gitee.com/kilomind/solitaire-mnp.git">官方语言</a></li></ol></li><li>[x] 机器人远程控制<ol><li>移动端<a href="https://gitee.com/kilomind/IPC-Client.git">Android Java</a></li></ol></li><li>[x] <a href="http://kilomeeting.kilomind.cn">kilomeeting</a><ol><li>服务端 <a href="https://gitee.com/kilomind/kilomeeting-server.git">NodeJS</a>、<a href="https://gitee.com/kilomind/kilomeeting-mqtt.git">MQTT</a></li><li>PC端  <a href="https://gitee.com/kilomind/kilomeeting-win.git"><code>C++</code></a></li><li>移动端<a href="https://gitee.com/kilomind/kilomeeting-android.git">Android Java</a>、<a href="https://gitee.com/kilomind/kilomeeting-ios.git">iOS Swfit</a></li></ol></li><li>[ ] 国祥世界-智能课桌<ol><li>服务端  <a href="https://gitee.com/kilomind/smartdesk-server.git">PHP</a></li><li>硬件 <a href="https://gitee.com/kilomind/smartdesk-launcher.git">iPad</a></li><li>移动端<a href="https://gitee.com/kilomind/smartdesk-android.git">Android Java</a>、<a href="https://gitee.com/kilomind/smartdesk-ios.git">iOS Swift</a></li></ol></li><li>[ ] 红白题<ol><li>服务端  <a href="https://gitee.com/kilomind/red-white-server.git">PHP</a></li><li>小程序<a href="">官方语言</a></li><li>移动端<a href="">Android Java</a>、<a href="">iOS Swfit</a></li></ol></li><li>[ ] 视频名片<ol><li>服务端 <a href="https://gitee.com/kilomind/videocard-server.git">NodeJS</a></li><li>小程序 <a href="https://gitee.com/kilomind/card.git">官方语言</a></li></ol></li></ul><h2 id="主要技术">主要技术</h2><h3 id="服务端">服务端</h3><ul><li>NodeJS 8<ol><li>Express</li></ol></li><li>PHP<ol><li>ThinkPHP</li></ol></li></ul><h3 id="移动端">移动端</h3><ul><li>Android<ol><li>Java</li></ol></li><li>iOS<ol><li>Swift</li></ol></li></ul><h2 id="功能组件化">功能组件化</h2><h2 id="Git-项目规范">Git 项目规范</h2><h3 id="命名规范-项目名称-平台-描述">命名规范 <code>[项目名称]-[平台]-[描述]</code></h3><ul><li>[项目名称]</li><li>[平台]  包含不限于以下平台<ol><li><code>android</code>Android端</li><li><code>ios</code>iOS端</li><li><code>h5</code>微信H5</li><li><code>web</code>网站前台</li><li><code>console</code>网站后台</li><li><code>server</code>服务端</li><li><code>mnp</code>小程序</li><li><code>win</code>PC端</li><li><code>launcher</code>Android启动器</li></ol></li><li>[描述] 可选描述</li></ul><h2 id="优化">优化</h2><p>内部</p><p>自我反省/他人问题/解决方法</p><p>外部</p><p>评估客户/拓展客户</p>]]>
    </content>
    <id>https://jeromexiong.github.io/2022/01/01/iOS-Swift/kilomind%E5%A4%8D%E7%9B%98/</id>
    <link href="https://jeromexiong.github.io/2022/01/01/iOS-Swift/kilomind%E5%A4%8D%E7%9B%98/"/>
    <published>2022-01-01T10:00:00.000Z</published>
    <summary>复盘千脉(kilomind)创立至今的项目历程，总结技术栈选择与团队协作经验。</summary>
    <title>kilomind复盘</title>
    <updated>2026-06-16T08:17:05.714Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="dev" scheme="https://jeromexiong.github.io/categories/dev/"/>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="Swift" scheme="https://jeromexiong.github.io/tags/Swift/"/>
    <category term="SQLite" scheme="https://jeromexiong.github.io/tags/SQLite/"/>
    <category term="objc" scheme="https://jeromexiong.github.io/tags/objc/"/>
    <category term="数据持久化" scheme="https://jeromexiong.github.io/tags/%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96/"/>
    <category term="CoreData" scheme="https://jeromexiong.github.io/tags/CoreData/"/>
    <content>
      <![CDATA[<p>数据持久化是 iOS 开发中的基础技能。本文详细介绍 iOS 平台下五种主流的数据持久化方式及其使用场景。</p><h1>一、iOS数据持久化方式</h1><ul><li>XML属性列表（plist）归档</li><li>Preference(偏好设置)，本质还是通过"plist"来存储数据, 但是使用更简单(无需关注文件、文件夹路径和名称)</li><li>NSKeyedArchiver归档(NSCoding)，可以把任何对象, 直接保存为文件的方式。</li><li>SQLite3，当非常大量的数据存储时使用</li><li>Core Data，就是对SQLite的封装</li></ul><blockquote><p>关于bundle路径和sandbox沙河路径：<br>（1）bundle路径：应用程序 (APP) 在手机里面的安装路径<br>（2）沙河路径：专门用来存储App自己数据的一个路径，iOS为每个app都分配了一个专门用来存储这个app自身的一些数据的路径</p></blockquote><hr><h1>二、应用沙盒(应用程序的文件夹)</h1><ol><li>打印沙盒路径</li></ol><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">NSLog</span>(<span class="string">@"%@"</span>,<span class="built_in">NSHomeDirectory</span>());</span><br></pre></td></tr></tbody></table></figure><ol start="2"><li>使用Documents目录进行数据持久化的保存，我们平时操作数据主要使用Documents目录</li></ol><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">Swift</button><button type="button" class="tab">objc</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight swift"><table><tbody><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="comment">// 1</span></span><br><span class="line"><span class="keyword">let</span> path <span class="operator">=</span> <span class="type">NSSearchPathForDirectoriesInDomains</span>(.documentDirectory, .userDomainMask, <span class="literal">true</span>)[<span class="number">0</span>] <span class="operator">+</span> <span class="string">"/test.plist"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2</span></span><br><span class="line"><span class="keyword">let</span> url <span class="operator">=</span> <span class="type">FileManager</span>.default.urls(for: .documentDirectory, in: .userDomainMask)[<span class="number">0</span>].appendingPathComponent(<span class="string">"test.plist"</span>)</span><br></pre></td></tr></tbody></table></figure></div><div class="tab-item-content"><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">NSString</span> *path = [[<span class="built_in">NSSearchPathForDirectoriesInDomains</span>(<span class="built_in">NSDocumentDirectory</span>, <span class="built_in">NSUserDomainMask</span>, <span class="literal">YES</span>) lastObject] stringByAppendingPathComponent:<span class="string">@"test.plist"</span>];</span><br></pre></td></tr></tbody></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><blockquote><ul><li>参数1：第一个参数指定了搜索的路径名称，NSDocumentDirectory表示是在Documents中寻找，NSCachesDirectory的话就是在cache文件夹中寻找<br>常用枚举：<br>NSDocumentDirectory<br>NSCachesDirectory</li></ul></blockquote><ul><li>参数2：<br>NSUserDomainMask = 1,//用户主目录中<br>NSLocalDomainMask = 2,//当前机器中<br>NSNetworkDomainMask = 4,//网络中可见的主机<br>NSSystemDomainMask = 8,//系统目录,不可修改(/System)<br>NSAllDomainsMask = 0x0ffff,//全部</li><li>参数3：是否展开波浪线，一般为YES展开</li></ul><h5 id="Documents：">Documents：</h5><p>需要保存由应用程序本身产生的文件或者数据，例如：游戏进度、涂鸦软件的绘图<br>目录中的文件会被自动保存在 iCloud<br>注意：不要保存从网络上下载的文件，否则会无法上架！</p><h5 id="tmp：">tmp：</h5><p>保存临时文件，后续不需要使用<br>tmp目录中的文件，系统会自动清理<br>重新启动手机，tmp 目录会被清空<br>系统磁盘空间不足时，系统也会自动清理<br>路径获取：<code>NSString *tmp = NSTemporaryDirectory();</code></p><h5 id="Library-Caches：">Library/Caches：</h5><p>保存临时文件，后续需要使用，例如：缓存图片，离线数据(地图数据)<br>系统不会清理cache目录中的文件<br>就要求程序开发时，必须提供cache目录的清理解决方案<br>路径获取：利用<code>NSSearchPathForDirectoriesInDomains</code>函数(将函数的第2个参数改为：<code>NSCachesDirectory</code>即可)</p><h5 id="Library-Preference：">Library/Preference：</h5><p>保存应用的所有偏好设置，使用 NSUserDefault直接读写，iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录。该目录由系统管理, 无需我们来管理。通常用来存储一些基本的软件配置信息, 比如记住密码、自动登录等。<br>路径获取： 通过NSUserDefaults类存取该目录下的设置信息</p><hr><h1>三、使用方法</h1><h3 id="1、属性列表">1、属性列表</h3><ul><li>属性列表是一种XML格式的文件，拓展名为plist，如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型，就可以使用，</li><li>注意：不能存储自定义对象，会失败的</li><li>存方法：writeToFile</li><li>读方法：如字典， dictionaryWithContentsOfFile</li></ul><h3 id="2、偏好设置">2、偏好设置</h3><ul><li>通过NSUserDefaults就能直接访问软件的偏好设置(Library/Preferences)<br>UserDefaults设置数据时，不是立即写入，而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了，为解决上述问题，通过调用synchornize方法强制写入。</li><li>写入步骤：<br>（1） 获取偏好设置对象</li></ul><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">Swift</button><button type="button" class="tab">objc</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> userDefault <span class="operator">=</span> <span class="type">UserDefaults</span>.standard</span><br></pre></td></tr></tbody></table></figure></div><div class="tab-item-content"><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">NSUserDefaults</span> *userDefault = [<span class="built_in">NSUserDefaults</span> standardUserDefaults];</span><br></pre></td></tr></tbody></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><p>（2）写入</p><figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">userDefault.setValue(switcher.isOn, forKey: <span class="string">"key_name"</span>)</span><br><span class="line"><span class="comment">// [userDefault setBool:switcher.isOn forKey:@"key_name"];</span></span><br></pre></td></tr></tbody></table></figure><p>（3）同步</p><figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">userDefault.synchronize()</span><br><span class="line"><span class="comment">// [userDefault synchronize];</span></span><br></pre></td></tr></tbody></table></figure><ul><li>读取步骤：<br>（1） 获取偏好设置对象</li></ul><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">NSUserDefaults</span> *userDefault = [<span class="built_in">NSUserDefaults</span> standardUserDefaults];</span><br></pre></td></tr></tbody></table></figure><p>（2）用一个变量接收</p><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">switcher.on = [userDefault boolForKey:<span class="string">@"key_name"</span>];</span><br></pre></td></tr></tbody></table></figure><h3 id="3、自定义对象归档-NSKeyedArchiver">3、自定义对象归档 NSKeyedArchiver</h3><blockquote><p>注意： 必须遵守NSCoding协议的对象才可以进行归档解档，默NSString、NSDictionary、NSArray、NSData、NSNumber等类型已遵守NSCoding协议，可以直接归档解档。</p></blockquote><h6 id="（1）遵守NSCoding协议，实现协议方法">（1）遵守NSCoding协议，实现协议方法</h6><p>NSCoding协议中两个方法，一般写在模型中：</p><ul><li>归档调用<br>一般在这个方法里面指定如何归档对象中的每个实例变量，可以使用encodeObject:forKey:方法归档实例变量</li></ul><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="type">void</span>)encodeWithCoder:(<span class="built_in">NSCoder</span> *)aCoder;</span><br><span class="line">[encoder encodeObject:<span class="keyword">self</span>.name forKey:<span class="string">@"name"</span>];</span><br></pre></td></tr></tbody></table></figure><ul><li>解档调用<br>一般在这个方法里面指定如何解码文件中的数据为对象的实例变量，可以使用decodeObject:forKey方法解码实例变量</li></ul><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithCoder:(<span class="built_in">NSCoder</span> *)aDecoder;</span><br><span class="line"><span class="keyword">self</span>.name = [decoder decodeObjectForKey:<span class="string">@"name"</span>];</span><br></pre></td></tr></tbody></table></figure><blockquote><p>initWithCoder原理:只要解析文件就会调用，xib,storyboard都是文件，因此只要解析这两个文件，就会调用initWithCoder，因此如果在storyboard使用自定义view,重写initWithCoder方法，一定要调用[super initWithCoder:]，因为只有系统才知道怎么解析storyboard，如果没有调用，就解析不了这个文件。</p></blockquote><h6 id="（2）归档一个对象（先获取路径path）">（2）归档一个对象（先获取路径path）</h6><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person *person = [[[Person alloc] init];</span><br><span class="line">[<span class="built_in">NSKeyedArchiver</span> archiveRootObject:person toFile:path];</span><br></pre></td></tr></tbody></table></figure><h6 id="（3）解档一个对象">（3）解档一个对象</h6><figure class="highlight objc"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Person *person = [<span class="built_in">NSKeyedUnarchiver</span> unarchiveObjectWithFile:path];</span><br></pre></td></tr></tbody></table></figure><blockquote><p>注意：<br>（1）如果父类也遵守了NSCoding协议，应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码，即也能被归档<br>（2）在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码，即也能被恢复</p></blockquote><h3 id="4、多个对象归档解档">4、多个对象归档解档</h3><p>使用archiveRootObject:toFile:方法可以将一个对象直接写入到一个文件中，但有时候可能想将多个对象写入到同一个文件中，那么就要使用NSData来进行归档对象，NSData可以为一些数据提供临时存储空间，以便随后写入文件，或者存放从磁盘读取的文件内容。可以使用[NSMutableData data]创建可变数据空间<br>（1） 归档步骤</p><figure class="highlight objc"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 新建一块可变数据区</span></span><br><span class="line"><span class="built_in">NSMutableData</span> *data = [<span class="built_in">NSMutableData</span> data];</span><br><span class="line"><span class="comment">// 将数据区连接到一个NSKeyedArchiver对象</span></span><br><span class="line"><span class="built_in">NSKeyedArchiver</span> *archiver = [[<span class="built_in">NSKeyedArchiver</span> alloc] initForWritingWithMutableData:data];</span><br><span class="line"><span class="comment">// 开始存档对象，存档的数据都会存储到NSMutableData中</span></span><br><span class="line">[archiver encodeObject:person1 forKey:<span class="string">@"person1"</span>];</span><br><span class="line">[archiver encodeObject:person2 forKey:<span class="string">@"person2"</span>];</span><br><span class="line"><span class="comment">// 存档完毕(一定要调用这个方法)</span></span><br><span class="line">[archiver finishEncoding];</span><br><span class="line"><span class="comment">// 将存档的数据写入文件</span></span><br><span class="line">[data writeToFile:path atomically:<span class="literal">YES</span>];</span><br></pre></td></tr></tbody></table></figure><p>（2） 解档步骤</p><figure class="highlight objc"><table><tbody><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="comment">// 从文件中读取数据</span></span><br><span class="line"><span class="built_in">NSData</span> *data = [<span class="built_in">NSData</span> dataWithContentsOfFile:path];</span><br><span class="line"><span class="comment">// 根据数据，解析成一个NSKeyedUnarchiver对象</span></span><br><span class="line"><span class="built_in">NSKeyedUnarchiver</span> *unarchiver = [[<span class="built_in">NSKeyedUnarchiver</span> alloc] initForReadingWithData:data];</span><br><span class="line">Person *person1 = [unarchiver decodeObjectForKey:<span class="string">@"person1"</span>];</span><br><span class="line">Person *person2 = [unarchiver decodeObjectForKey:<span class="string">@"person2"</span>];</span><br><span class="line"><span class="comment">// 恢复完毕</span></span><br><span class="line">[unarchiver finishDecoding];</span><br></pre></td></tr></tbody></table></figure>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/10/15/iOS-Swift/iOS%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96%E6%96%B9%E5%BC%8F/</id>
    <link href="https://jeromexiong.github.io/2021/10/15/iOS-Swift/iOS%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96%E6%96%B9%E5%BC%8F/"/>
    <published>2021-10-15T10:00:00.000Z</published>
    <summary>全面介绍 iOS 中 plist、偏好设置、归档、SQLite3 和 Core Data 五种数据持久化方式。</summary>
    <title>iOS数据持久化方式</title>
    <updated>2026-06-16T08:17:05.714Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="dev" scheme="https://jeromexiong.github.io/categories/dev/"/>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="Swift" scheme="https://jeromexiong.github.io/tags/Swift/"/>
    <category term="Xcode" scheme="https://jeromexiong.github.io/tags/Xcode/"/>
    <category term="离屏渲染" scheme="https://jeromexiong.github.io/tags/%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93/"/>
    <category term="阴影优化" scheme="https://jeromexiong.github.io/tags/%E9%98%B4%E5%BD%B1%E4%BC%98%E5%8C%96/"/>
    <content>
      <![CDATA[<p>本文汇总了 Xcode 开发中遇到的一些常见问题及其解决方法，帮助开发者快速定位和修复问题。</p><h3 id="Optimization-Opportunities-The-layer-is-using-dynamic-shadows-which-are-expensive-to-render-If-possible-try-setting-shadowPath-or-pre-rendering-the-shadow-into-an-image-and-putting-it-under-the-layer">Optimization Opportunities: The layer is using dynamic shadows which are expensive to render. If possible try setting shadowPath, or pre-rendering the shadow into an image and putting it under the layer.</h3><blockquote><p>这是因为没有设置shadowPath导致了离屏渲染<br>解决方法有两种：</p></blockquote><ol><li>通过明确地设置shadowPath来"引导"阴影渲染，例如</li></ol><figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">view.layer.shadowPath <span class="operator">=</span> <span class="type">UIBezierPath</span>(rect: view.bounds).cgPath</span><br></pre></td></tr></tbody></table></figure><ol start="2"><li>缓存<code>rasterization</code>(珊格化)</li></ol><figure class="highlight swift"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">view.layer.shouldRasterize <span class="operator">=</span> <span class="literal">true</span></span><br><span class="line">view.layer.rasterizationScale <span class="operator">=</span> <span class="type">UIScreen</span>.main.scale</span><br></pre></td></tr></tbody></table></figure>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/10/14/iOS-Swift/Xcode%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/</id>
    <link href="https://jeromexiong.github.io/2021/10/14/iOS-Swift/Xcode%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/"/>
    <published>2021-10-14T10:00:00.000Z</published>
    <summary>汇总 Xcode 开发中常见的离屏渲染与动态阴影优化问题及解决方案。</summary>
    <title>Xcode常见问题</title>
    <updated>2026-06-16T08:17:05.713Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="dev" scheme="https://jeromexiong.github.io/categories/dev/"/>
    <category term="Go" scheme="https://jeromexiong.github.io/categories/Go/"/>
    <category term="Go" scheme="https://jeromexiong.github.io/tags/Go/"/>
    <category term="Golang" scheme="https://jeromexiong.github.io/tags/Golang/"/>
    <category term="Iris" scheme="https://jeromexiong.github.io/tags/Iris/"/>
    <category term="Web框架" scheme="https://jeromexiong.github.io/tags/Web%E6%A1%86%E6%9E%B6/"/>
    <content>
      <![CDATA[<h2 id="序">序</h2><p>本文是基于<a href="https://github.com/kataras/iris">iris 12</a> 扩展编写的类似<a href="https://eggjs.org/zh-cn/intro/">eggjs</a>框架结构。这里就简单介绍一下什么是iris，iris主要侧重于Web开发，提供了Web开发的一系列功能组件，基于MVC开发模式。<em><strong>如果你想直接开始，请点击<a href="https://github.com/jeromexiong/stencil-go">stencil-go</a>。</strong></em></p><p><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/20211009111105.png" alt=""></p><p>因为我本人之前写nodejs比较多，所以在学习go的时候就找到iris这个框架，毕竟它的关于里面就有一句<code>A true successor of expressjs and laravel</code>😄。有了框架之后就得约束一下结构不是，不然大家都随心所欲的写就很混乱了，所以我就参照了eggjs的结构进行设计。（当然这只是我个人的想法，毕竟这也才是我的入门项目，多有不足，还请指教( ´▽｀)</p><h2 id="基础功能">基础功能</h2><h3 id="目录结构">目录结构</h3><p>这里就简单介绍下目录约定规范</p><figure class="highlight plaintext"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">stencil-go</span><br><span class="line">├── README.md</span><br><span class="line">├── app</span><br><span class="line">│   ├── bindata</span><br><span class="line">│   ├── controller</span><br><span class="line">│   ├── core</span><br><span class="line">│   ├── extend（可选）</span><br><span class="line">│   ├── middleware（可选）</span><br><span class="line">│   ├── model</span><br><span class="line">│   ├── router</span><br><span class="line">│   └── service（可选）</span><br><span class="line">├── build_linux.sh</span><br><span class="line">├── build_win64.bat</span><br><span class="line">├── config</span><br><span class="line">│   ├── config.default.yaml</span><br><span class="line">│   └── config.prod.yaml</span><br><span class="line">├── config.yml（可选）</span><br><span class="line">├── go.mod</span><br><span class="line">├── main.go</span><br><span class="line">├── output</span><br><span class="line">│   ├── logs （日志目录）</span><br><span class="line">│   └── stencil-go (可执行二进制文件)</span><br><span class="line">└── public（可选）</span><br><span class="line">    ├── css</span><br><span class="line">    ├── index.html</span><br><span class="line">    └── js</span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure><ul><li><code>app/bindata/**</code> 用于打包配置文件为二进制文件，具体参见<a href="https://github.com/jteeuwen/go-bindata">bindata</a></li><li><code>app/controller/**</code> 用于解析用户的输入，处理后返回相应的结果</li><li><code>app/core/**</code> 用于解析各种非常但又必须的方法，例如读取配置、初始化日志等</li><li><code>app/extend/**</code> 用于框架的扩展，可选</li><li><code>app/middleware/**</code> 用于编写中间件，可选</li><li><code>app/model/**</code> 用于编写模型文件</li><li><code>app/router/**</code> 用于配置 URL 路由规则</li><li><code>app/service/**</code> 用于编写业务逻辑层，可选，建议使用</li><li><code>build_*</code> 由于构建对应平台的二进制文件</li><li><code>config/config.{env}.js</code> 用于编写配置文件</li><li><code>config.yml</code> mysql数据库转 struct 工具，可选 （ <a href="https://github.com/xxjwxc/gormt/blob/master/README_zh_cn.md">gormt</a>配置文件</li><li><code>main.go</code> 入口文件，用于加载配置并启动服务</li><li><code>public/**</code> 用于放置静态资源，可选</li><li><code>output/**</code> 用于放置日志等生成的文件</li></ul><h2 id="go-指令">go 指令</h2><h3 id="清除模块缓存-GOPATH-pkg-mod">清除模块缓存<code>$GOPATH/pkg/mod</code></h3><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go clean --modcache</span><br></pre></td></tr></tbody></table></figure><h3 id="安装打包器-go-bindata">安装打包器 <a href="https://github.com/jteeuwen/go-bindata">go-bindata</a></h3><blockquote><p>go-bindata -pkg &lt;指定包名&gt; -o &lt;目标输出文件,可包含路径&gt; &lt;源文件,可包含路径&gt;</p></blockquote><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">go get -u github.com/go-bindata/go-bindata/v3/go-bindata</span><br><span class="line">go-bindata -h</span><br></pre></td></tr></tbody></table></figure><p><code>go-bindata</code>如果不在环境变量中需要手动配置。在<code>~/.bash_profile</code>中添加以下行:</p><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># golang</span></span></span><br><span class="line">export PATH=~/go/bin:$PATH</span><br></pre></td></tr></tbody></table></figure><h3 id="mysql数据库转-struct-工具-gormt">mysql数据库转 struct 工具 <a href="https://github.com/xxjwxc/gormt/blob/master/README_zh_cn.md">gormt</a></h3><p>需要修改根目录下的<code>config.yml</code></p><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">go get -u -v github.com/xxjwxc/gormt@master</span><br><span class="line">gormt -h</span><br><span class="line">gormt</span><br></pre></td></tr></tbody></table></figure><p>⚠️修改配置文件后，需要运行打包命令使配置生效</p><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go-bindata -pkg config_data -o app/bindata/config/config_data.go config/...</span><br></pre></td></tr></tbody></table></figure><h3 id="本地https测试-mkcert">本地<code>https</code>测试 <a href="https://github.com/FiloSottile/mkcert">mkcert</a></h3><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mkcert -install</span><br><span class="line">mkcert local.cn "*.local.cn" localhost 127.0.0.1 ::1</span><br></pre></td></tr></tbody></table></figure><h2 id="常见问题">常见问题</h2><h3 id="go-updates-to-go-mod-needed-disabled-by-mod-readonly-packages-Load-error">go: updates to go.mod needed, disabled by -mod=readonly : packages.Load error</h3><figure class="highlight shell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go mod tidy</span><br></pre></td></tr></tbody></table></figure><h2 id="参考文档">参考文档</h2><ul><li><a href="https://www.iris-go.com/docs/#/?id=installation">iris-go 文档</a> 官方文档</li><li><a href="https://docs.iris-go.com/iris/getting-started/installation">iris-go 文档</a> 官方文档2</li><li><a href="https://www.kancloud.cn/terry/iris/1683304">iris12 文档</a> 三方中文文档</li><li><a href="http://www.topgoer.com/">go语言介绍</a>  三方中文文档</li><li><a href="https://www.kancloud.cn/sliver_horn/gorm/1861157">GORM V2 中文文档</a> 看云文档</li><li><a href="https://gorm.io/docs/gorm_config.html">GORM V2 英文文档</a> 官方文档</li></ul>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/10/09/%E5%B7%A5%E5%85%B7/iris-go%E5%90%8E%E5%8F%B0%E6%A8%A1%E7%89%88/</id>
    <link href="https://jeromexiong.github.io/2021/10/09/%E5%B7%A5%E5%85%B7/iris-go%E5%90%8E%E5%8F%B0%E6%A8%A1%E7%89%88/"/>
    <published>2021-10-09T02:00:11.000Z</published>
    <summary>基于Iris框架仿Egg.js结构打造的Go Web后台模板，涵盖目录规范、打包部署与常见问题。</summary>
    <title>iris-go后台模版</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="mac" scheme="https://jeromexiong.github.io/categories/mac/"/>
    <category term="Mac" scheme="https://jeromexiong.github.io/tags/Mac/"/>
    <category term="软件推荐" scheme="https://jeromexiong.github.io/tags/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    <category term="macOS" scheme="https://jeromexiong.github.io/tags/macOS/"/>
    <content>
      <![CDATA[<p>本文整理了 Mac 平台上一系列实用软件和开发工具，从系统配置到日常应用一应俱全，帮助你快速搭建高效的工作环境。</p><h2 id="系统软件">系统软件</h2><ol><li><a href="https://www.jianshu.com/p/b7b789a2ed2c">homebrew</a></li><li><a href="https://www.jianshu.com/p/4fc53d7d7620">mysql</a></li><li><a href="https://github.com/pyenv/pyenv#homebrew-on-macos">pyenv</a></li><li><a href="https://www.runoob.com/w3cnote/nvm-manager-node-versions.html">nvm</a></li><li><a href="">redis</a> 直接<code>brew install redis</code>即可</li></ol><h2 id="Mac必装软件">Mac必装软件</h2><ol><li><a href="https://iina.io/">IINA</a> 最好用的音视频播放软件（可播放任何地址</li><li><a href="https://www.typora.io/">Typora</a> 最好用的Markdown编辑工具 （➕<code>PicGo</code>实现图片自动上传</li><li><a href="https://code.visualstudio.com/">VsCode</a> 最好用的代码编辑工具</li><li><a href="http://www.neatdownloadmanager.com/index.php/en/">Neat Download Manager</a> 最快速的下载工具</li><li><a href="https://github.com/electerm/electerm">Electerm</a> 开源的跨平台Shell管理工具</li><li><a href="http://www.hostbuf.com/">FinalShell</a> 最好用跨平台Shell管理工具，就是不开源</li><li><a href="https://lemon.qq.com/">Tencent Lemon</a> 类似于CleanMyMac，但是完全免费</li><li><a href="https://apps.apple.com/cn/app/xmind-2020-%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/id1327661892?mt=12">xmind</a> 思维导图</li><li><a href="https://apps.apple.com/cn/app/wps-office/id1443749478?mt=12">wps</a> 好用的文档中心</li><li><a href="https://tlanyan.me/v2ray-clients-download/">V2ray</a> mac 推荐<code>v2rayu</code>, win推荐<code>v2rayn</code> （免费订阅<a href="https://github.com/freefq/free">free</a> <a href="https://youjinnode.com/#/">幽禁节点</a></li></ol><hr><p>可选软件</p><ol><li><a href="https://obsproject.com/">OBS</a> 强大的推流工具</li><li><a href="https://apps.apple.com/cn/app/ishot-%E4%BC%98%E7%A7%80%E7%9A%84%E6%88%AA%E5%9B%BE%E5%BD%95%E5%B1%8F%E5%B7%A5%E5%85%B7/id1485844094?mt=12">ishot</a> 截图、长截图、贴图、标注、取色、录屏，样样优秀</li><li><a href="https://github.com/Molunerfinn/PicGo/">PicGo</a> 一个用于快速上传图片并获取图片 URL 链接的工具</li><li><a href="https://www.macwk.com/soft/daisydisk">Daisy Disk</a> 磁盘大小管理</li><li><a href="https://apps.apple.com/cn/app/pixeur-%E5%B1%8F%E5%B9%95%E6%8B%BE%E8%89%B2%E5%99%A8/id1507890049?mt=12">Pixeur - 屏幕拾色器</a> 取色器</li><li><a href="https://www.zhinin.com/parallels_desktop_15-mac.html">Parallels Desktop</a> 虚拟机管理 <a href="https://mp.weixin.qq.com/s/HpHRrJrUh7PJRYAWhusk-g">big sur</a></li><li><a href="https://www.macwk.com/soft/navicat-premium">Navicat Premium</a> 数据库管理</li></ol><p>MAC破解软件网址</p><ol><li><a href="https://www.macwk.com/">macwk</a></li><li><a href="https://www.zhinin.com/">知您网</a></li><li><a href="https://xclient.info/">XClient</a></li><li><a href="http://www.ruanman.net/?s=parallels">软曼网</a></li></ol><p>Chrome 插件</p><ol><li><a href="https://chrome.google.com/webstore/detail/%E6%B2%99%E6%8B%89%E6%9F%A5%E8%AF%8D-%E8%81%9A%E5%90%88%E8%AF%8D%E5%85%B8%E5%88%92%E8%AF%8D%E7%BF%BB%E8%AF%91/cdonnmffkdaoajfknoeeecmchibpmkmg?utm_source=chrome-ntp-icon">沙拉查词</a> 划词翻译</li><li><a href="https://chrome.google.com/webstore/detail/infinity-new-tab-pro/nnnkddnnlpamobajfibfdgfnbcnkgngh?utm_source=chrome-ntp-icon">infinity pro</a> 新标签</li></ol><h2 id="Mac-常见问题">Mac 常见问题</h2><h3 id="刷新DNS">刷新DNS</h3><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo dscacheutil -flushcache</span><br><span class="line">sudo killall -HUP mDNSResponder</span><br></pre></td></tr></tbody></table></figure><h3 id="xxx-app已损坏-打不开-你应该将它移到废纸篓-已解决">xxx.app已损坏,打不开.你应该将它移到废纸篓-已解决</h3><ol><li><p>系统偏好设置… -&gt; 安全性与隐私–&gt;修改为任何来源</p></li><li><p>serria里面没有"任何来源"这一项，需要打开终端执行sudo spctl --master-disable，这个时候再去系统偏好设置… -&gt; 安全性与隐私 是不是发现有了"任何来源"这一项</p></li></ol><figure class="highlight plaintext"><table><tbody><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"># 允许任何来源的软件</span><br><span class="line">sudo spctl --master-disable</span><br><span class="line"># 关闭</span><br><span class="line">sudo spctl --master-enable</span><br></pre></td></tr></tbody></table></figure><h3 id="已经勾选-允许任何来源-，为啥还是提示-文件已损坏">已经勾选"允许任何来源"，为啥还是提示"文件已损坏"</h3><p>打开终端，在终端中粘贴下面命令：【<code>sudo xattr -r -d com.apple.quarantine </code>】 ,然后输入个空格，再将应用程序目录中的软件拖拽到命令后面，按回车后输入密码执行。<br>比如：Sketch的命令是 sudo xattr -r -d com.apple.quarantine /Applications/Sketch.app<br>亲测可行</p><h3 id="MAC查看端口占用情况">MAC查看端口占用情况</h3><ul><li>lsof -i tcp:port  （port替换成端口号，比如6379）可以查看该端口被什么程序占用</li><li>kill port 关闭端口</li></ul><h3 id="显示finder的所有文件，包括隐藏文件">显示finder的所有文件，包括隐藏文件</h3><p><code>defaults write com.apple.Finder AppleShowAllFiles true</code><br>然后按住option+右击finder，重启finder<br><code>Command shift .</code> 隐藏显示隐藏文件</p><h3 id="Q-Can’t-chown-usr-local-in-High-Sierra">Q:Can’t chown /usr/local in High Sierra</h3><p>A:sudo chown -R $(whoami) $(brew --prefix)/*</p><h3 id="Xcode-支持库">Xcode 支持库</h3><p>链接：<a href="https://pan.baidu.com/s/1zXEFlt94bz3O1e3GdtG92w">https://pan.baidu.com/s/1zXEFlt94bz3O1e3GdtG92w</a> 密码: rc4k<br>/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport</p>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/09/17/Mac/Mac%E5%BF%85%E8%A3%85%E8%BD%AF%E4%BB%B6/</id>
    <link href="https://jeromexiong.github.io/2021/09/17/Mac/Mac%E5%BF%85%E8%A3%85%E8%BD%AF%E4%BB%B6/"/>
    <published>2021-09-17T08:34:21.000Z</published>
    <summary>Mac用户必备软件推荐清单，涵盖开发工具、系统工具、Chrome插件及常见macOS问题解决方案。</summary>
    <title>Mac必装软件</title>
    <updated>2026-06-16T08:17:05.713Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="dev" scheme="https://jeromexiong.github.io/categories/dev/"/>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="Typora" scheme="https://jeromexiong.github.io/tags/Typora/"/>
    <category term="PicGo" scheme="https://jeromexiong.github.io/tags/PicGo/"/>
    <category term="GitHub" scheme="https://jeromexiong.github.io/tags/GitHub/"/>
    <category term="Markdown" scheme="https://jeromexiong.github.io/tags/Markdown/"/>
    <category term="图床" scheme="https://jeromexiong.github.io/tags/%E5%9B%BE%E5%BA%8A/"/>
    <content>
      <![CDATA[<h3 id="前文">前文</h3><p>很多时候我们都需要一个公共的资源地址来存储自己的文章等信息，作为一个coder，那当然是要用我们专属的语言来写日记了（markdown）。这里就给大家讲解一下如何使用<a href="https://www.typora.io">typora</a> + <a href="https://github.com/Molunerfinn/PicGo">PicGo</a> + <a href="https://github.com/">github</a> 打造专属的编辑&amp;存储方式。</p><h3 id="准备">准备</h3><p>一、从上面的链接中下载并安装<code>typora</code>和<code>PicGo</code><br>二、 登录<code>github</code>账号</p><ol><li>创建公开资源库<br><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917113156228.png" alt="image-20210917113156228"></li><li>生成新令牌</li></ol><ul><li><p>依次点击 右上角点<code>用户头像</code> -&gt; <code>Settings</code> -&gt; <code>Developer settings</code> -&gt;  <code>Personal access tokens</code>）-&gt; <code>Generate new token</code><br><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917113803036.png" alt="image-20210917113803036"></p></li><li><p>设置令牌描述性名称，过期时间看自己情况选择，<code>Select scopes</code>只勾选：<code>repo</code>、 <code>user</code><br><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917114208452.png" alt="image-20210917114208452"></p></li><li><p><code>Generate token</code> 生成令牌 <strong>⚠️令牌只显示一次，一定要复制保存好</strong></p></li></ul><h3 id="设置PicGo图床">设置PicGo图床</h3><ol><li><p>打开<code>picgo</code>后在顶部菜单栏<code>右击图标</code>，选择<code>打开详情窗口</code>，选择<code>PicGo设置</code>并勾选<code>GitHub图床</code>；就会在<code>图床设置</code>处显示图床<br><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917115945814.png" alt="image-20210917115945814"></p></li><li><p>配置<code>GitHub图床</code></p></li></ol><ul><li>填写github账号名： <code>github账户/仓库名</code></li><li>一般为master或者main，具体看你的建的仓库</li><li>个人令牌，就是之前在github中生成私人令牌时得到的一串字符串</li><li>图片存放在仓库下面的哪个目录，不填就在项目的根目</li><li>默认的域名无法访问，修改为官方<code>https://raw.githubusercontent.com/github账户/仓库名/master/img/icon.png</code> 或者 CDN域名<code>https://cdn.jsdelivr.net/gh/github账户/仓库名/img/icon.png</code>，推荐使用cdn域名<br><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917120159803.png" alt="image-20210917120159803"></li></ul><ol start="3"><li>复制任意图片后，点击菜单栏应用图标，即可看到图片上传</li></ol><h3 id="typora图片上传">typora图片上传</h3><ol><li>打开<code>typora</code>的<code>偏好设置</code>下的<code>图像</code></li><li><code>插入图片时</code>默认<code>无操作</code>，根据情况选择是否<code>上传图片</code>；勾选以下选项</li></ol><ul><li>对本地位置的图片应用上述规则</li></ul><ol start="3"><li><code>上传服务</code> 选<code>PicGo.app</code>后即可</li></ol><p><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/image-20210917111332765.png" alt="image-20210917114821536"></p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">同样的，该文章就是以配置好的Typora编写的，所有截图复制后就上传并替换链接为cdn域名，简直方便的不行。</span><br><span class="line">顺便说下改文章的截图工具为ishot，自动阴影注释等👍</span><br></pre></td></tr></tbody></table></figure><ul><li><a href="https://apps.apple.com/cn/app/ishot-%E6%88%AA%E5%9B%BE-%E9%95%BF%E6%88%AA%E5%9B%BE-%E6%A0%87%E6%B3%A8%E5%B7%A5%E5%85%B7/id1485844094?mt=12">ishot</a> Mac上最强的截图工具</li></ul>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/09/17/%E5%B7%A5%E5%85%B7/Typora-GitHub-PicGo%E6%89%93%E9%80%A0%E4%B8%9D%E6%BB%91%E7%9A%84%E7%BC%96%E8%BE%91%E4%BD%93%E9%AA%8C/</id>
    <link href="https://jeromexiong.github.io/2021/09/17/%E5%B7%A5%E5%85%B7/Typora-GitHub-PicGo%E6%89%93%E9%80%A0%E4%B8%9D%E6%BB%91%E7%9A%84%E7%BC%96%E8%BE%91%E4%BD%93%E9%AA%8C/"/>
    <published>2021-09-17T08:13:21.000Z</published>
    <summary>使用Typora+PicGo+GitHub搭建Markdown图床，实现截图自动上传并替换为CDN链接。</summary>
    <title>Typora+GitHub+PicGo打造丝滑的编辑体验</title>
    <updated>2026-06-16T08:17:05.715Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="iOS" scheme="https://jeromexiong.github.io/categories/iOS/"/>
    <category term="iOS" scheme="https://jeromexiong.github.io/tags/iOS/"/>
    <category term="XCFramework" scheme="https://jeromexiong.github.io/tags/XCFramework/"/>
    <category term="Framework" scheme="https://jeromexiong.github.io/tags/Framework/"/>
    <category term="架构合并" scheme="https://jeromexiong.github.io/tags/%E6%9E%B6%E6%9E%84%E5%90%88%E5%B9%B6/"/>
    <content>
      <![CDATA[<p>XCFramework 是 Apple 推荐的 Framework 分发格式，支持多架构合并。本文详细介绍从 Framework 到 XCFramework 的转换流程。</p><h3 id="先说一下XCFramework的好处吧：">先说一下XCFramework的好处吧：</h3><ol><li>多架构合并，模拟器，真机可以通用随便跑</li><li>上架AppStore，不需要将<code>.xcframework</code>中的真机架构分离，<code>.framework</code>还需要用脚本分离，这实在太棒了</li></ol><h3 id="Framework简单解析">Framework简单解析</h3><p>拿腾讯IM的举例吧，其实<code>.framework</code>就是个文件夹里面装着封装好的文件。</p><figure class="highlight sh"><table><tbody><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></pre></td><td class="code"><pre><span class="line">% <span class="built_in">cd</span> path/ImSDK.framework <span class="comment"># path 为 framework 路径</span></span><br><span class="line">ImSDK.framework % tree -L 1</span><br><span class="line">.</span><br><span class="line">├── Headers <span class="comment"># 头文件夹</span></span><br><span class="line">├── ImSDK <span class="comment"># 可执行文件</span></span><br><span class="line">├── Info.plist</span><br><span class="line">└── Modules <span class="comment"># Modules 文件夹</span></span><br><span class="line"></span><br><span class="line">2 directories, 2 files</span><br></pre></td></tr></tbody></table></figure><p>通过<code>lipo -info</code>查看<code>.framework</code>中的可执行文件中包含的架构：</p><figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ImSDK.framework % lipo -info ImSDK </span><br><span class="line">Architectures <span class="keyword">in</span> the fat file: ImSDK are: x86_64 armv7 arm64 </span><br></pre></td></tr></tbody></table></figure><h3 id="XCFramework简单解析">XCFramework简单解析</h3><p><code>.xcframework</code>是由两个文件夹和一个配置文件组成:</p><figure class="highlight sh"><table><tbody><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">ImSDK.xcframework % tree -L 1</span><br><span class="line">.</span><br><span class="line">├── Info.plist</span><br><span class="line">├── ios-arm64_armv7 <span class="comment"># arm64 以及 armv7的真机支持</span></span><br><span class="line">└── ios-x86_64-simulator <span class="comment"># i386 以及 x86_64的模拟器支持</span></span><br><span class="line"></span><br><span class="line">2 directories, 1 file</span><br></pre></td></tr></tbody></table></figure><p>在编译过程中，编译器通过识别设备的架构不同架构的设备，去<code>.xcframework</code>中取对应的支持执行文件。</p><p><code>.xcframework</code>只是封装了真机和模拟器的<code>.framework</code></p><h3 id="Framework架构的分离以及合并">Framework架构的分离以及合并</h3><ol><li>将多架构的<code>.framework</code> 中的所有架构的执行文件全部分离出来（<code>arm64</code>, <code>armv7</code>, <code>x86_64</code>, <code>i386</code>）（不一定全部有</li></ol><figure class="highlight sh"><table><tbody><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">ImSDK.framework % lipo ImSDK -thin x86_64 -output ImSDK-x86_64</span><br><span class="line"></span><br><span class="line">依次分离出所有架构：</span><br><span class="line">.</span><br><span class="line">├── ImSDK-arm64</span><br><span class="line">├── ImSDK-armv7</span><br><span class="line">├── ImSDK-x86_64</span><br><span class="line">├── ImSDK-i386</span><br></pre></td></tr></tbody></table></figure><ol start="2"><li>拆解后，真机架构（arm64）和真机架构（armv7）合并</li></ol><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">% mkdir -p ImSDK-arm/ImSDK.framework</span><br><span class="line">% lipo -create ImSDK-arm64 ImSDK-armv7 -output ImSDK-arm/ImSDK.framework/ImSDK</span><br></pre></td></tr></tbody></table></figure><ol start="3"><li>拆解后，模拟器架构（x86_64）和模拟器架构（i386）合并。（有几个合并几个</li></ol><figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">% <span class="built_in">mkdir</span> -p ImSDK-simulator/ImSDK.framework</span><br><span class="line">% lipo -create ImSDK-x86_64 ImSDK-i386 -output ImSDK-simulator/ImSDK.framework/ImSDK</span><br></pre></td></tr></tbody></table></figure><ol start="4"><li>将原来的<code>.framework</code>中除了可执行文件，原封不动的拷贝到我们手动创建的<code>.framework</code>。(如果不拷贝会出编译时会各种奇怪的问题)</li></ol><figure class="highlight sh"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 真机</span></span><br><span class="line">ImSDK.framework % tree -L 2 ImSDK-arm</span><br><span class="line">ImSDK-arm</span><br><span class="line">└── ImSDK.framework</span><br><span class="line">    ├── Headers</span><br><span class="line">    ├── ImSDK</span><br><span class="line">    ├── Info.plist</span><br><span class="line">    └── Modules</span><br><span class="line"></span><br><span class="line">3 directories, 2 files</span><br><span class="line"></span><br><span class="line"><span class="comment"># 模拟器</span></span><br><span class="line">ImSDK.framework % tree -L 2 ImSDK-simulator</span><br><span class="line">ImSDK-simulator</span><br><span class="line">└── ImSDK.framework</span><br><span class="line">    ├── Headers</span><br><span class="line">    ├── ImSDK</span><br><span class="line">    ├── Info.plist</span><br><span class="line">    └── Modules</span><br><span class="line"></span><br><span class="line">3 directories, 2 files</span><br></pre></td></tr></tbody></table></figure><ol start="5"><li>在终端通指令<code>xcodebuild -create-xcframework</code>指令生成<code>xcframework</code></li></ol><figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xcodebuild -create-xcframework -framework ImSDK-arm/ImSDK.framework -framework ImSDK-simulator/ImSDK.framework -output ImSDK.xcframework</span><br></pre></td></tr></tbody></table></figure><p>提示 <code>xcframework successfully written out to: path/ImSDK.framework/ImSDK.xcframework</code>即合并成功</p><p><strong>完成以上步骤后即可生成XCFramework，用法和Framework一样</strong></p><p><em><strong>最后如果想要使用xcframework ，在<code>File -&gt; workspcaeSetting</code> 中只用<code>new Build System</code></strong></em></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2021/06/01/iOS-Swift/Framework%E8%BD%AC%E6%8D%A2XCFramework%E4%B9%8B%E6%97%85/</id>
    <link href="https://jeromexiong.github.io/2021/06/01/iOS-Swift/Framework%E8%BD%AC%E6%8D%A2XCFramework%E4%B9%8B%E6%97%85/"/>
    <published>2021-06-01T10:00:00.000Z</published>
    <summary>详解如何将传统 Framework 转换为 XCFramework，实现多架构合并与分发。</summary>
    <title>Framework转换XCFramework之旅</title>
    <updated>2026-06-16T08:17:05.713Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="Web" scheme="https://jeromexiong.github.io/categories/Web/"/>
    <category term="工具" scheme="https://jeromexiong.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="Node.js" scheme="https://jeromexiong.github.io/tags/Node-js/"/>
    <category term="Volta" scheme="https://jeromexiong.github.io/tags/Volta/"/>
    <category term="pnpm" scheme="https://jeromexiong.github.io/tags/pnpm/"/>
    <category term="nvm" scheme="https://jeromexiong.github.io/tags/nvm/"/>
    <category term="版本管理" scheme="https://jeromexiong.github.io/tags/%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86/"/>
    <content>
      <![CDATA[<p>Node.js 版本管理工具从 nvm 迁移到 Volta，包管理器从 npm 迁移到 pnpm，是提升前端开发效率的重要一步。Volta 相比 nvm 的优势在于自动版本切换和项目级配置，本文记录完整的迁移过程。</p><h3 id="一、卸载-nvm（避免冲突）">一、卸载 nvm（避免冲突）</h3><ol><li><p>​<strong>卸载 nvm</strong>​：</p><p>在终端执行以下命令移除 nvm 及其配置：</p><pre><code>nvm unload                    # 卸载 nvmrm -rf "${NVM_DIR:-~/.nvm}"  # 删除安装目录</code></pre></li><li><p>​<strong>清理配置文件</strong>​：</p><p>编辑 shell 配置文件（如&nbsp;<code>~/.zshrc</code>或&nbsp;<code>~/.bashrc</code>），删除以下行：</p><pre><code>export NVM_DIR="$HOME/.nvm"[ -s "$NVM_DIR/nvm.sh" ] &amp;&amp; \. "$NVM_DIR/nvm.sh"[[ -r $NVM_DIR/bash_completion ]] &amp;&amp; \. $NVM_DIR/bash_completion</code></pre><p>完成后运行&nbsp;<code>source ~/.zshrc</code>（或重启终端）。</p></li></ol><hr><h3 id="二、安装-Volta">二、安装 Volta</h3><ol><li><p>​<strong>自动安装</strong>​：</p><ul><li><p>​<strong>Mac/Linux</strong>​：</p><pre><code>curl https://get.volta.sh | bash</code></pre></li><li><p>​<strong>Windows</strong>​：</p><pre><code>winget install Volta.Volta</code></pre><p>安装后重启终端，运行&nbsp;<code>volta --version</code>验证是否成功。</p></li></ul></li><li><p>​<strong>手动配置（可选）​</strong>​：</p><p>若需自定义安装路径（如 Windows 下移至 D 盘）：</p><ul><li>设置环境变量&nbsp;<code>VOLTA_HOME=D:\Volta</code>；</li><li>在&nbsp;<code>PATH</code>中添加&nbsp;<code>%VOLTA_HOME%\bin</code>。</li></ul></li></ol><hr><h3 id="三、迁移项目配置">三、迁移项目配置</h3><ol><li><p>​<strong>全局设置默认 Node 版本</strong>​：</p><pre><code>volta install node@18  # 安装并设为全局默认版本</code></pre></li><li><p>​<strong>为项目固定版本</strong>​：</p><p>进入项目根目录，执行以下命令（Volta 会自动在&nbsp;<code>package.json</code>中生成配置）：</p><pre><code>volta pin node@16.14.2    # 固定 Node 版本volta pin npm@8.5.0       # 可选：固定 npm 版本volta pin yarn@1.22.19    # 可选：固定 Yarn 版本</code></pre><p>生成的&nbsp;<code>package.json</code>示例：</p><pre><code>{  "volta": {    "node": "16.14.2",    "npm": "8.5.0"  }}</code></pre><p>​<strong>提交此变更到 Git</strong>，确保团队成员无需手动切换版本。</p></li><li><p>​<strong>自动版本切换</strong>​：</p><p>进入已配置 Volta 的项目目录时，Volta 会自动切换到对应 Node 版本；若本地无该版本，会自动下载。</p></li></ol><hr><h3 id="四、高级功能">四、高级功能</h3><ol><li><p>​<strong>支持 PNPM（实验性）​</strong>​：</p><ul><li><p>在 shell 配置文件（如&nbsp;<code>~/.zshrc</code>）中添加：</p><pre><code>export VOLTA_FEATURE_PNPM=1</code></pre></li><li><p>重启终端后即可用&nbsp;<code>volta pin pnpm@7.x</code>管理版本。</p></li></ul></li><li><p>​<strong>常用命令汇总</strong>​：</p><table><thead><tr><th style="text-align:left">命令</th><th style="text-align:left">作用</th></tr></thead><tbody><tr><td style="text-align:left"><code>volta list</code></td><td style="text-align:left">查看已安装工具版本</td></tr><tr><td style="text-align:left"><code>volta install node@20</code></td><td style="text-align:left">安装指定 Node 版本</td></tr><tr><td style="text-align:left"><code>volta uninstall node@14</code></td><td style="text-align:left">卸载版本</td></tr><tr><td style="text-align:left"><code>volta which node</code></td><td style="text-align:left">查看当前使用的 Node 路径</td></tr><tr><td style="text-align:left"><code>volta run node app.js</code></td><td style="text-align:left">在 Volta 环境下运行命令</td></tr></tbody></table></li></ol><hr><h3 id="五、注意事项">五、注意事项</h3><ol><li><p>​<strong>全局工具迁移</strong>​：</p><p>若之前通过 nvm 安装全局包（如&nbsp;<code>pm2</code>），需用&nbsp;<code>npm list -g --depth=0</code>列出后，通过&nbsp;<code>npm install -g &lt;包名&gt;</code>重新安装。</p></li><li><p>​<strong>版本兼容性</strong>​：</p><ul><li>Volta 不支持 32 位 Node.js；</li><li>对旧项目（如 Node.js 12），建议验证版本是否可用。</li></ul></li></ol><hr><h3 id="总结">总结</h3><p>Volta 通过自动化版本切换和项目级配置，解决了 nvm 需手动切换的痛点。迁移后，团队可通过&nbsp;<code>package.json</code>统一环境，减少协作冲突。</p>]]>
    </content>
    <id>
      <![CDATA[https://jeromexiong.github.io/2021/05/01/%E5%B7%A5%E5%85%B7/%E4%BB%8E%20nvm%20%E8%BF%81%E7%A7%BB%E5%88%B0%20Volta%20&npm%E5%88%B0%20pnpm/]]>
    </id>
    <link href="https://jeromexiong.github.io/2021/05/01/%E5%B7%A5%E5%85%B7/%E4%BB%8E%20nvm%20%E8%BF%81%E7%A7%BB%E5%88%B0%20Volta%20&amp;npm%E5%88%B0%20pnpm/"/>
    <published>2021-05-01T10:00:00.000Z</published>
    <summary>从nvm迁移到Volta的完整指南，实现Node版本自动切换与项目级配置管理。</summary>
    <title>
      <![CDATA[从 nvm 迁移到 Volta &npm到 pnpm]]>
    </title>
    <updated>2026-06-16T08:17:05.717Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="Linux" scheme="https://jeromexiong.github.io/categories/Linux/"/>
    <category term="Nginx" scheme="https://jeromexiong.github.io/tags/Nginx/"/>
    <category term="MySQL" scheme="https://jeromexiong.github.io/tags/MySQL/"/>
    <category term="Redis" scheme="https://jeromexiong.github.io/tags/Redis/"/>
    <category term="Docker" scheme="https://jeromexiong.github.io/tags/Docker/"/>
    <category term="docker-compose" scheme="https://jeromexiong.github.io/tags/docker-compose/"/>
    <category term="Mac" scheme="https://jeromexiong.github.io/tags/Mac/"/>
    <content>
      <![CDATA[<p>本文介绍在 Mac 上使用 Docker 和 docker-compose 一键部署 MySQL、Redis 和 Nginx 服务，涵盖镜像加速、数据持久化、容器链接等关键配置。</p><h2 id="安装">安装</h2><p>首先去<a href="https://www.runoob.com/docker/macos-docker-install.html">官网下载</a>，因为国内网络问题，需要配置网络加速，可以使用：</p><ul><li><a href="http://hub-mirror.c.163.com">http://hub-mirror.c.163.com</a> 网易</li><li><a href="https://registry.docker-cn.com">https://registry.docker-cn.com</a> 中国区官方</li><li><a href="http://docker.mirrors.ustc.edu.cn">docker.mirrors.ustc.edu.cn</a> 中国科技大学</li></ul><p><img src="https://cdn.jsdelivr.net/gh/jeromexiong/resources/img/20210903144322.png" alt=""></p><pre><code>{  "registry-mirrors": [    "https://docker.registry.cyou",    "https://docker-cf.registry.cyou",    "https://dockercf.jsdelivr.fyi",    "https://docker.jsdelivr.fyi",    "https://dockertest.jsdelivr.fyi",    "https://mirror.aliyuncs.com",    "https://dockerproxy.com",    "https://mirror.baidubce.com",    "https://docker.m.daocloud.io",    "https://docker.nju.edu.cn",    "https://docker.mirrors.sjtug.sjtu.edu.cn",    "https://docker.mirrors.ustc.edu.cn",    "https://mirror.iscas.ac.cn",    "https://docker.rainbond.cc"  ]}</code></pre><h2 id="使用compose统一配置mysql、redis镜像">使用compose统一配置mysql、redis镜像</h2><ol><li>在用户目录<code>~</code>下新建<code>mkdir -p docker/service</code>目录</li><li>在<code>service</code>目录下新建文件<code>docker-compose.yml</code></li></ol><figure class="highlight yaml"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">"3"</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">redis:5.0.4</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">${REDIS_PORT}:6379</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">"${REDIS_DIR}/conf:/usr/local/etc/redis"</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">"${REDIS_DIR}/data:/data"</span></span><br><span class="line">    <span class="attr">command:</span></span><br><span class="line">      <span class="string">redis-server</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">mysql:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">mysql:5.7</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">${MYSQL_PORT}:3306</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">"${MYSQL_DIR}/data:/var/lib/mysql"</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">"${MYSQL_DIR}/conf.d:/etc/mysql/conf.d"</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}</span></span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure><ol><li><code>docker-compose.yml</code>文件会读取系统环境变量以及当前目录下的<code>.env</code>文件变量</li></ol><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><span class="line"># redis</span><br><span class="line">REDIS_PORT=6379</span><br><span class="line">REDIS_PWD=123456</span><br><span class="line">REDIS_DIR=./redis</span><br><span class="line"></span><br><span class="line"># mysql</span><br><span class="line">MYSQL_PORT=3306</span><br><span class="line">MYSQL_DIR=./mysql</span><br><span class="line">MYSQL_ROOT_PASSWORD=123456 # 密码只在初始化时设置</span><br><span class="line"></span><br></pre></td></tr></tbody></table></figure><p>运行后会默认生成镜像服务容器名<code>service_mysql_1, service_redis_1</code></p><h2 id="docker-compose常用命令">docker-compose常用命令</h2><ul><li><p>docker-compose up -d [options] [SERVICE…]<br>该命令十分强大，它将尝试自动完成包括构建镜像，（重新）创建服务，启动服务，并关联服务相关容器的一系列操作。<br>链接的服务都将会被自动启动，除非已经处于运行状态。<br>-d 以守护进程方式运行</p></li><li><p>docker-compose down<br>此命令将会停止 up 命令所启动的容器，并移除网络</p></li><li><p>docker-compose restart [options] [SERVICE…]<br>重启项目中的服务。</p></li></ul><h2 id="安装nginx">安装nginx</h2><ol><li><p>拉取nginx镜像 <code>docker pull nginx@latest</code></p></li><li><p>查看镜像 <code>docker images</code></p></li><li><p>运行镜像为容器</p><p>docker run -d -p 4000:80 --name service_nginx nginx</p><h1>用4000端口映射80，用service_nginx作为容器名，对应仓库镜像 nginx</h1></li><li><p>查看容器</p><p>docker ps -a</p><h3 id="所有容器，包括未运行">所有容器，包括未运行</h3></li><li><p>以终端的方式进入nginx容器</p><p>docker exec -it service_nginx bash</p></li><li><p>复制文件到本地</p><p>docker cp service_nginx:/etc/nginx ~/docker/nginx/config/</p><p>docker cp service_nginx:/usr/share/nginx/html ~/docker/nginx/</p><p>docker cp service_nginx:/var/log/nginx ~/docker/nginx/logs/</p></li><li><p>关闭容器, 重启并挂载文件</p><p>docker rm -f service_nginx</p><p>docker run --name service_nginx -p 4000:80 <br>-v ~/docker/nginx/config/:/etc/nginx <br>-v ~/docker/nginx/html:/usr/share/nginx/html <br>-v ~/docker/nginx/logs:/var/log/nginx <br>--link service_mysql_1:mysql <br>-d nginx</p></li></ol><p><code>--link service_mysql_1:mysql</code>，表示 nginx 容器要连到 service_mysql_1 容器，冒号表示该容器的别名是mysql</p><h2 id="问题">问题</h2><h3 id="修改密码">修改密码</h3><p>进入<code>docker exec -it service_mysql_1 bash mysql -u root -p</code></p><pre><code># 修改普通用户，只改一个就好SET PASSWORD FOR 'youruser' = PASSWORD('newpwd');# 修改root用户，改两个SET PASSWORD FOR 'root' = PASSWORD('newpwd');SET PASSWORD FOR 'root'@'localhost'=PASSWORD('newpwd');</code></pre>]]>
    </content>
    <id>https://jeromexiong.github.io/2020/09/01/Linux-DevOps/mac%20%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85mysql%EF%BC%8Credis,%20nginx/</id>
    <link href="https://jeromexiong.github.io/2020/09/01/Linux-DevOps/mac%20%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85mysql%EF%BC%8Credis,%20nginx/"/>
    <published>2020-09-01T10:00:00.000Z</published>
    <summary>在Mac上使用Docker和docker-compose统一安装配置MySQL、Redis和Nginx的完整教程，含镜像加速与数据挂载。</summary>
    <title>mac 使用docker安装mysql，redis, nginx</title>
    <updated>2026-06-16T08:17:05.712Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="Linux" scheme="https://jeromexiong.github.io/categories/Linux/"/>
    <category term="Nginx" scheme="https://jeromexiong.github.io/tags/Nginx/"/>
    <category term="反向代理" scheme="https://jeromexiong.github.io/tags/%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/"/>
    <category term="SSL" scheme="https://jeromexiong.github.io/tags/SSL/"/>
    <category term="宝塔" scheme="https://jeromexiong.github.io/tags/%E5%AE%9D%E5%A1%94/"/>
    <category term="服务器" scheme="https://jeromexiong.github.io/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    <category term="部署" scheme="https://jeromexiong.github.io/tags/%E9%83%A8%E7%BD%B2/"/>
    <category term="面板" scheme="https://jeromexiong.github.io/tags/%E9%9D%A2%E6%9D%BF/"/>
    <content>
      <![CDATA[<p>本教程详细介绍如何在宝塔面板中配置 Nginx 反向代理、静态资源服务，以及部署 Let’s Encrypt 免费 SSL 证书和自动续期功能。</p><p>在<a href="https://www.bt.cn/new/index.html">宝塔面板</a>中配置您提供的 Nginx 反向代理和静态资源服务，可以按照以下步骤操作。下面的流程图汇总了核心配置步骤，帮助您快速了解整体流程：</p><figure class="highlight plaintext"><table><tbody><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><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line">    A[开始配置] --&gt; B[登录宝塔面板&lt;br&gt;创建或选择站点]</span><br><span class="line">    B --&gt; C{配置目标}</span><br><span class="line">    C --&gt;|反向代理| D[配置反向代理]</span><br><span class="line">    C --&gt;|静态资源| E[配置静态资源]</span><br><span class="line">    </span><br><span class="line">    D --&gt; D1[添加反向代理规则]</span><br><span class="line">    D1 --&gt; D2[自定义代理名称和目标URL]</span><br><span class="line">    D2 --&gt; D3[高级配置中添加&lt;br&gt;proxy_set_header等参数]</span><br><span class="line">    </span><br><span class="line">    E --&gt; E1[修改网站根目录]</span><br><span class="line">    E1 --&gt; E2[设置默认文档]</span><br><span class="line">    E2 --&gt; E3[添加try_files指令]</span><br><span class="line">    </span><br><span class="line">    D3 --&gt; F[保存并重启Nginx]</span><br><span class="line">    E3 --&gt; F</span><br><span class="line">    F --&gt; G[配置完成]</span><br></pre></td></tr></tbody></table></figure><h3 id="🔧-配置反向代理-location-asapi">🔧 配置反向代理 (location ^~ /asapi)</h3><ol><li><p>​<strong>登录宝塔面板</strong>，进入【网站】页面，找到您的站点，点击右侧的【设置】。</p></li><li><p>在站点设置中，找到并点击【反向代理】选项卡，然后点击【添加反向代理】。</p></li><li><p>在添加反向代理的界面中：</p><ul><li>​<strong>代理名称</strong>​：可以自定义，例如&nbsp;<code>asapi_proxy</code>。</li><li>​<strong>目标URL</strong>​：填写&nbsp;<code>http://127.0.0.1:7001</code>。</li></ul></li><li><p>点击【提交】后，宝塔会自动生成一个基础的反向代理配置。为了匹配您提供的配置，您可能需要点击【配置文件】选项卡，找到自动生成的&nbsp;<code>/asapi</code>相关配置块，手动添加上其他&nbsp;<code>proxy_set_header</code>等参数，或者直接在反向代理设置的高级配置中进行添加 。确保最终的配置包含以下关键指令 ：</p><pre><code>location ^~ /asapi {    proxy_pass http://127.0.0.1:7001;    proxy_set_header X-Real-IP  $remote_addr;    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    proxy_set_header Host   $http_host;    proxy_set_header X-NginX-Proxy true;    proxy_set_header Connection "";    proxy_http_version 1.1;}</code></pre></li></ol><h3 id="📁-配置静态资源服务-location-web">📁 配置静态资源服务 (location /web)</h3><p>宝塔面板的图形界面主要简化了反向代理配置，对于使用&nbsp;<code>alias</code>指令的静态资源映射，通常需要直接编辑配置文件来实现。</p><ol><li><p>在站点的设置中，点击【配置文件】选项卡。</p></li><li><p>在&nbsp;<code>server</code>块内，找到或添加&nbsp;<code>location /web</code>的配置部分。您可能需要注释掉或调整宝塔面板自动生成的与根目录&nbsp;<code>/</code>相关的&nbsp;<code>location</code>块，以避免规则冲突。</p></li><li><p>将您提供的配置粘贴或修改到合适的位置：</p><pre><code>location /web {    alias /www/wwwroot/smartfarm/web/; # 请确保此路径正确且宝塔面板的www用户有权访问    index index.html;    try_files $uri $uri/ /web/index.html; # 用于支持前端路由的history模式}</code></pre><p>​<strong>关键提示</strong>​：</p><ul><li>​<strong>路径权限</strong>​：请确认路径&nbsp;<code>/mnt/projects/smart-farm/web/</code>存在，并且宝塔面板运行Nginx的用户（通常是<code>www</code>）拥有读取权限 。</li><li>​<strong>历史模式路由</strong>​：<code>try_files $uri $uri/ /web/index.html;</code>这行配置对于使用 history 模式的前端路由框架（如 Vue Router、React Router）至关重要，它确保在直接访问非首页URL时能正确返回&nbsp;<code>index.html</code>。</li></ul></li></ol><h3 id="✅-最终检查">✅ 最终检查</h3><p>配置完成后，请务必执行以下操作：</p><ul><li>点击配置文件编辑器上方的【保存】按钮。</li><li>在宝塔面板的首页或软件管理中找到Nginx服务，执行【重载配置】或【重启】，使修改生效 。</li><li>重载或重启后，检查Nginx状态是否正常运行。如果启动失败，请查看【网站】日志或Nginx错误日志（通常在&nbsp;<code>/www/wwwlogs/</code>目录下，以您的域名-error.log命名）来排查语法或路径错误 。</li></ul><h3 id="🔧-部署免费SSL证书">🔧 部署免费SSL证书</h3><p>首先，您需要为网站申请并部署一张SSL证书。宝塔面板内置了对 ​<strong>Let‘s Encrypt</strong>​ 免费证书的支持，整个过程非常便捷。</p><ol><li><p>​<strong>前提准备</strong>​：确保您的域名已经正确解析到当前服务器的IP地址，并且网站可以通过HTTP正常访问。</p></li><li><p>​<strong>申请证书</strong>​：</p><ul><li>登录宝塔面板，进入【网站】列表，点击目标网站右侧的【设置】。</li><li>切换到【SSL】选项卡，在证书服务中选择 ​<strong>​“Let’s Encrypt”​</strong>​ 。</li><li>勾选您需要绑定的域名（例如&nbsp;<code>example.com</code>和&nbsp;<code>www.example.com</code>）。</li><li>选择<strong>验证方式</strong>。如果您希望申请通配符证书（支持所有子域名）或为自动化续期打下最可靠的基础，强烈推荐使用 ​<strong>DNS验证</strong>​（如阿里云DNS、Cloudflare等）。如果您的域名解析已生效且80端口畅通，也可以使用简单的文件验证。</li><li>点击【申请】或【验证】，系统会自动完成域名验证、证书申请和配置工作。</li></ul></li><li><p>​<strong>开启强制HTTPS</strong>​：证书部署成功后，建议在SSL设置页面勾选【强制HTTPS】选项，这样所有HTTP请求都会被自动重定向到安全的HTTPS连接。</p></li></ol><h3 id="⚙️-配置自动续期">⚙️ 配置自动续期</h3><p>Let‘s Encrypt证书的有效期为90天，因此设置自动续期至关重要。宝塔面板提供了两种主要方式来实现这一点。</p><ul><li><p>​<strong>方式一：利用面板内置的自动续签功能</strong>​</p><p>当您通过宝塔面板成功申请Let’s Encrypt证书后，系统<strong>默认会创建一条自动续签计划任务</strong>。您可以在面板左侧导航栏点击【计划任务】，检查是否存在名为“续签Let‘s Encrypt证书”的任务。该任务通常会定期（如每天）检查证书并在到期前约30天自动续签。</p></li><li><p>​<strong>方式二：手动创建或验证计划任务（更可靠）​</strong>​</p><p>如果内置任务不存在或您希望更主动地管理，可以手动添加一条Shell脚本任务，这是确保自动续期生效的最可靠方法。</p><ol><li><p>进入【计划任务】。</p></li><li><p>【任务类型】选择 “Shell脚本”。</p></li><li><p>【执行周期】可以设置为每天或每周执行一次。</p></li><li><p>在【脚本内容】中填入以下命令：</p><pre><code>/www/server/panel/pyenv/bin/python3 -u /www/server/panel/class/acme_v2.py --renew=1</code></pre></li><li><p>点击【添加任务】即可。</p></li></ol><p>对于使用<strong>DNS验证</strong>方式申请证书的用户，为了确保自动续期脚本有权限自动更新DNS记录，您需要提前在宝塔面板的SSL设置中配置好DNS服务商的API密钥（如阿里云的AccessKey ID和Secret）。</p></li></ul><p><a href="https://note.youdao.com/">link</a></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2020/08/01/Linux-DevOps/%E5%AE%9D%E5%A1%94%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2/</id>
    <link href="https://jeromexiong.github.io/2020/08/01/Linux-DevOps/%E5%AE%9D%E5%A1%94%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2/"/>
    <published>2020-08-01T10:00:00.000Z</published>
    <summary>宝塔面板配置Nginx反向代理、静态资源服务及部署免费SSL证书的完整教程，含Let's Encrypt自动续期设置。</summary>
    <title>宝塔管理服务器部署</title>
    <updated>2026-06-16T08:17:05.712Z</updated>
  </entry>
  <entry>
    <author>
      <name>Jerome Xiong</name>
    </author>
    <category term="Linux" scheme="https://jeromexiong.github.io/categories/Linux/"/>
    <category term="Nginx" scheme="https://jeromexiong.github.io/tags/Nginx/"/>
    <category term="HTTPS" scheme="https://jeromexiong.github.io/tags/HTTPS/"/>
    <category term="SSL" scheme="https://jeromexiong.github.io/tags/SSL/"/>
    <category term="LetsEncrypt" scheme="https://jeromexiong.github.io/tags/LetsEncrypt/"/>
    <category term="TLS" scheme="https://jeromexiong.github.io/tags/TLS/"/>
    <category term="证书" scheme="https://jeromexiong.github.io/tags/%E8%AF%81%E4%B9%A6/"/>
    <category term="Certbot" scheme="https://jeromexiong.github.io/tags/Certbot/"/>
    <category term="Apache" scheme="https://jeromexiong.github.io/tags/Apache/"/>
    <content>
      <![CDATA[<h1>使用Let’s Encrypt获取和安装SSL/TLS证书的完整指南</h1><p>Let’s Encrypt是一个免费、自动化的证书颁发机构(CA)，通过其官方工具Certbot可以简化SSL/TLS证书的获取和安装流程。以下是详细的步骤指南：</p><h2 id="一、准备工作">一、准备工作</h2><ol><li><strong>域名准备</strong>：确保您拥有要申请证书的域名，并且该域名的DNS记录已正确解析到您的服务器IP地址</li><li><strong>服务器要求</strong>：需要root或sudo权限，并确保服务器开放了80(HTTP)和443(HTTPS)端口</li><li><strong>Web服务器</strong>：已安装Nginx或Apache等Web服务器软件</li></ol><h2 id="二、安装Certbot工具">二、安装Certbot工具</h2><p>Certbot是Let’s Encrypt官方推荐的客户端工具，安装方法因操作系统而异：</p><h3 id="Ubuntu-Debian系统">Ubuntu/Debian系统</h3><figure class="highlight bash"><table><tbody><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"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install certbot python3-certbot-nginx  <span class="comment"># 用于Nginx</span></span><br><span class="line"><span class="comment"># 或</span></span><br><span class="line"><span class="built_in">sudo</span> apt install certbot python3-certbot-apache <span class="comment"># 用于Apache</span></span><br></pre></td></tr></tbody></table></figure><h3 id="CentOS-RHEL系统">CentOS/RHEL系统</h3><figure class="highlight bash"><table><tbody><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="built_in">sudo</span> yum install epel-release</span><br><span class="line"><span class="built_in">sudo</span> yum install certbot python3-certbot-nginx  <span class="comment"># 用于Nginx</span></span><br><span class="line"><span class="comment"># 或</span></span><br><span class="line"><span class="built_in">sudo</span> yum install certbot python3-certbot-apache <span class="comment"># 用于Apache</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">## The requested nginx plugin does not appear to be installed 未安装插件</span></span><br><span class="line"><span class="built_in">sudo</span> yum install certbot-nginx</span><br></pre></td></tr></tbody></table></figure><h3 id="通过Snap安装-推荐获取最新版本">通过Snap安装(推荐获取最新版本)</h3><figure class="highlight bash"><table><tbody><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"><span class="built_in">sudo</span> snap install core</span><br><span class="line"><span class="built_in">sudo</span> snap refresh core</span><br><span class="line"><span class="built_in">sudo</span> snap install --classic certbot</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">ln</span> -s /snap/bin/certbot /usr/bin/certbot</span><br></pre></td></tr></tbody></table></figure><p>安装完成后验证版本：<code>certbot --version</code></p><h2 id="三、获取Let’s-Encrypt证书">三、获取Let’s Encrypt证书</h2><h3 id="1-基本证书申请命令">1. 基本证书申请命令</h3><p>对于Nginx服务器：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> certbot --nginx -d example.com -d www.example.com</span><br></pre></td></tr></tbody></table></figure><p>对于Apache服务器：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> certbot --apache -d example.com -d www.example.com</span><br></pre></td></tr></tbody></table></figure><p>执行命令后会要求：</p><ol><li>输入有效的电子邮件地址(用于证书到期提醒)</li><li>同意服务条款</li><li>选择是否将HTTP流量重定向到HTTPS(推荐选择"2"强制重定向)</li></ol><h3 id="2-域名验证方式">2. 域名验证方式</h3><p>Let’s Encrypt支持两种主要验证方式：</p><table><thead><tr><th>验证类型</th><th>说明</th><th>适用场景</th></tr></thead><tbody><tr><td>HTTP验证</td><td>在网站根目录创建验证文件</td><td>标准Web服务器环境</td></tr><tr><td>DNS验证</td><td>添加TXT记录到域名DNS</td><td>无法开放80端口的服务器或泛域名证书</td></tr></tbody></table><p><strong>DNS验证示例</strong>(适用于泛域名证书)：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> certbot certonly --manual --preferred-challenges dns -d *.example.com</span><br></pre></td></tr></tbody></table></figure><p>执行后会提示添加特定的TXT记录到DNS解析</p><h2 id="四、安装和配置证书">四、安装和配置证书</h2><h3 id="Nginx服务器配置">Nginx服务器配置</h3><p>Certbot通常会自动修改Nginx配置，生成的证书文件位于：</p><figure class="highlight plaintext"><table><tbody><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">/etc/letsencrypt/live/example.com/</span><br><span class="line">├── cert.pem      # 证书文件</span><br><span class="line">├── chain.pem     # 中间证书</span><br><span class="line">├── fullchain.pem # 完整证书链</span><br><span class="line">└── privkey.pem   # 私钥文件</span><br></pre></td></tr></tbody></table></figure><p>典型Nginx SSL配置示例：</p><figure class="highlight nginx"><table><tbody><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></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> {</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl;</span><br><span class="line">    <span class="attribute">server_name</span> example.com www.example.com;</span><br><span class="line">    </span><br><span class="line">    <span class="attribute">ssl_certificate</span> /etc/letsencrypt/live/example.com/fullchain.pem;</span><br><span class="line">    <span class="attribute">ssl_certificate_key</span> /etc/letsencrypt/live/example.com/privkey.pem;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 其他配置...</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure><p>配置完成后测试并重载Nginx：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> nginx -t &amp;&amp; <span class="built_in">sudo</span> systemctl reload nginx</span><br></pre></td></tr></tbody></table></figure><h3 id="Apache服务器配置">Apache服务器配置</h3><p>Apache的配置类似，Certbot会自动修改配置文件，证书路径与Nginx相同。典型配置包括：</p><figure class="highlight apache"><table><tbody><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="section">&lt;VirtualHost *<span class="number">:443</span>&gt;</span></span><br><span class="line">    <span class="attribute">ServerName</span> example.com</span><br><span class="line">    <span class="attribute">SSLEngine</span> <span class="literal">on</span></span><br><span class="line">    <span class="attribute">SSLCertificateFile</span> /etc/letsencrypt/live/example.com/cert.pem</span><br><span class="line">    <span class="attribute">SSLCertificateKeyFile</span> /etc/letsencrypt/live/example.com/privkey.pem</span><br><span class="line">    <span class="attribute">SSLCertificateChainFile</span> /etc/letsencrypt/live/example.com/chain.pem</span><br><span class="line">    <span class="comment"># 其他配置...</span></span><br><span class="line"><span class="section">&lt;/VirtualHost&gt;</span></span><br></pre></td></tr></tbody></table></figure><p>配置完成后重启Apache：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart apache2</span><br></pre></td></tr></tbody></table></figure><h2 id="五、证书自动续期">五、证书自动续期</h2><p>Let’s Encrypt证书有效期为90天，设置自动续期非常重要：</p><ol><li>测试续期命令是否正常工作：</li></ol><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> certbot renew --dry-run</span><br></pre></td></tr></tbody></table></figure><ol start="2"><li>添加定时任务(通常Certbot已自动配置)：</li></ol><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> crontab -e</span><br></pre></td></tr></tbody></table></figure><p>添加以下内容(每天凌晨2点检查续期)：</p><figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 2 * * * /usr/bin/certbot renew --quiet</span><br></pre></td></tr></tbody></table></figure><ol start="3"><li>对于Nginx/Apache，续期后可能需要重载服务：</li></ol><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0 2 * * * /usr/bin/certbot renew --quiet &amp;&amp; systemctl reload nginx</span><br><span class="line"><span class="comment"># 或</span></span><br><span class="line">0 2 * * * /usr/bin/certbot renew --quiet &amp;&amp; systemctl reload apache2</span><br></pre></td></tr></tbody></table></figure><h2 id="六、常见问题解决">六、常见问题解决</h2><ol><li><p><strong>证书申请失败</strong>：</p><ul><li>检查域名解析是否正确</li><li>确保80/443端口开放</li><li>验证服务器时间是否正确</li></ul></li><li><p><strong>续期失败</strong>：</p><ul><li>检查Certbot日志：<code>/var/log/letsencrypt/</code></li><li>确保定时任务配置正确</li><li>手动运行<code>certbot renew</code>查看具体错误</li></ul></li><li><p><strong>混合内容警告</strong>：</p><ul><li>确保网页中所有资源(图片、CSS、JS)都使用HTTPS链接</li><li>考虑添加Content Security Policy头</li></ul></li><li><p><strong>服务器配置错误</strong>：</p><ul><li>Nginx: <code>nginx -t</code>测试配置</li><li>Apache: <code>apachectl configtest</code>测试配置</li><li>检查错误日志获取详细信息</li></ul></li></ol><h2 id="七、高级用法">七、高级用法</h2><ol><li><p><strong>泛域名证书</strong>：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">certbot certonly --manual --preferred-challenges dns -d *.example.com</span><br></pre></td></tr></tbody></table></figure><p>需要手动添加DNS TXT记录验证</p></li><li><p><strong>IP地址证书</strong>(2025年7月新增功能)：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">certbot certonly --standalone -d 192.0.2.1</span><br></pre></td></tr></tbody></table></figure><p>需要验证IP地址所有权</p></li><li><p><strong>多域名证书</strong>：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">certbot --nginx -d example.com -d api.example.com -d app.example.com</span><br></pre></td></tr></tbody></table></figure></li><li><p><strong>证书吊销</strong>：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem</span><br></pre></td></tr></tbody></table></figure></li></ol><p>通过以上步骤，您可以轻松地为网站部署Let’s Encrypt免费SSL/TLS证书，实现安全的HTTPS连接。Certbot工具大大简化了证书的申请、安装和续期流程，使加密通信的部署变得更加便捷。</p><p>引用链接：<br>1.<a href="http://zhuanlan.zhihu.com/p/1915026203070410908">用Let‘s Encrypt给网站添加一个免费的SSL证书 - 24K纯学渣</a><br>2.<a href="https://www.cnblogs.com/pangguoming/p/18814092">使用Let’s Encrypt 获取免费SSL证书 - 博客园</a><br>3.<a href="https://blog.csdn.net/weixin_34718952/article/details/148640254">自动化获取Let‘s Encrypt SSL证书的Shell脚本指南 - CSDN博客</a><br>4.<a href="https://blog.csdn.net/yangjing19910801/article/details/145531466">Let’s Encrypt 免费SSL证书申请 - CSDN博客</a><br>5.<a href="https://blog.csdn.net/qyhua/article/details/143793029">免费申请 Let‘s Encrypt SSL 证书 - CSDN博客</a><br>6.<a href="https://www.cnblogs.com/osfipin/p/18301902">申请Let’s Encrypt免费SSL证书 - 博客园</a><br>7.<a href="https://blog.csdn.net/L18637178596/article/details/147787367">[教程] 如何为 Nginx/Apache 配置免费 Let‘s Encrypt SSL 证书 (Certbot 详解) - CSDN博客</a><br>8.<a href="https://blog.csdn.net/weixin_36847823/article/details/149418642">使用acme.sh颁发TLS证书并安装到nginx/apache实现网站https访问 - CSDN博客</a><br>9.<a href="https://cloud.tencent.com/developer/article/1009193">在Apache 上部署 Let’s Encrypt 证书与自动续期脚本 - 腾讯云</a><br>10.<a href="https://blog.csdn.net/DomicZhong/article/details/147963697">【SSL部署与优化​】​​如何为网站启用HTTPS:从Let‘s Encrypt免费证书到Nginx配置​​ - CSDN博客</a><br>11.<a href="http://zhuanlan.zhihu.com/p/1915027835321552913">定期更新Let‘s Encrypt SSL证书遇到的问题 - 24K纯学渣</a><br>12.<a href="https://juejin.cn/post/7486373487038070784">[笔记] CentOS7 + Nginx 环境下,安装使用 Let‘s Encrypt 免费 SSL 证书 (自动续签)  - 掘金开发者社区</a><br>13.<a href="https://blog.csdn.net/problc/article/details/148292129">使用Certbot 获取免费 HTTPS 证书:从零开始的 HTTPS 配置指南 - CSDN博客</a><br>14.<a href="https://www.cnblogs.com/lingyanspace/p/18687569">HTTPS 证书自动化运维:使用Certbot来申请https证书实践指南 - 博客园</a><br>15.<a href="https://blog.csdn.net/unbuntu_luo/article/details/149153187">使用Certbot 申请和自动续签 Let’s Encrypt 的免费 SSL 证书 - CSDN博客</a><br>16.<a href="https://blog.csdn.net/Wanganchuan/article/details/148413113">创建Let‘s Encrypt 证书 - CSDN博客</a><br>17.<a href="https://baijiahao.baidu.com/s?id=1833204376423528552&amp;wfr=spider&amp;for=pc">使用Let’s Encrypt和Certbot快速为网站启用HTTPS - 沿途赋能站</a><br>18.<a href="https://zhuanlan.zhihu.com/p/1923711888488899980">在Ubuntu上使用Certbot申请Let’s Encrypt SSL证书 - 随心不欲</a></p>]]>
    </content>
    <id>https://jeromexiong.github.io/2020/07/01/Linux-DevOps/%E4%BD%BF%E7%94%A8LetsEncrypt%E8%8E%B7%E5%8F%96%E5%92%8C%E5%AE%89%E8%A3%85SSLTLS%E8%AF%81%E4%B9%A6%E7%9A%84%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97/</id>
    <link href="https://jeromexiong.github.io/2020/07/01/Linux-DevOps/%E4%BD%BF%E7%94%A8LetsEncrypt%E8%8E%B7%E5%8F%96%E5%92%8C%E5%AE%89%E8%A3%85SSLTLS%E8%AF%81%E4%B9%A6%E7%9A%84%E5%AE%8C%E6%95%B4%E6%8C%87%E5%8D%97/"/>
    <published>2020-07-01T10:00:00.000Z</published>
    <summary>完整指南教你使用Let's Encrypt和Certbot获取免费SSL/TLS证书，涵盖Nginx/Apache安装配置与自动续期。</summary>
    <title>使用LetsEncrypt获取和安装SSLTLS证书的完整指南</title>
    <updated>2026-06-16T08:17:05.712Z</updated>
  </entry>
</feed>
