<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>w2solo - 独立开发者社区</title>
    <link>https://w2solo.com/</link>
    <description>w2solo - 独立开发者社区社区最新发帖.</description>
    <language>en-us</language>
    <item>
      <title>我的 Chrome 插件月活从 0 到 8000，推广费为 0，分享我的五个野路子</title>
      <description>&lt;p&gt;先交代背景：我做的是一个网页批注工具，功能很简单——在任意网页上高亮、记笔记，数据同步到 Notion。&lt;/p&gt;

&lt;p&gt;2024 年 3 月上线，现在月活 8000，付费转化率 2.3%。没团队、没预算、没投广告。今天分享几个真正有用的冷启动方法，以及我踩过的坑。&lt;/p&gt;

&lt;p&gt;野路子一：在目标用户扎堆的地方出现，而不是发广告&lt;/p&gt;

&lt;p&gt;我的第一批用户来自 Reddit 的 r/Notion。但我没发推广帖，而是回答了一个问题："有没有办法在网页上高亮内容，自动同步到 Notion？"&lt;/p&gt;

&lt;p&gt;我认真写了 500 字，说明为什么现有方案不好用，最后提了一句"我自己做了个工具，如果你愿意可以试试"。那个回答拿了 200 多赞，当天来了 300 多个安装。&lt;/p&gt;

&lt;p&gt;关键是：先提供价值，再提产品。直接发链接会被删，但真诚回答问题不会。&lt;/p&gt;

&lt;p&gt;野路子二：把用户反馈变成内容&lt;/p&gt;

&lt;p&gt;有个用户在 Twitter 上吐槽："同步好慢啊"。我回复他："确实，我正在优化，预计下周发布。如果你愿意，我可以先给你发测试版。"&lt;/p&gt;

&lt;p&gt;他同意了，测试后发了条 Tweet 说"开发者响应好快，问题解决了"。这条 Tweet 被转发了 30 多次，带来一波安装。&lt;/p&gt;

&lt;p&gt;后来我养成了习惯：每次修复 bug 或发新功能，主动找之前抱怨过的用户试用。他们变成"自来水"的概率很高。&lt;/p&gt;

&lt;p&gt;野路子三：蹭大事件的流量&lt;/p&gt;

&lt;p&gt;Notion 有一次大更新，改了 API。很多第三方工具挂了，我的也差点挂。但我提前一周看到了预告，连夜适配，更新说明里写了"已适配 Notion 最新 API"。&lt;/p&gt;

&lt;p&gt;那周搜索"Notion API update"的人暴增，我的插件因为关键词匹配，安装量翻了 3 倍。&lt;/p&gt;

&lt;p&gt;野路子四：别忽视 Chrome 商店本身的优化&lt;/p&gt;

&lt;p&gt;截图展示真实使用场景，不是 UI 截图。我第一张图是一个研究论文页面，上面有高亮和笔记，用户一眼就知道这工具是干嘛的&lt;/p&gt;

&lt;p&gt;描述前两句包含核心关键词&lt;/p&gt;

&lt;p&gt;回复每一条评论，哪怕只有"谢谢"。Chrome 商店算法奖励高互动率&lt;/p&gt;

&lt;p&gt;我踩过最大的坑：过早收费&lt;/p&gt;

&lt;p&gt;上线第一个月我就加了付费功能，结果付费用户没几个，免费用户因为功能限制给了很多差评。第二个月改成完全免费 + 捐赠，口碑回升，第三个月再推出 Pro 版，转化率反而更高。&lt;/p&gt;

&lt;p&gt;独立开发者的信任积累很慢，先让用户爱上产品，再谈钱。&lt;/p&gt;

&lt;p&gt;现在的困惑：&lt;/p&gt;

&lt;p&gt;8000 月活卡了两个月了，自然增长见顶。我在考虑要不要试试 Google Ads，但听说插件类 ROI 很低。有没有做过付费推广的兄弟？求分享经验，或者还有其他野路子推荐吗？&lt;/p&gt;</description>
      <author>freemanbrent40</author>
      <pubDate>Tue, 23 Jun 2026 10:19:45 +0800</pubDate>
      <link>https://w2solo.com/topics/7579</link>
      <guid>https://w2solo.com/topics/7579</guid>
    </item>
    <item>
      <title>三套方法论，10 个 AI 技能，我做了一个会自我进化的 Obsidian 知识库</title>
      <description>&lt;p&gt;收藏夹吃灰、笔记找不到、灵感转眼忘——问题不是你不够努力，而是没有一套系统。&lt;/p&gt;

&lt;p&gt;我花了两个月时间，把三套顶级方法论整合在一起，做了一个&lt;strong&gt;会自己整理的 Obsidian 知识库模板&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;一套基于 PARA + Zettelkasten + LLM Wiki 三套方法论整合的知识管理系统。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/cover-obsidian-ai-wiki.webp" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="三套方法论，各管一件事"&gt;三套方法论，各管一件事&lt;/h3&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;方法论&lt;/th&gt;
&lt;th&gt;提出者&lt;/th&gt;
&lt;th&gt;管什么&lt;/th&gt;
&lt;th&gt;核心理念&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PARA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tiago Forte&lt;/td&gt;
&lt;td&gt;信息分类&lt;/td&gt;
&lt;td&gt;按行动性分类，不是按主题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zettelkasten&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Niklas Luhmann&lt;/td&gt;
&lt;td&gt;知识连接&lt;/td&gt;
&lt;td&gt;卡片 + 链接，越积累越产生新洞见&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM Wiki&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Andrej Karpathy&lt;/td&gt;
&lt;td&gt;自动维护&lt;/td&gt;
&lt;td&gt;知识编译一次，持续更新&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;这套模板，就是把他们的方法整合在一起，让你直接用。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/01-framework-three-methods.webp" title="" alt="三套方法论如何组合成 Obsidian 知识库模板"&gt;&lt;/p&gt;
&lt;h3 id="知识库的四层结构"&gt;知识库的四层结构&lt;/h3&gt;
&lt;p&gt;大多数知识管理的失败，是因为「只存不流」。我设计了一套&lt;strong&gt;有流动方向&lt;/strong&gt;的四层结构：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│  输入层：原始资料（外部输入，不可变）                       │
├─────────────────────────────────────────────────────────┤
│  中间层：Wiki（LLM 提炼，可查询）                         │
├─────────────────────────────────────────────────────────┤
│  输出层：项目（你的作品：视频、文章、产品）                 │
├─────────────────────────────────────────────────────────┤
│  沉淀层：领域（你的方法论、经验、指南）                     │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/02-framework-four-layers.webp" title="" alt="Obsidian 知识库的输入层、中间层、输出层和沉淀层"&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;知识怎么流动？&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;外部世界
  ↓
原始资料（网页剪藏、文章、论文）—— 不可变
  ↓ /ingest 技能
Wiki（LLM 自动维护）—— 结构化、可查询
  ↓
  ├→ 你查询 → 直接使用
  ├→ 沉淀到 领域 → 你的方法论
  └→ 输出到 项目 → 视频、文章
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键区别：&lt;strong&gt;Wiki 是「别人的知识」，领域是「你的知识」。&lt;/strong&gt; 从 Wiki 到领域，不是复制，而是重新写——加入你的理解、你的应用、你的经验。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/03-flowchart-knowledge-flow.webp" title="" alt="知识从外部世界流入 Wiki 并输出到项目和领域"&gt;&lt;/p&gt;
&lt;h3 id="每个目录的职责"&gt;每个目录的职责&lt;/h3&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;目录&lt;/th&gt;
&lt;th&gt;本质&lt;/th&gt;
&lt;th&gt;谁写&lt;/th&gt;
&lt;th&gt;谁读&lt;/th&gt;
&lt;th&gt;类比&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;灵感库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;碎片想法&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;便利贴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;原始资料&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;外部输入&lt;/td&gt;
&lt;td&gt;你放&lt;/td&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;文件柜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wiki&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;结构化知识&lt;/td&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;图书馆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;领域&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;你的方法论&lt;/td&gt;
&lt;td&gt;你 +LLM&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;笔记本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;参考资料&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;外部原始资料&lt;/td&gt;
&lt;td&gt;你 +LLM&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;资料夹&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;项目&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;具体任务&lt;/td&gt;
&lt;td&gt;你 +LLM&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;任务清单&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;归档&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;已完成内容&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;td&gt;你&lt;/td&gt;
&lt;td&gt;档案室&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="PARA：按行动性分类"&gt;PARA：按行动性分类&lt;/h3&gt;
&lt;p&gt;PARA 的核心不是按主题分类，而是&lt;strong&gt;按行动性分类&lt;/strong&gt;：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;分类&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;th&gt;特征&lt;/th&gt;
&lt;th&gt;举例&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;P&lt;/strong&gt;rojects&lt;/td&gt;
&lt;td&gt;项目&lt;/td&gt;
&lt;td&gt;有截止日期，做完就结束&lt;/td&gt;
&lt;td&gt;这期视频、这次活动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt;reas&lt;/td&gt;
&lt;td&gt;领域&lt;/td&gt;
&lt;td&gt;长期维护，没有终点&lt;/td&gt;
&lt;td&gt;内容创作、客户服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;R&lt;/strong&gt;esources&lt;/td&gt;
&lt;td&gt;资源&lt;/td&gt;
&lt;td&gt;外部资料，可能有用&lt;/td&gt;
&lt;td&gt;官方文档、别人教程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;A&lt;/strong&gt;rchive&lt;/td&gt;
&lt;td&gt;归档&lt;/td&gt;
&lt;td&gt;不再活跃，保留记录&lt;/td&gt;
&lt;td&gt;完成的项目、过时资料&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;三个原则&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;按行动性分类，不是按主题&lt;/li&gt;
&lt;li&gt;定期流动，项目完成 → 归档&lt;/li&gt;
&lt;li&gt;领域只放自己的，参考资料放外部的&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;
&lt;h3 id="Zettelkasten：卡片+链接"&gt;Zettelkasten：卡片 + 链接&lt;/h3&gt;
&lt;p&gt;Zettelkasten 的核心是&lt;strong&gt;原子化 + 链接&lt;/strong&gt;。每个想法写成一张独立卡片，用 &lt;code&gt;[[]]&lt;/code&gt; 把相关卡片串起来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三种卡片类型&lt;/strong&gt;：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;举例&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;闪念卡&lt;/td&gt;
&lt;td&gt;突然想到的碎片&lt;/td&gt;
&lt;td&gt;灵感库里的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;洞见卡&lt;/td&gt;
&lt;td&gt;经过思考的结论&lt;/td&gt;
&lt;td&gt;某个方法论的核心观点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文献卡&lt;/td&gt;
&lt;td&gt;从外部摘录的内容&lt;/td&gt;
&lt;td&gt;读书笔记、文章摘录&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;链接原则&lt;/strong&gt;：不要只链接「相关的」，要链接「能产生新想法的」。一张卡片至少链接 2 张其他卡片。&lt;/p&gt;

&lt;hr&gt;
&lt;h3 id="LLM Wiki：让 AI 帮你维护"&gt;LLM Wiki：让 AI 帮你维护&lt;/h3&gt;
&lt;p&gt;传统 RAG 每次提问都从原始文档重新检索，没有积累。LLM Wiki 的核心区别是：&lt;strong&gt;知识编译一次，持续更新。&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;传统 RAG：  原始文档 → 每次重新检索 → 回答（无积累）
LLM Wiki：  原始文档 → LLM 编译成 wiki → 持续更新 → 回答（有积累）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;三层架构&lt;/strong&gt;：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;层级&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;谁负责&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Raw Sources&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;原始资料（文章、论文、图片、数据）&lt;/td&gt;
&lt;td&gt;你（不可变，只读）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The Wiki&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LLM 生成的 markdown 文件&lt;/td&gt;
&lt;td&gt;LLM（创建、更新、维护）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The Schema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;配置文件（如 CLAUDE.md）&lt;/td&gt;
&lt;td&gt;你和 LLM 共同演化&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;三个核心操作&lt;/strong&gt;：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ingest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;处理新来源 → 提取关键信息 → 整合到现有 wiki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;基于 wiki 回答问题，有价值的写回 wiki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定期健康检查：矛盾、过时、孤儿页面&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="10 个 AI 自动化技能"&gt;10 个 AI 自动化技能&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/04-infographic-ai-skills.webp" title="" alt="10 个 AI 自动化技能组成捕获、组织、创造和维护闭环"&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;技能&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;知识卡片&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/card&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;灵感/口播 → 结构化卡片（钩子 + 痛点 + 方案 + 金句）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;卡片可视化&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/card-picture&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文字 → 学术风格信息图&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;视频脚本&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/card-video&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;卡片 → 口播逐字稿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;摄入&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/ingest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;新文章/论文 → 自动整合到 wiki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查询&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/query&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;基于 wiki 回答问题，有价值的写回 wiki&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;健康检查&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/lint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;扫描矛盾、孤儿页面、过时内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;项目管理&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/project&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建项目、更新进度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;每日复盘&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/daily&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;扫描灵感库、检查进度、输出报告&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;发布&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/publish&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;生成封面标题、发布标题、标签&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;归档&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/archive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自动归档已完成项目&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;五套模板&lt;/strong&gt;&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;模板&lt;/th&gt;
&lt;th&gt;用途&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;视频脚本模板&lt;/td&gt;
&lt;td&gt;封面标题、发布标题、标签、状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;知识卡片模板&lt;/td&gt;
&lt;td&gt;来源、关联卡片&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;项目模板&lt;/td&gt;
&lt;td&gt;截止日期、任务清单&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文章模板&lt;/td&gt;
&lt;td&gt;平台、阅读量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;学习笔记模板&lt;/td&gt;
&lt;td&gt;来源、学习时长&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="实际工作流"&gt;实际工作流&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;场景 1：看到一篇好文章&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. 剪藏到 原始资料/文章/
2. /ingest → Wiki 自动生成结构化页面
3. 有问题 → /query → 从 Wiki 中找答案
4. 有价值 → 沉淀到 领域/
5. 要做内容 → 调用 Wiki 和领域 → 输出到 项目/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景 2：突然有个灵感&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. 语音转文字，记录到 灵感库/
2. /card → 生成钩子+痛点+方案+金句
3. /card-picture → 自动生成可视化配图
4. /card-video → 自动转成口播逐字稿
5. /publish → 自动生成标题和标签
6. 录制视频，发布，归档
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景 3：读一本书&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. 记录读书笔记到 参考资料/
2. 提炼方法论，沉淀到 领域/
3. /card 生成视频脚本
4. 录制视频，发布，归档
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景 4：每日复盘&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/daily
  ↓ 自动扫描灵感库、项目进度、wiki 健康
  ↓ 输出复盘报告 + 建议行动
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id="设计原则"&gt;设计原则&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;先捕捉，后整理&lt;/strong&gt; — 不要让灵感溜走&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;用自己的话&lt;/strong&gt; — 不要只是摘抄&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;定期回顾&lt;/strong&gt; — 发现新的链接和洞见&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;输出倒逼输入&lt;/strong&gt; — 写作是最好的学习&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;
&lt;h3 id="适合谁？"&gt;适合谁？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;✅ 内容创作者（视频、文章、课程）&lt;/li&gt;
&lt;li&gt;✅ 知识工作者（需要管理大量信息）&lt;/li&gt;
&lt;li&gt;✅ 终身学习者（读书、学课程）&lt;/li&gt;
&lt;li&gt;✅ 想用 AI 提升效率的人&lt;/li&gt;
&lt;li&gt;❌ 纯轻量笔记需求（备忘录就够了）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;这套知识库的核心就一句话：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;你只管输入，系统帮你输出。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;灵感不丢失，知识有连接，AI 帮整理，输出更高效。&lt;/p&gt;

&lt;p&gt;以上，既然看到这里了，如果对你有所帮助，还望不吝点赞与关注，这也是对我最大的鼓励与支持。&lt;/p&gt;

&lt;p&gt;感谢你拨冗阅读，山高水长，我们期待下篇文章与你再见。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;/ 更多 Agent 实战干货
迎访问我的博客：&lt;a href="https://www.dqtx.cc/" rel="nofollow" target="_blank" title=""&gt;dqtx.cc&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;文章来源&lt;/strong&gt;：&lt;a href="https://mp.weixin.qq.com/s/5LkcBS6TvwXEGxIMiA-1jQ" rel="nofollow" target="_blank" title=""&gt;点此查看&lt;/a&gt;&lt;/p&gt;</description>
      <author>sphinx30</author>
      <pubDate>Mon, 22 Jun 2026 21:40:34 +0800</pubDate>
      <link>https://w2solo.com/topics/7578</link>
      <guid>https://w2solo.com/topics/7578</guid>
    </item>
    <item>
      <title>AI 生成的代码能跑就行？这 5 个坑迟早炸</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;AI 写代码的效率毋庸置疑，但"能跑"和"能维护"之间隔了一道鸿沟。这篇文章总结了 AI 生成代码最常见的 5 个质量问题，每个都附反面案例和修复方案，最后给出一份 5 条验收 checklist。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;2026 年了，AI 写代码已经不是新鲜事。但我发现一个普遍现象：很多人的工作流是——&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;让 AI 生成代码&lt;/li&gt;
&lt;li&gt;能跑就提交&lt;/li&gt;
&lt;li&gt;出了 bug 再让 AI 修&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这个循环看似高效，实际上在代码仓库里埋了一堆定时炸弹。下面是我 review AI 代码时反复遇到的 5 个问题，从高频到低频排列。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="第一坑：过度工程化——3 行能解决的事写了 30 行"&gt;第一坑：过度工程化——3 行能解决的事写了 30 行&lt;/h2&gt;
&lt;p&gt;AI 特别喜欢上设计模式。你让它写一个"判断用户是否登录"的函数，它能给你整出工厂模式 + 策略模式 + 抽象基类：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AuthStrategyFactory.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AuthStrategyFactory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;createStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;strategies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;JwtAuthStrategy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SessionAuthStrategy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;oauth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;OAuthStrategy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;strategies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;JwtAuthStrategy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// JwtAuthStrategy.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;JwtAuthStrategy&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;BaseAuthStrategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;TokenDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;AuthResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthErrorCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INVALID_TOKEN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;AuthResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 另外还有：BaseAuthStrategy.js、TokenDecoder.js、AuthResult.js、AuthErrorCode.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;6 个文件，200 多行，就为了判断用户有没有登录。而这个项目从头到尾只用了 JWT 一种方式，不可能有 session 和 OAuth。&lt;/p&gt;

&lt;p&gt;实际需要的代码：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkAuth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个文件，15 行，功能完全一样。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么会这样：&lt;/strong&gt; AI 倾向于"展示它知道的所有设计模式"，而不是"用最简单的方式解决问题"。它没有偷懒的本能，而偷懒有时候是好事——逼你写出最简方案。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;怎么防：&lt;/strong&gt; 拿到 AI 代码先问自己——"删掉一半代码还能跑吗？"如果能，那删掉的就是过度设计。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="第二坑：幽灵代码——大量函数从未被调用"&gt;第二坑：幽灵代码——大量函数从未被调用&lt;/h2&gt;
&lt;p&gt;让 AI 写一个"订单模块的工具函数"，它会把所有它能想到的都给你：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// utils/orderHelpers.js&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calculateOrderDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;discountRules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userLevel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 45 行折扣计算逻辑&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;formatOrderForExport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;csv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 60 行导出格式化逻辑&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;validateOrderTransition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetStatus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 30 行状态机校验&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写得都挺好，逻辑也对。但问题是——&lt;strong&gt;项目根本没有折扣功能，没有导出功能，状态机也没用到。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这些就是"幽灵代码"：活在仓库里，从未被执行，但你维护的时候会把它们当成有用的代码去读、去理解。实际有效代码 5000 行的模块，可能躺了 3000 行死代码。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么会这样：&lt;/strong&gt; AI 不知道 YAGNI（You Ain't Gonna Need It）。它基于"这个场景可能需要什么"生成代码，而不是"现在到底需要什么"。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;怎么防：&lt;/strong&gt; 前端用 &lt;code&gt;knip&lt;/code&gt; 检测，比 &lt;code&gt;depcheck&lt;/code&gt; 更准：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx knip &lt;span class="nt"&gt;--include&lt;/span&gt; exports
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一条命令揪出所有未被使用的导出函数、类型、组件。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="第三坑：假注释——注释和代码说的不是同一件事"&gt;第三坑：假注释——注释和代码说的不是同一件事&lt;/h2&gt;
&lt;p&gt;这个坑最阴，因为你只看注释的话，逻辑是通的：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 检查用户是否有该订单的操作权限&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkOrderPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formattedOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YYYY-MM-DD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YYYY-MM-DD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;formattedOrder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注释说"检查权限"，代码在做&lt;strong&gt;数据格式化&lt;/strong&gt;。返回值不是 &lt;code&gt;boolean&lt;/code&gt;，是一个格式化后的对象。&lt;/p&gt;

&lt;p&gt;调用方写成了这样：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;checkOrderPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;无权限&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恰好，当 &lt;code&gt;orderId&lt;/code&gt; 不存在时 &lt;code&gt;findById&lt;/code&gt; 返回 &lt;code&gt;null&lt;/code&gt;，&lt;code&gt;!null === true&lt;/code&gt;，所以"权限检查"碰巧能跑。纯属巧合。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么会这样：&lt;/strong&gt; AI 先生成了一个权限检查函数，后来被要求加数据格式化逻辑，改了函数体但没改函数名和注释。这种"假注释"比没注释更危险——没注释你会认真读代码，有注释你会下意识信任它，跳过代码。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;怎么防：&lt;/strong&gt; 好的代码不需要注释。与其修注释，不如改函数名——&lt;code&gt;checkOrderPermission&lt;/code&gt; 改成 &lt;code&gt;formatOrderForDisplay&lt;/code&gt;，删掉注释，可读性反而更高。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="第四坑：万能 try-catch——出了 bug 永远定位不到"&gt;第四坑：万能 try-catch——出了 bug 永远定位不到&lt;/h2&gt;
&lt;p&gt;AI 特别喜欢给每个函数都包一层 try-catch：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;validateParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;notifyUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;updateInventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in createOrder:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;validateParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... 校验逻辑&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in validateParams:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每一层都默默吞掉错误，打个 &lt;code&gt;console.log&lt;/code&gt; 就完事。&lt;/p&gt;

&lt;p&gt;结果：线上出 bug，Sentry 里只有 "Error in createOrder: null"。是创建失败了？通知失败了？库存扣减失败了？你不知道。所有上下文都被 catch 吃掉了。&lt;/p&gt;

&lt;p&gt;更要命的是 &lt;code&gt;return null&lt;/code&gt;。调用方拿到 &lt;code&gt;null&lt;/code&gt; 以为"没有订单"，继续往下跑，导致后面一连串空指针。一个本该在源头暴露的错误，被层层掩盖，最后在距离原始问题八百里远的地方炸出来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;正确做法：错误冒泡，只在边界捕获。&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;validateParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 校验失败直接抛&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 数据库错误直接抛&lt;/span&gt;

  &lt;span class="c1"&gt;// 只有不影响主流程的旁路操作才 try-catch&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;notifyUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;通知发送失败，不影响订单创建&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;为什么会这样：&lt;/strong&gt; AI 出于"安全感"给每个函数加 try-catch——它不想让任何错误导致程序崩溃。但过度防御恰恰让 debug 变成噩梦。错误处理不是越多越好，是在&lt;strong&gt;正确的位置&lt;/strong&gt;处理。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="第五坑：data、data2、data3——变量名丢失业务语义"&gt;第五坑：data、data2、data3——变量名丢失业务语义&lt;/h2&gt;
&lt;p&gt;这个问题随处可见：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;submitData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;setList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;读到 &lt;code&gt;data3&lt;/code&gt; 的时候你已经忘了 &lt;code&gt;data&lt;/code&gt; 是什么了。对比一下：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchOrders&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formattedOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formatForDisplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allOrders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;activeOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formattedOrders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;submitResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;submitOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeOrders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setOrderList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一眼就知道每一步在做什么。&lt;/p&gt;

&lt;p&gt;另一个变种更常见：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/orders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/orders/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/items`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三个完全不同的接口，返回值都叫 &lt;code&gt;res&lt;/code&gt;。改 bug 的时候搜 &lt;code&gt;res&lt;/code&gt;，搜出来 47 个结果，祝你好运。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;为什么会这样：&lt;/strong&gt; AI 在生成整段代码时倾向于用通用名词。&lt;code&gt;data&lt;/code&gt; 是最安全的命名——不会出错，但也不传达任何信息。它没有你的业务上下文，不知道 &lt;code&gt;data&lt;/code&gt; 其实是"订单列表"。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;怎么防：&lt;/strong&gt; AI 生成代码后，第一件事搜 &lt;code&gt;data&lt;/code&gt;、&lt;code&gt;res&lt;/code&gt;、&lt;code&gt;result&lt;/code&gt;、&lt;code&gt;temp&lt;/code&gt;、&lt;code&gt;item&lt;/code&gt;，全部改成业务名词。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="AI 代码验收 Checklist"&gt;AI 代码验收 Checklist&lt;/h2&gt;
&lt;p&gt;以上 5 个坑归结起来，就是一句话：&lt;strong&gt;AI 的代码和实习生的代码一样，能跑但需要 review。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;每次 AI 生成代码后，花 5 分钟过一遍：&lt;/p&gt;
&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;检查项&lt;/th&gt;
&lt;th&gt;怎么查&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;删减测试&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;删掉一半代码还能跑吗？能跑的就是过度设计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;死代码检测&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;跑 &lt;code&gt;npx knip --include exports&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;注释一致性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;每条注释和代码对一下，不确定就删注释&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;错误处理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;搜 &lt;code&gt;catch&lt;/code&gt;，是不是只有 &lt;code&gt;console.log&lt;/code&gt;？该冒泡还是该吞？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;命名审查&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;搜 &lt;code&gt;data&lt;/code&gt;/&lt;code&gt;res&lt;/code&gt;/&lt;code&gt;result&lt;/code&gt;/&lt;code&gt;temp&lt;/code&gt;，全改成业务名词&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;5 分钟能省你三天的 debug 时间。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;你在 review AI 代码时踩到过什么坑？评论区聊聊。&lt;/em&gt;&lt;/p&gt;</description>
      <author>193577746</author>
      <pubDate>Mon, 22 Jun 2026 18:36:40 +0800</pubDate>
      <link>https://w2solo.com/topics/7577</link>
      <guid>https://w2solo.com/topics/7577</guid>
    </item>
    <item>
      <title>Square face generator</title>
      <description>&lt;p&gt;一个好玩的头像生成器，欢迎使用：
&lt;a href="https://square-faces.com" rel="nofollow" target="_blank"&gt;https://square-faces.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/Harlan/17f9cb63-dfd7-4611-8b26-6270143bb575.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/Harlan/8647cf8d-57a3-41cb-9379-81f90bfb67b9.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/Harlan/ad3144af-ad6a-4844-9e5b-7de283d35f84.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/Harlan/aa1e2aaf-a9af-417e-b97f-f37d1700c9b0.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>Harlan</author>
      <pubDate>Mon, 22 Jun 2026 17:45:49 +0800</pubDate>
      <link>https://w2solo.com/topics/7576</link>
      <guid>https://w2solo.com/topics/7576</guid>
    </item>
    <item>
      <title>纵马赴夏日，豪礼皆自达  影帝梁家辉实力背书 EZ-60 马年版上市 EZ-6 超级置换季开启</title>
      <description>&lt;p&gt;纵马赴夏日，豪礼皆自达。即日起至2026年5月31日，长安马自达继续加码全系车型购车礼遇。MAZDA EZ-60（以下称 EZ-60）马年版领衔登场，售价 13.99 万起，全系车型至高可享 23,000 元购车权益，进店试驾即赠国家非遗金陵金箔。MAZDA EZ-6（以下称 EZ-6）限时超级置换季开启，至高可享 17,000 元置换厂补和 20,000 元以旧换新国补。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/577dd6c1-4bdf-4b3c-b007-5b033f72aed7.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;EZ-60 马年版：千面影帝梁家辉实力背书 合资新能源 SUV 最优选&lt;/p&gt;

&lt;p&gt;作为连续 6 个月蝉联合资新能源中型 SUV 销量冠军的全球车型，EZ-60 持续优化产品阵容，马年版车型在北京车展正式上市，以增程 200 马年版 13.99 万元、纯电 600 马年版 14.59 万元的诚意定价，成为五一小长假自驾、露营、跨城出游的座驾最优选。活动期间，EZ-60 全系车型在至高 20,000 元以旧换新国补基础上，叠加 6 重专属购车礼遇：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;置换礼：至高可享 7,000 元置换厂补；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;拥车礼：免费赠送价值 950 元交强险；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;自燃包赔礼：赠送价值 7,999 元终身零燃权益，不限车主、不限里程；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;畅充礼：免费赠送价值 3,999 元原厂充电桩；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;升级礼：免费赠送 3,000 元专属选装基金；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;金融礼：支持 0 首付 5 年低息购车方案，年均费率低至 1.99%。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/f5dd4bf6-70b2-4fba-b660-364be3891225.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;作为全球唯一同时斩获德国 iF、美国 IDA 等 7 项国际顶级设计大奖的新能源 SUV，EZ-60 马年版完整传承了车型硬核实力，更精准响应马粉需求：开放原顶配车型专属紫色内饰选装，满足个性化定制需求；标志性 9 风道空气动力学设计，兼顾魂动美学与空气动力学性能，高速自驾时车身更稳；2,902mm 超长轴距带来宽绰车内空间，轻松容纳全套露营装备、婴儿车与多件行李箱，后排座椅放倒秒变 2 米纯平大床，景区游玩间隙随时躺平休息；中日德三国四地工程师联合调校，搭配 “人马一体” 的精准操控，无论是高速、山路，还是非铺装路面，都能带来从容稳定的驾乘体验，更有马自达独家 “不晕车” 黑科技，老人孩子长途乘坐也能全程舒适。&lt;/p&gt;

&lt;p&gt;EZ-6：限时超级置换季开启 至高享 17000 元置换厂补 +20000 元国补&lt;/p&gt;

&lt;p&gt;作为斩获 “2026 世界年度设计车大奖” 的全球战略车型，同时也是首款达成全球主流安全认证大满贯的合资新能源轿车，EZ-6 自上市以来便树立了合资新能源 B 级轿车价值标杆。电感「人马一体」的调校，精准复刻马自达标志性线性加速与弯道操控，兼顾舒适家用和操控乐趣；越级的车身尺寸与宽绰座舱，兼顾前排驾驶体验与后排乘坐舒适性，出行久坐不累，更有母婴级环保座舱材质，新车无异味，全家出行更安心。活动期间，进店试驾 EZ-6 即可获赠国家非遗金陵金箔，更有多重购车权益，全方位降低用户购车与用车门槛：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;限时超级置换季：至高 17,000 元置换厂补，至高 20,000 元以旧换新国补；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;拥车礼：免费赠送价值 3999 元原厂充电桩 + 价值 950 元交强险；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;金融权益礼：支持 0 首付 5 年低息购车方案，年均费率低至 1.99%；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;自燃包赔礼：赠送价值 7,999 元终身零燃权益，不限车主、不限里程。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/2a278285-a5df-4966-b5d2-900d8bb62bcc.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;CX-50 行也：焕新一口价 13.98 万起 至高享 21,000 元补贴&lt;/p&gt;

&lt;p&gt;“山系生活宽体 SUV” CX-50 行也，天生适配户外出行生活方式，完美契合当代家庭 “城市通勤 + 户外旅行” 的多元出行需求。4785mm 越级车长搭配宽体车身设计，带来远超同级的车内空间与后备箱容积，帐篷、天幕、折叠桌椅、山地自行车等户外装备均可轻松收纳；高离地间隙搭配专业级底盘调校，城市铺装路面、乡间非铺装小路、山野轻度穿越路况皆可从容应对，带你解锁更多小众风景。活动期间，CX-50 行也焕新一口价 13.98 万元起，叠加 6,000 元置换厂补与至高 15,000 元以旧换新国补，综合补贴可达 21,000 元。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/03094868-9bad-4973-8fed-a2466f6f5514.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;与此同时，长安马自达多款经典燃油产品同步奉上五一专属福利，全面覆盖不同用户的出行需求：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;次世代 MAZDA 3 昂克赛拉：全系 8.99 万起，购车可享至高 14,000 元以旧换新国补，灵活好开、油耗经济，是年轻群体城市通勤、假日出游的乐趣之选；&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/23a7e3a8-2e3c-487c-9e85-a25f3167eecf.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MAZDA CX-5：限时 11.58 万起，至高可享 15,000 元以旧换新国补与 6,000 元置换厂补，全球超 400 万用户口碑背书，兼顾家用舒适与操控乐趣，全家出行无压力；&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/8ebcd3c2-80de-4a74-9d03-763accafcb9f.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MAZDA CX-30：全系 9.99 万起，叠加至高 14,000 元以旧换新国补，潮酷造型灵动小巧，城市打卡、山路自驾都能轻松驾驭，是自驾出行的个性之选。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/yuanguanhua/6d049814-4484-4e92-8c3c-28caaf7fb74c.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;即日起，可前往长安马自达全国授权经销商门店，或通过 “悦马星空” APP、官方小程序查询政策详情、预约试驾及预订新车。无论是燃油车时代，还是新能源时代，长安马自达将持续以全球顶级的安全品质、越级的产品实力与诚意满满的福利政策，携手每一位用户，在马年开启更多美好出行新旅程。&lt;/p&gt;</description>
      <author>yuanguanhua</author>
      <pubDate>Mon, 22 Jun 2026 17:28:44 +0800</pubDate>
      <link>https://w2solo.com/topics/7575</link>
      <guid>https://w2solo.com/topics/7575</guid>
    </item>
    <item>
      <title>怎么做三角洲电竞代练护航陪玩小程序？全面介绍系统功能和搭建准备流程</title>
      <description>&lt;p&gt;面对 “三角洲行动” 催生的刚性护航需求，成熟的技术方案可在 48 小时内上线全流程陪玩小程序。技术生态已高度成熟，市面上存在商用级护航小程序系统源码，采用 ThinkPHP6+MySQL5.6 后端、Uniapp+Vue2 前端、自研 WorkermanIM 引擎实现毫秒级消息推送，独立部署兼容阿里云、腾讯云。系统覆盖用户、店员、客服、工作室、管理后台五端，包含发单、派单、结算、评价等全流程闭环。建议先以小程序跑通获客→下单→服务→复购流程，前端页面展示老板端/下单：极速下单选择游戏品类、大神、规格并支付，需求发布客服智能匹配派单，大神列表多维度筛选，钱包充值支持微信/支付宝，评价系统积累口碑，退款申请一键发起，转盘抽奖增加趣味性，老客一键填单。店员/客服端支持三模式接单、多品类独立开关、等级认证、保证金管理、收益明细。搭建需准备营业执照、法人信息、对公账户、邮箱手机号等资质，及服务器、域名、服务号、小程序等第三方产品，安装后端并打包前端，申请接口调试参数，申请服务号备案小程序，后台完善参数上传审核。核心适配电竞服务、游戏工作室、陪玩行业，延伸适配游戏博主私域变现、综合数字平台增值服务，支持段位提升、代肝任务等游戏增值服务。
&lt;img src="https://img.way2solo.com/photo/dkrjkf/f2ab14fb-9c23-4a3c-bce3-5c53f596d8ca.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
技术生态层面
系统方案已高度成熟。 目前市面上已有多套商用级护航小程序系统源码，技术栈普遍采用：&lt;/p&gt;

&lt;p&gt;后端：ThinkPHP 6 + MySQL 5.6，支持高并发&lt;/p&gt;

&lt;p&gt;前端：Uniapp + Vue2，一套代码编译微信小程序、H5、iOS/Android APP 多端&lt;/p&gt;

&lt;p&gt;即时通讯：自研 Workerman IM 引擎，零成本实现毫秒级消息推送&lt;/p&gt;

&lt;p&gt;部署方式：独立部署，兼容阿里云、腾讯云，48 小时内可上线&lt;/p&gt;

&lt;p&gt;功能体系完善。 成熟的系统已覆盖用户端、店员端、客服端、工作室端、管理后台五端协同，包含快速发单、智能/自选派单、订单流转、自动结算、车队单分成、保证金体系、评价投诉、售后退款等全流程闭环。
&lt;img src="https://img.way2solo.com/photo/dkrjkf/8911ab53-fb7a-4e65-a57a-6ac2d3d3ab03.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如果你正在考虑入局这个赛道，建议先以小程序跑通"获客→下单→服务→复购"&lt;/p&gt;

&lt;p&gt;老板端/下单&lt;/p&gt;

&lt;p&gt;✅ 极速下单选择游戏品类 → 选大神 → 选规格 → 支付，最快 3 步完成下单&lt;/p&gt;

&lt;p&gt;✅ 需求发布填写段位/声音/性别等需求，客服智能匹配后派单&lt;/p&gt;

&lt;p&gt;✅ 大神列表筛选按性别、等级、价格、关注多维度筛选，快速找到合适大神&lt;/p&gt;

&lt;p&gt;✅ 钱包充值支持微信/支付宝充值，余额明细、消费记录实时查询&lt;/p&gt;

&lt;p&gt;✅ 评价系统服务结束后打分、文字评价，帮助平台积累口碑&lt;/p&gt;

&lt;p&gt;✅ 退款申请订单页一键发起退款，上传凭证，实时查看审核进度&lt;/p&gt;

&lt;p&gt;✅ 转盘抽奖购买带抽奖的订单后，可在订单页参与幸运转盘&lt;/p&gt;

&lt;p&gt;✅ 老客一键填单再次下单时自动读取上次订单的游戏昵称/ID/大区/联系方式，一键填入&lt;/p&gt;

&lt;p&gt;高效下单，灵活选服​ 老板可快速筛选热门游戏类目，按需选择服务模式 —— 支持指定心仪打手、等待打手抢单或由平台客服专业派单，无需繁琐操作，3 步即可完成下单，精准匹配游戏需求。&lt;/p&gt;

&lt;p&gt;店员 /客服端&lt;/p&gt;

&lt;p&gt;⭐ 三模式接单
选人下单 + 抢单（主动抢）+ 客服派单，三种模式并行不干扰&lt;/p&gt;

&lt;p&gt;✅ 多品类独立开关王者/吃鸡/LOL 等游戏卡片式开关，一个账号可同时开启多个品类接单&lt;/p&gt;

&lt;p&gt;✅ 等级认证与主页店员等级标识、个人主页背景图、动态帖子，打造专属人设&lt;/p&gt;

&lt;p&gt;✅ 接单开关 一键在线/隐身，不影响已接订单继续执行&lt;/p&gt;

&lt;p&gt;✅ 保证金管理 查看保证金余额、主动缴纳、查看扣缴记录&lt;/p&gt;

&lt;p&gt;✅ 收益明细 每笔订单收益、佣金、提现记录一目了然&lt;/p&gt;

&lt;p&gt;✅ 流程建议 只需接单 - 服务 - 上传完成截图&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkrjkf/79b13633-9313-47e7-acdb-5fc2a8e1d284.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/9a24f366-cd42-42a2-a733-2106f4df4a5b.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/434c6098-2085-46fb-b8ff-c18376df4a74.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/e41656e1-7631-42a8-b9e9-d4c6485c1aec.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如何搭建护航陪玩小程序平台？
需要准备：&lt;/p&gt;

&lt;p&gt;一、需要资质&lt;/p&gt;

&lt;p&gt;1.营业执照：个体户和企业执照都行，主要用于各种认证和小程序服务号及域名的备案等&lt;/p&gt;

&lt;p&gt;2.法人信息：认证信息需要&lt;/p&gt;

&lt;p&gt;3.对公账户：企业执照需要对公账户，个体户可用法人的银行卡；申请微信商户号用于平台收款&lt;/p&gt;

&lt;p&gt;4.邮箱、手机号：申请各个平台的账号和登录&lt;/p&gt;

&lt;p&gt;二、需要第三方产品&lt;/p&gt;

&lt;p&gt;1.服务器：安装承载系统的运行&lt;/p&gt;

&lt;p&gt;2.域名：需备案，用于访问系统&lt;/p&gt;

&lt;p&gt;3.服务号、小程序：都需要认证，且小程序要备案&lt;/p&gt;

&lt;p&gt;三、源码系统
后端源码：Thinkphp6&lt;/p&gt;

&lt;p&gt;前端源码： UNI-APPvue2.0（支持一键式发布 H5、微信小程序、安卓/iOS 苹果 app）&lt;/p&gt;

&lt;p&gt;宝塔： 安装后台、管理网站&lt;/p&gt;

&lt;p&gt;搭建流程和上线步骤：&lt;/p&gt;

&lt;p&gt;1.获取源码（源码交付、永久域名授权/非租用版）&lt;/p&gt;

&lt;p&gt;2.安装后端并打包前端（H5+ 小程序 +APP）&lt;/p&gt;

&lt;p&gt;3.申请接口并调试参数（商户号）&lt;/p&gt;

&lt;p&gt;4.申请服务号、备案小程序&lt;/p&gt;

&lt;p&gt;5.后台填写并完善各个参数&lt;/p&gt;

&lt;p&gt;6.上传小程序进行审核&lt;/p&gt;

&lt;p&gt;推荐源码&lt;/p&gt;

&lt;p&gt;核心适配行业（游戏服务相关匹配的领域）：&lt;/p&gt;

&lt;p&gt;1.FPS 或竞技网游陪玩、护航、代肝的电竞服务行业，&lt;/p&gt;

&lt;p&gt;2.管理私域订单和打手团队的游戏工作室，&lt;/p&gt;

&lt;p&gt;3.提供上分陪玩等服务的电竞陪玩行业，&lt;/p&gt;

&lt;p&gt;4.淘宝拼多多上的游戏代练电商店铺；&lt;/p&gt;

&lt;p&gt;延伸适配行业 (可拓展使用该系统的领域)：&lt;/p&gt;

&lt;p&gt;1.游戏博主用它实现粉丝私域变现，&lt;/p&gt;

&lt;p&gt;2.综合数字平台增加游戏增值服务类目，&lt;/p&gt;

&lt;p&gt;3.创业团队快速搭建游戏服务平台；&lt;/p&gt;

&lt;p&gt;适配业务类型 (系统能支持的具体服务内容)：&lt;/p&gt;

&lt;p&gt;1.包括段位提升、代肝任务、游戏护航、陪玩等标准化或定制化的游戏增值服务。&lt;/p&gt;

&lt;p&gt;明确系统的目标用户和应用场景，旨在帮助不同类型的运营者判断是否适合使用该系统。&lt;img src="https://img.way2solo.com/photo/dkrjkf/50007e54-85ce-4da9-a738-908bbbf6de12.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>dkrjkf</author>
      <pubDate>Mon, 22 Jun 2026 14:43:48 +0800</pubDate>
      <link>https://w2solo.com/topics/7574</link>
      <guid>https://w2solo.com/topics/7574</guid>
    </item>
    <item>
      <title>做了个免费 AI 图片去字工具：PicTextRemover，也能顺手去水印和去杂物</title>
      <description>&lt;p&gt;最近把 PicTextRemover 主站重新整理了一下，核心还是做 “图片里的字干净去掉”，适合处理截图标题、海报文案、商品图标签、旧活动字样这些场景。&lt;/p&gt;

&lt;p&gt;我自己最在意的是别把背景抹糊，所以现在的思路是：先手动涂抹要去掉的区域，再让 AI 做局部重建，尽量把周围纹理、边缘和光影接回来。&lt;/p&gt;

&lt;p&gt;现在主要有 3 个入口：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pictextremover.com/" rel="nofollow" target="_blank" title=""&gt;PicTextRemover&lt;/a&gt;：偏通用的图片去字 / 去说明文字&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pictextremover.com/watermark-remover" rel="nofollow" target="_blank" title=""&gt;Watermark Remover&lt;/a&gt;：更适合去水印、logo、印章&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pictextremover.com/object-remover" rel="nofollow" target="_blank" title=""&gt;Object Remover&lt;/a&gt;：更适合去路人、杂物、穿帮元素&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;比较适合的图：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;商品图和详情图&lt;/li&gt;
&lt;li&gt;截图里的字幕、标签、时间字样&lt;/li&gt;
&lt;li&gt;海报和社媒图上的旧文案&lt;/li&gt;
&lt;li&gt;想复用但被水印或小杂物影响的图片&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;目前是免费可用版本，想先多收一些真实反馈，尤其想听听大家对下面两点的看法：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;去字时你更在意 “干净”，还是更在意 “速度”？&lt;/li&gt;
&lt;li&gt;你们最常见的图片清理场景是什么？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果你愿意试试，欢迎直接拍砖。&lt;/p&gt;</description>
      <author>xuseen</author>
      <pubDate>Mon, 22 Jun 2026 13:56:25 +0800</pubDate>
      <link>https://w2solo.com/topics/7573</link>
      <guid>https://w2solo.com/topics/7573</guid>
    </item>
    <item>
      <title>KidoX, 一个开源的 macOS Launchpad 替代 App</title>
      <description>&lt;p&gt;最近升级 macOS Tahoe 后，一切都感觉挺好的，最不适应的是 Launchpad 没了，取而代之的是一个不可拖动、窗口大小也不能调整的 Apps 窗口。&lt;/p&gt;

&lt;p&gt;所以我做了一个叫 KidoX 的小工具，目标是尽量还原一个更好用的 Launchpad：可以快速打开应用、整理应用、隐藏不常用应用，也支持一些外观和交互设置。&lt;/p&gt;

&lt;p&gt;目前第一个版本已经基本可用。&lt;/p&gt;

&lt;p&gt;网站： &lt;a href="https://kidox.app" rel="nofollow" target="_blank"&gt;https://kidox.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;源码： &lt;a href="https://github.com/defcc/kidox.app" rel="nofollow" target="_blank"&gt;https://github.com/defcc/kidox.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;源码是公开的，你可以自己 build 使用，完全免费。 如果不想自己构建，也可以直接从网站下载已经打包好的安装包。&lt;/p&gt;

&lt;p&gt;欢迎大家试用，也欢迎提 issue / PR 。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/defcc/0aaa5a57-6b24-4d1e-96e8-185c9b849922.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/defcc/a455a165-2e62-4ba5-884c-58ba7ebc422e.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>defcc</author>
      <pubDate>Mon, 22 Jun 2026 13:14:30 +0800</pubDate>
      <link>https://w2solo.com/topics/7572</link>
      <guid>https://w2solo.com/topics/7572</guid>
    </item>
    <item>
      <title>Telegram 登录验证机制的技术观察：多通道容错设计与 +86 号码的实践记录</title>
      <description>&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/quyb63232/70f82e02-5ec5-474f-8b65-66ce7473b993.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;最近在研究即时通讯产品的登录流程，Telegram 的验证机制有一些值得记录的细节。这篇算是技术笔记，分享给有同样兴趣的开发者。&lt;/p&gt;

&lt;p&gt;一、Telegram 的验证通道架构&lt;/p&gt;

&lt;p&gt;Telegram 的登录流程在简洁的 UI 之下，其实实现了一个多通道容错的验证系统。作为开发者，拆解一下它的设计思路：&lt;/p&gt;

&lt;p&gt;通道 1：SMS 验证码&lt;/p&gt;

&lt;p&gt;默认路径，依赖运营商 SMS 网关&lt;/p&gt;

&lt;p&gt;在部分场景下（漫游、运营商策略限制）存在送达率问题&lt;/p&gt;

&lt;p&gt;通道 2：语音验证码（Voice Call）&lt;/p&gt;

&lt;p&gt;在 SMS 等待界面提供 fallback 选项&lt;/p&gt;

&lt;p&gt;系统主动呼入语音电话，自动播报验证码&lt;/p&gt;

&lt;p&gt;实测在 Android 和 iOS 上实现一致，送达率高于 SMS&lt;/p&gt;

&lt;p&gt;通道 3：已登录设备授权&lt;/p&gt;

&lt;p&gt;利用现有登录设备作为"信任锚点"&lt;/p&gt;

&lt;p&gt;新设备请求验证时，已登录设备推送确认通知&lt;/p&gt;

&lt;p&gt;完全绕过手机号接收环节，适合多设备开发者场景&lt;/p&gt;

&lt;p&gt;通道 4：桌面端先行 + 移动端扫码&lt;/p&gt;

&lt;p&gt;桌面端（Telegram Desktop）完成登录&lt;/p&gt;

&lt;p&gt;移动端通过二维码扫描接入&lt;/p&gt;

&lt;p&gt;对于频繁切换测试设备的开发者，这是最顺畅的路径&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/quyb63232/3006cbcd-dda1-43bf-af00-8ab0df764575.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;二、+86 号码的实测记录&lt;/p&gt;

&lt;p&gt;我的账号绑定的是 +86 号码，用了比较长时间。&lt;/p&gt;

&lt;p&gt;差异主要与运营商层面的策略有关，而非 Telegram 服务端的问题。&lt;/p&gt;

&lt;p&gt;三、对独立开发者的启发&lt;/p&gt;

&lt;p&gt;Telegram 的登录设计有几个值得借鉴的点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;多通道降级策略&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;不要假设单一路径永远可用。SMS、语音、设备授权三条路径互为 backup，任何一条通畅就能完成验证。这种设计思路在产品架构中很有参考价值——尤其是当你的产品依赖第三方服务（如短信服务商、支付网关）时。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;信任链的渐进式构建&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;已登录设备成为后续设备的信任基础，减少了重复验证成本。类似的设计可以应用在多设备同步、会话管理等功能中。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;跨平台一致性&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Android 和 iOS 的登录流程几乎完全一致，背后是协议层的统一设计。对于需要同时维护多端的独立开发者来说，这种"协议先行、UI 跟随"的思路能减少很多适配成本。&lt;/p&gt;

&lt;p&gt;四、结语
这篇没有"教程"的野心，只是记录了一个开发者在使用 Telegram 过程中观察到的一些技术细节。如果你也研究过其他 IM 产品的登录机制（比如 Signal、WhatsApp 的设计差异），欢迎在评论区交流。&lt;/p&gt;

&lt;p&gt;我会把我的登录方法分享在评论区，大家可以去试试，然后即可一起讨论他的登录流程~&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/quyb63232/ffded166-c790-4eb0-b1fa-b4ad76817deb.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>quyb63232</author>
      <pubDate>Mon, 22 Jun 2026 10:11:09 +0800</pubDate>
      <link>https://w2solo.com/topics/7571</link>
      <guid>https://w2solo.com/topics/7571</guid>
    </item>
    <item>
      <title>【限时福利 免费试用】动态住宅低至 0.5$/GB 静态 ISP 低至 3.8$/条</title>
      <description>&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/Novproxy6/74e05cb4-9020-4077-a838-fcbc1668fb4a.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>Novproxy6</author>
      <pubDate>Mon, 22 Jun 2026 10:08:50 +0800</pubDate>
      <link>https://w2solo.com/topics/7570</link>
      <guid>https://w2solo.com/topics/7570</guid>
    </item>
    <item>
      <title>海外公司注册前，建议先想清楚这几个问题</title>
      <description>&lt;p&gt;很多客户一开始咨询海外公司注册时，都会先问：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;注册哪里比较好？&lt;br&gt;
香港公司好还是新加坡公司好？&lt;br&gt;
岛屿公司是不是更方便？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;其实在回答这些问题之前，更建议先想清楚 “公司准备用来做什么”。&lt;/p&gt;

&lt;p&gt;因为海外公司不是注册完就结束了，后续还涉及年审、审计、开户、维护、税务申报、知识产权归属等问题。&lt;/p&gt;

&lt;p&gt;注册前可以先确认几个问题：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;公司主要用途是什么？&lt;br&gt;
是跨境业务、海外客户签约、品牌出海，还是架构安排？&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;是否需要银行账户？&lt;br&gt;
如果需要开户，要提前了解账户维护和资料要求。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;是否需要长期使用？&lt;br&gt;
如果只是短期试水，要考虑后续维护成本。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;是否涉及知识产权？&lt;br&gt;
比如商标、专利、版权是否需要用公司名义申请。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;是否能接受后续维护？&lt;br&gt;
不同国家和地区，对年审、审计、报税的要求不同。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果公司不用了，是否知道如何处理？&lt;br&gt;
很多公司不是 “不用了就放着”，后续可能还需要正常注销。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;常见海外公司包括香港公司、新加坡公司、BVI、开曼、塞舌尔等。不同主体没有绝对好坏，主要看实际用途和后续维护需求。&lt;/p&gt;

&lt;p&gt;我所在公司主要做海外/离岸公司注册、公司开户协助、年审审计、全球知识产权注册等基础服务，已有多年行业经验。我们不介入客户具体业务操作，但可以协助客户完成主体搭建和后续维护。&lt;/p&gt;

&lt;p&gt;如果大家对某类主体感兴趣，比如香港公司、新加坡公司、岛屿公司，也可以后续单独聊聊它们各自适合的情况。&lt;/p&gt;</description>
      <author>api_to_inc</author>
      <pubDate>Mon, 22 Jun 2026 09:18:14 +0800</pubDate>
      <link>https://w2solo.com/topics/7569</link>
      <guid>https://w2solo.com/topics/7569</guid>
    </item>
    <item>
      <title>如何快速制作高考班级毕业去向分布图</title>
      <description>&lt;p&gt;高考已经落下帷幕，在 6 月 23 日全国各省就将陆续迎来出分、报志愿和录取... 在这少年各赴山海之际，如何用一张毕业去向分布图，留住全班奔赴各地的温柔印记？&lt;/p&gt;

&lt;p&gt;今天给大家介绍我打造的这款毕业蹭饭图快速制作工具。不需要任何专业设计，轻松在线操作，就能生成一张专属班级的毕业去向分布图。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://huayemao.run/api/files/e2c8ca9f8f8df8e0.png" title="" alt="毕业蹭饭图快速制作工具界面截图"&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;打开 &lt;a href="https://uni.utities.online/" rel="nofollow" target="_blank" title=""&gt;china edu atlas 高校名录数据可视化平台&lt;/a&gt;，点击进入&lt;a href="https://uni.utities.online/map-creator" rel="nofollow" target="_blank" title=""&gt;毕业去向分布图制作工具&lt;/a&gt;
&lt;img src="https://huayemao.run/api/files/30092601e8890916.png" title="" alt="在 china edu atlas 高校名录数据可视化平台主页，点击上方导航栏中的毕业去向分布图制作工具菜单项，进入该功能页面"&gt;
&lt;/li&gt;
&lt;li&gt;在标题设置中修改地图标题，如"师大附中 2026 届 5 班毕业去向分布图"
&lt;img src="https://huayemao.run/api/files/8a98a102877d8b91.webp" title="" alt="在标题设置中修改要制作的蹭饭图的标题信息"&gt;
&lt;/li&gt;
&lt;li&gt;点左上角进入数据选项卡，清除预置数据
&lt;img src="https://huayemao.run/api/files/460231a6a2e97096.webp" title="" alt="清除预置的录取信息数据"&gt;
&lt;/li&gt;
&lt;li&gt;手动输入班级内的学生录取院校信息，也可以根据固定格式的 excel 模板，一键导入 excel 表格。
&lt;img src="https://huayemao.run/api/files/c157b6f4c6d99095.png" title="" alt="点击按钮，添加学生录取信息"&gt;
&lt;img src="https://huayemao.run/api/files/e85b4e5dcb61276d.png" title="" alt="填写同学姓名、录取院校、省份后，右侧地图上就可以实时预览出该条目信息"&gt;
&lt;/li&gt;
&lt;li&gt;自由挑选喜欢的样式与配色：数据录入完成后，可切换到样式 Tab ，调整布局风格、配色组合、字体配置、其他布局参数等。
&lt;img src="https://huayemao.run/api/files/a83e6a8e8972b3c6.webp" title="" alt="数据录入完成后，调整毕业蹭饭图的样式"&gt;
&lt;/li&gt;
&lt;li&gt;导出图片：点击右上角的【导出高清图】按钮导出制作好的班级毕业去向图。或者也可直接截图保存。
&lt;img src="https://huayemao.run/api/files/71c338671405bda5.webp" title="" alt="点击【导出高清图】按钮，导出得到高考班级毕业去向图高清图片"&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>huayemao</author>
      <pubDate>Sun, 21 Jun 2026 15:46:12 +0800</pubDate>
      <link>https://w2solo.com/topics/7568</link>
      <guid>https://w2solo.com/topics/7568</guid>
    </item>
    <item>
      <title>Codex App 接上微信，我开始在厕所里改 Bug 了</title>
      <description>&lt;p&gt;这两天折腾了一个挺有意思的东西：&lt;/p&gt;

&lt;p&gt;把个人微信接到 Codex 上。&lt;/p&gt;

&lt;p&gt;以后不用一直坐在电脑前开着 Codex APP。人在外面，手机微信里发一句话，家里或办公室那台电脑上的 Codex 就能收到任务，继续帮你改代码、查项目、跑命令、整理文件。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;项目地址&lt;/strong&gt;
&lt;a href="https://github.com/Gan-Xing/CodexBridge" rel="nofollow" target="_blank"&gt;https://github.com/Gan-Xing/CodexBridge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;它做的事情很直接：把微信消息转成 Codex 能处理的请求，再把 Codex 的回复发回微信。
&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/cover-wechat-codex-bridge-apimart.webp" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;简单理解就是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;个人微信 -&amp;gt; CodexBridge -&amp;gt; 本机 Codex -&amp;gt; CodexBridge -&amp;gt; 个人微信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Codex 还是跑在你的电脑上，项目文件也还是在你的电脑上。微信只是多了一个远程入口。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/flow-wechat-codex-bridge.webp" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="最简单的接入方式"&gt;最简单的接入方式&lt;/h3&gt;
&lt;p&gt;如果你已经安装好了 Codex APP，可以直接把下面这句话发给 Codex：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/Gan-Xing/CodexBridge 帮我对接个人微信
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/20260620233854951.webp" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;Codex 会自动处理后面的流程：克隆项目、安装依赖、检查环境、生成二维码、等待扫码、启动桥接服务。&lt;/p&gt;
&lt;h3 id="扫码登录"&gt;扫码登录&lt;/h3&gt;
&lt;p&gt;依赖安装完之后，它会给你一个二维码。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/20260620233959351.webp" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;用个人微信扫一下，然后在手机上确认登录就行。&lt;/p&gt;

&lt;p&gt;这里注意一点：二维码有效期比较短。如果提示「二维码已过期」，让 Codex 重新生成一张再扫，不用纠结。&lt;/p&gt;
&lt;h3 id="成功后怎么测试"&gt;成功后怎么测试&lt;/h3&gt;
&lt;p&gt;扫码成功后，本机会生成微信账号凭证，通常在：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Users\你的用户名\.codexbridge\weixin\accounts\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Windows 上还可以注册成计划任务，任务名一般是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CodexBridge-Weixin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样以后登录 Windows，它会自动启动。&lt;/p&gt;

&lt;p&gt;接入成功后，打开微信，给桥接会话发：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果能收到回复，说明链路已经通了。&lt;/p&gt;

&lt;p&gt;后面就可以直接发自然语言任务，比如：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;帮我看一下 D:\project2026\fuwari 这个项目最近有哪些改动，整理成一段提交说明。
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="常用命令"&gt;常用命令&lt;/h3&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看帮助&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看当前桥接状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/new 路径&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;切换到新的项目目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/threads&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看历史线程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/open 2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打开某个历史线程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;停止当前正在跑的任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/retry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;重试上一条请求&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;日常远程使用，先记住这几个就够了。&lt;/p&gt;
&lt;h3 id="几个注意点"&gt;几个注意点&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;一、Windows 脚本路径可能要改&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;项目自带的 &lt;code&gt;.cmd&lt;/code&gt; 里可能写着作者自己的电脑路径，需要改成你本机的 Codex 路径和工作目录。&lt;/p&gt;

&lt;p&gt;比如：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;D:\software\Codex\app\resources\codex.exe
D:\zed-workspace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你是让 Codex 自动接入，它一般会自己检查并替你改掉。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;二、二维码过期很正常&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;看到二维码就马上扫。过期了就重新生成。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三、电脑要保持在线&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这个桥接不是云服务。CodexBridge 跑在你本机上，所以电脑关机、睡眠、断网，微信就收不到回复。&lt;/p&gt;

&lt;p&gt;如果打算长期使用，建议关闭自动睡眠，并用 Windows 计划任务保持服务常驻。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;四、注意权限边界&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;微信消息最后会变成 Codex 在你电脑上的任务，所以不要随便开放给别人用。建议只处理私聊，群聊默认关闭，或者只允许指定用户。&lt;/p&gt;
&lt;h3 id="适合什么场景"&gt;适合什么场景&lt;/h3&gt;
&lt;p&gt;它不是为了替代 Codex APP，而是给 Codex 多开了一个入口。&lt;/p&gt;

&lt;p&gt;电脑端适合认真操作，微信端适合随手派活。&lt;/p&gt;

&lt;p&gt;比如你在外面突然想到一个需求、一段文案、一个代码修改点，就可以直接发给微信里的 Codex。只要电脑在线，它就能在背后继续干活。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://gitee.com/da-qiang-classmate/typora/raw/master/image/remote-work-wechat-codex.webp" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;这次接入之后，我最大的感受是：&lt;/p&gt;

&lt;p&gt;AI Agent 真正变好用，不只是模型变强，而是入口变近。&lt;/p&gt;

&lt;p&gt;以前你要坐到电脑前，打开软件，找到项目，再开始说需求。&lt;/p&gt;

&lt;p&gt;现在变成了：&lt;/p&gt;

&lt;p&gt;想到什么，微信发一句。&lt;/p&gt;

&lt;p&gt;对于改代码、整理文件、写博客、查项目状态这类任务，这个体验已经很实用了。&lt;/p&gt;

&lt;p&gt;以上，既然看到这里了，如果对你有所帮助，还望不吝点赞与关注，这也是对我最大的鼓励与支持。&lt;/p&gt;

&lt;p&gt;感谢你拨冗阅读，山高水长，我们下次再见。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;gt;/ 更多可落地干货教程
欢迎访问我的博客：&lt;a href="https://www.dqtx.cc/" rel="nofollow" target="_blank" title=""&gt;dqtx.cc&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description>
      <author>sphinx30</author>
      <pubDate>Sun, 21 Jun 2026 15:28:09 +0800</pubDate>
      <link>https://w2solo.com/topics/7567</link>
      <guid>https://w2solo.com/topics/7567</guid>
    </item>
    <item>
      <title>2026 年了，这 6 个 npm 包可以卸载了——浏览器原生 API 已经能替代</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;前几天我跑了一下 &lt;code&gt;npx depcheck&lt;/code&gt;，发现项目里有 47 个依赖，其中至少 6 个完全可以用浏览器原生 API 替代。卸载之后，打包体积直接少了 82KB（gzip 后少了 23KB），首屏加载快了 300ms。这篇文章把每个包的原生替代方案都写出来，附迁移代码，直接抄。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="为什么要清理依赖"&gt;为什么要清理依赖&lt;/h2&gt;
&lt;p&gt;每多一个 npm 包，你的项目就多了：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;打包体积&lt;/strong&gt;：用户每次访问都要多下载这些代码&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;供应链风险&lt;/strong&gt;：还记得 &lt;code&gt;event-stream&lt;/code&gt; 投毒事件吗？依赖越少，攻击面越小&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;版本冲突&lt;/strong&gt;：包 A 依赖 lodash@4，包 B 依赖 lodash@3，解决冲突的时间比写代码还长&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2026 年的浏览器已经非常强大了。很多你以为"必须装包"的功能，原生 API 早就支持了。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="1. 卸载 lodash.cloneDeep → 用 structuredClone()"&gt;1. 卸载 &lt;code&gt;lodash.cloneDeep&lt;/code&gt; → 用 &lt;code&gt;structuredClone()&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;之前：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;lodash.cloneDeep   &lt;span class="c"&gt;# 5.3KB gzip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cloneDeep&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.cloneDeep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cloneDeep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;complexObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现在：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;complexObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完了。一行，零依赖。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;structuredClone&lt;/code&gt; 是浏览器原生的深拷贝方法，支持 &lt;code&gt;Map&lt;/code&gt;、&lt;code&gt;Set&lt;/code&gt;、&lt;code&gt;Date&lt;/code&gt;、&lt;code&gt;RegExp&lt;/code&gt;、&lt;code&gt;ArrayBuffer&lt;/code&gt;、循环引用——这些 &lt;code&gt;JSON.parse(JSON.stringify())&lt;/code&gt; 做不到的，它全能做。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;兼容性：&lt;/strong&gt; Chrome 98+、Firefox 94+、Safari 15.4+，2026 年你不需要担心兼容性。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;唯一限制：&lt;/strong&gt; 不支持拷贝 DOM 节点和函数。如果你的对象里有函数属性，这个方案不适用。但说实话，你的数据对象里不应该有函数。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;能省多少：&lt;/strong&gt; lodash.cloneDeep 单独引入约 5.3KB gzip，卸载后直接省掉。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="2. 卸载 uuid → 用 crypto.randomUUID()"&gt;2. 卸载 &lt;code&gt;uuid&lt;/code&gt; → 用 &lt;code&gt;crypto.randomUUID()&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;之前：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;uuid   &lt;span class="c"&gt;# 2.7KB gzip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;v4&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;uuidv4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uuid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 'f47ac10b-58cc-4372-a567-0e02b2c3d479'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现在：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 'f47ac10b-58cc-4372-a567-0e02b2c3d479'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出格式完全一样，都是标准的 UUID v4。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;兼容性：&lt;/strong&gt; Chrome 92+、Firefox 95+、Safari 15.4+，全线支持。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js 也支持：&lt;/strong&gt; Node 19+ 内置 &lt;code&gt;crypto.randomUUID()&lt;/code&gt;，前后端通吃。&lt;/p&gt;

&lt;p&gt;如果你只需要一个唯一 ID 而不需要严格的 UUID 格式，还有更轻量的方案：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simpleId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// '5x3g7k9m2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="3. 卸载 dayjs / moment → 用 Intl.DateTimeFormat + Temporal"&gt;3. 卸载 &lt;code&gt;dayjs&lt;/code&gt; / &lt;code&gt;moment&lt;/code&gt; → 用 &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; + &lt;code&gt;Temporal&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;这个是最重磅的。&lt;code&gt;moment.js&lt;/code&gt; 光 gzip 就 72KB，&lt;code&gt;dayjs&lt;/code&gt; 虽然轻（2KB），但大多数场景你连 2KB 都不需要。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;场景一：格式化日期显示&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 之前：dayjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YYYY年MM月DD日&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 现在：原生 Intl&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DateTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zh-CN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// '2026/06/21'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景二：相对时间（"3 小时前"）&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 之前：dayjs + relativeTime 插件&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;relativeTime&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs/plugin/relativeTime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relativeTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;fromNow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// 现在：原生 Intl.RelativeTimeFormat&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rtf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RelativeTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zh-CN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;rtf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hour&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// '3小时前'&lt;/span&gt;
&lt;span class="nx"&gt;rtf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// '昨天'&lt;/span&gt;
&lt;span class="nx"&gt;rtf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;month&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// '后2个月'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;场景三：日期计算&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 之前&lt;/span&gt;
&lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toDate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// 现在：Temporal API（2026 年主流浏览器已支持）&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plainDateISO&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextWeek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;days&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextWeek&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// '2026-06-28'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;什么时候还需要 dayjs：&lt;/strong&gt; 如果你要做大量复杂的时区转换、日历系统切换（农历之类），dayjs 的插件生态还是有价值的。但如果只是格式化显示和简单计算，原生足够了。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="4. 卸载 classnames / clsx → 用模板字符串"&gt;4. 卸载 &lt;code&gt;classnames&lt;/code&gt; / &lt;code&gt;clsx&lt;/code&gt; → 用模板字符串&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;之前：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;classnames   &lt;span class="c"&gt;# 0.6KB gzip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cn&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;classnames&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isPrimary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isDisabled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-large&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;large&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现在：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isPrimary&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isDisabled&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;large&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-large&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你觉得 &lt;code&gt;filter(Boolean).join(' ')&lt;/code&gt; 写起来啰嗦，封装一个两行的工具函数：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 用法完全一样&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isPrimary&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isDisabled&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn-disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2 行代码替代一个 npm 包。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;更好的方案：&lt;/strong&gt; 如果项目用了 Tailwind CSS，&lt;code&gt;tailwind-merge&lt;/code&gt; 比 classnames 更合适，因为它能处理 Tailwind 的类名冲突（比如同时写了 &lt;code&gt;p-2&lt;/code&gt; 和 &lt;code&gt;p-4&lt;/code&gt;）。这种场景下原生方案做不到。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="5. 卸载 node-fetch → 用原生 fetch"&gt;5. 卸载 &lt;code&gt;node-fetch&lt;/code&gt; → 用原生 &lt;code&gt;fetch&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;之前（Node.js 环境）：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;node-fetch   &lt;span class="c"&gt;# 8.4KB gzip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现在：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Node.js 18+ 内置了 &lt;code&gt;fetch&lt;/code&gt;，不需要再装 &lt;code&gt;node-fetch&lt;/code&gt;。2026 年还在装这个包，大概率是因为 &lt;code&gt;package.json&lt;/code&gt; 里一直没清理。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 如果你的 Node.js 版本低于 18，还是需要 &lt;code&gt;node-fetch&lt;/code&gt;。但 2026 年了，Node 18 已经是 EOL，你至少应该在 Node 20+ 上。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="6. 卸载 qs → 用 URLSearchParams"&gt;6. 卸载 &lt;code&gt;qs&lt;/code&gt; → 用 &lt;code&gt;URLSearchParams&lt;/code&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;之前：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;qs   &lt;span class="c"&gt;# 6.2KB gzip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;qs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 序列化&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;前端&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// 'page=1&amp;amp;size=20&amp;amp;keyword=%E5%89%8D%E7%AB%AF'&lt;/span&gt;

&lt;span class="c1"&gt;// 解析&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;page=1&amp;amp;size=20&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// { page: '1', size: '20' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现在：&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 序列化&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;前端&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// 'page=1&amp;amp;size=20&amp;amp;keyword=%E5%89%8D%E7%AB%AF'&lt;/span&gt;

&lt;span class="c1"&gt;// 解析&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;page=1&amp;amp;size=20&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// { page: '1', size: '20' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;唯一限制：&lt;/strong&gt; &lt;code&gt;URLSearchParams&lt;/code&gt; 不支持嵌套对象和数组的序列化。如果你的查询参数是 &lt;code&gt;{ filter: { status: ['active', 'pending'] } }&lt;/code&gt; 这种结构，还是需要 &lt;code&gt;qs&lt;/code&gt;。但大多数前端场景的查询参数都是扁平的 key-value。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="实操：怎么找出项目里可以卸载的包"&gt;实操：怎么找出项目里可以卸载的包&lt;/h2&gt;&lt;h3 id="第一步：找出未使用的依赖"&gt;第一步：找出未使用的依赖&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx depcheck
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它会列出 &lt;code&gt;package.json&lt;/code&gt; 里声明了但代码里从未 import 的包，直接删。&lt;/p&gt;
&lt;h3 id="第二步：分析打包体积"&gt;第二步：分析打包体积&lt;/h3&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx vite-bundle-visualizer
&lt;span class="c"&gt;# 或 webpack 项目&lt;/span&gt;
npx webpack-bundle-analyzer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看看哪些包占了大头。通常 &lt;code&gt;moment&lt;/code&gt;、&lt;code&gt;lodash&lt;/code&gt; 完整包是体积杀手。&lt;/p&gt;
&lt;h3 id="第三步：逐个替换"&gt;第三步：逐个替换&lt;/h3&gt;
&lt;p&gt;按本文方案替换后，跑一遍测试，确认功能正常再发版。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="总结对照表"&gt;总结对照表&lt;/h2&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;npm 包&lt;/th&gt;
&lt;th&gt;gzip 体积&lt;/th&gt;
&lt;th&gt;原生替代&lt;/th&gt;
&lt;th&gt;限制&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lodash.cloneDeep&lt;/td&gt;
&lt;td&gt;5.3KB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;structuredClone()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不支持函数和 DOM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uuid&lt;/td&gt;
&lt;td&gt;2.7KB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;crypto.randomUUID()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dayjs&lt;/td&gt;
&lt;td&gt;2KB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Intl&lt;/code&gt; + &lt;code&gt;Temporal&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;复杂时区场景不够用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;classnames&lt;/td&gt;
&lt;td&gt;0.6KB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;filter(Boolean).join(' ')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node-fetch&lt;/td&gt;
&lt;td&gt;8.4KB&lt;/td&gt;
&lt;td&gt;原生 &lt;code&gt;fetch&lt;/code&gt; (Node 18+)&lt;/td&gt;
&lt;td&gt;需要 Node 18+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qs&lt;/td&gt;
&lt;td&gt;6.2KB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLSearchParams&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;不支持嵌套对象&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;合计&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~25KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;25KB gzip 看起来不多，但在移动端弱网环境下，这就是 &lt;strong&gt;200-500ms 的加载时间差距&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;更重要的是：&lt;strong&gt;少一个依赖，就少一个供应链攻击的入口，少一个版本冲突的可能，少一个 &lt;code&gt;npm audit&lt;/code&gt; 的告警。&lt;/strong&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;如果你的项目里还有其他可以用原生 API 替代的包，评论区说一下，我补充进来。点赞收藏一下，下次 Code Review 看到同事装多余的包，直接把这篇甩给他。&lt;/em&gt;&lt;/p&gt;</description>
      <author>193577746</author>
      <pubDate>Sun, 21 Jun 2026 12:32:36 +0800</pubDate>
      <link>https://w2solo.com/topics/7566</link>
      <guid>https://w2solo.com/topics/7566</guid>
    </item>
    <item>
      <title>出海挣美元分享之：怎么购买域名？</title>
      <description>&lt;p&gt;上一篇文章给大家分享了《出海挣美元分享之：什么是域名？》，其中就给大家介绍了什么是域名、域名与 IP 地址的关系，以及为什么每个网站都需要一个域名。&lt;/p&gt;

&lt;p&gt;这里在简单说一下，域名就是网站的网址，例如：&lt;/p&gt;

&lt;p&gt;google.com&lt;/p&gt;

&lt;p&gt;freeai.run&lt;/p&gt;

&lt;p&gt;timestampcameras.com&lt;/p&gt;

&lt;p&gt;有了域名之后，用户才能方便地访问你的网站。&lt;/p&gt;

&lt;p&gt;那么问题来了：&lt;/p&gt;

&lt;p&gt;域名在哪里买？&lt;/p&gt;

&lt;p&gt;域名怎么注册？&lt;/p&gt;

&lt;p&gt;买域名需要准备什么？&lt;/p&gt;

&lt;p&gt;国内和国外购买有什么区别？&lt;/p&gt;

&lt;p&gt;今天就带大家一步一步完成自己的第一个域名购买。&lt;/p&gt;

&lt;p&gt;一、购买域名前需要准备什么？&lt;/p&gt;

&lt;p&gt;其实非常简单，只需要准备两样东西：&lt;/p&gt;

&lt;p&gt;1、一个邮箱&lt;/p&gt;

&lt;p&gt;用于注册账号、接收域名到期提醒以及找回密码。&lt;/p&gt;

&lt;p&gt;推荐使用：&lt;/p&gt;

&lt;p&gt;国外常用的就是：Gmail&lt;/p&gt;

&lt;p&gt;国内大家常用的就是：QQ 邮箱、网易邮箱&lt;/p&gt;

&lt;p&gt;2、一种支付方式&lt;/p&gt;

&lt;p&gt;国内平台一般支持：&lt;/p&gt;

&lt;p&gt;微信支付&lt;/p&gt;

&lt;p&gt;支付宝&lt;/p&gt;

&lt;p&gt;银行卡&lt;/p&gt;

&lt;p&gt;国外平台一般支持：&lt;/p&gt;

&lt;p&gt;Visa&lt;/p&gt;

&lt;p&gt;MasterCard&lt;/p&gt;

&lt;p&gt;PayPal&lt;/p&gt;

&lt;p&gt;二、中国大陆用户如何购买域名？&lt;/p&gt;

&lt;p&gt;如果你的网站主要面向国内用户，或者你不太熟悉英文操作界面，可以优先选择国内域名注册商。&lt;/p&gt;

&lt;p&gt;比较常见的平台有：&lt;/p&gt;

&lt;p&gt;阿里云&lt;/p&gt;

&lt;p&gt;腾讯云&lt;/p&gt;

&lt;p&gt;华为云&lt;/p&gt;

&lt;p&gt;这些平台的优点是：&lt;/p&gt;

&lt;p&gt;全中文界面&lt;/p&gt;

&lt;p&gt;支持支付宝和微信支付&lt;/p&gt;

&lt;p&gt;操作简单&lt;/p&gt;

&lt;p&gt;客服沟通方便&lt;/p&gt;

&lt;p&gt;购买流程&lt;/p&gt;

&lt;p&gt;第一步：注册账号&lt;/p&gt;

&lt;p&gt;使用手机号注册即可。&lt;/p&gt;

&lt;p&gt;第二步：搜索想要的域名&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;p&gt;mywebsite.com&lt;/p&gt;

&lt;p&gt;如果显示：&lt;/p&gt;

&lt;p&gt;可注册&lt;/p&gt;

&lt;p&gt;说明还没有人购买。&lt;/p&gt;

&lt;p&gt;如果显示：&lt;/p&gt;

&lt;p&gt;已注册&lt;/p&gt;

&lt;p&gt;说明已经被别人注册了，需要换一个名字或者换一个后缀。&lt;/p&gt;

&lt;p&gt;第三步：加入购物车并付款&lt;/p&gt;

&lt;p&gt;付款成功后，域名就属于你了。&lt;/p&gt;

&lt;p&gt;一般情况下：&lt;/p&gt;

&lt;p&gt;.com 域名每年几十元到一百元左右&lt;/p&gt;

&lt;p&gt;.cn 域名通常更便宜一些&lt;/p&gt;

&lt;p&gt;三、面向海外用户的网站如何购买域名？&lt;/p&gt;

&lt;p&gt;如果你的目标是：&lt;/p&gt;

&lt;p&gt;AI 工具站&lt;/p&gt;

&lt;p&gt;SaaS 产品&lt;/p&gt;

&lt;p&gt;Google SEO&lt;/p&gt;

&lt;p&gt;海外博客&lt;/p&gt;

&lt;p&gt;独立开发项目&lt;/p&gt;

&lt;p&gt;那么我更推荐使用国外域名注册商。&lt;/p&gt;

&lt;p&gt;原因很简单：&lt;/p&gt;

&lt;p&gt;国际认可度更高&lt;/p&gt;

&lt;p&gt;DNS 功能更完善&lt;/p&gt;

&lt;p&gt;与海外服务兼容更好&lt;/p&gt;

&lt;p&gt;后续迁移更加方便&lt;/p&gt;

&lt;p&gt;推荐平台一：Cloudflare Registrar&lt;/p&gt;

&lt;p&gt;Cloudflare Registrar&lt;/p&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;p&gt;基本按成本价出售域名&lt;/p&gt;

&lt;p&gt;没有各种隐藏加价&lt;/p&gt;

&lt;p&gt;DNS 服务非常优秀&lt;/p&gt;

&lt;p&gt;我目前大部分域名都放在 Cloudflare。&lt;/p&gt;

&lt;p&gt;推荐平台二：Namecheap&lt;/p&gt;

&lt;p&gt;Namecheap&lt;/p&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;p&gt;老牌域名注册商&lt;/p&gt;

&lt;p&gt;经常有优惠活动&lt;/p&gt;

&lt;p&gt;新手容易上手&lt;/p&gt;

&lt;p&gt;推荐平台三：Porkbun&lt;/p&gt;

&lt;p&gt;Porkbun&lt;/p&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;p&gt;价格便宜&lt;/p&gt;

&lt;p&gt;免费隐私保护&lt;/p&gt;

&lt;p&gt;近年来在独立开发者圈子里口碑很好&lt;/p&gt;

&lt;p&gt;国外平台注册流程&lt;/p&gt;

&lt;p&gt;基本与国内一致：&lt;/p&gt;

&lt;p&gt;注册账号&lt;/p&gt;

&lt;p&gt;搜索域名&lt;/p&gt;

&lt;p&gt;加入购物车&lt;/p&gt;

&lt;p&gt;完成支付&lt;/p&gt;

&lt;p&gt;域名注册成功&lt;/p&gt;

&lt;p&gt;整个过程通常只需要几分钟。&lt;/p&gt;

&lt;p&gt;四、域名后缀怎么选？&lt;/p&gt;

&lt;p&gt;很多新手第一次购买域名时都会纠结：&lt;/p&gt;

&lt;p&gt;.com .net .cn .xyz .top .ai&lt;/p&gt;

&lt;p&gt;到底选哪个？&lt;/p&gt;

&lt;p&gt;我的建议很简单：&lt;/p&gt;

&lt;p&gt;第一选择：.com&lt;/p&gt;

&lt;p&gt;如果能买到 .com，优先购买 .com。&lt;/p&gt;

&lt;p&gt;因为：&lt;/p&gt;

&lt;p&gt;用户最熟悉&lt;/p&gt;

&lt;p&gt;最容易记忆&lt;/p&gt;

&lt;p&gt;品牌认可度最高&lt;/p&gt;

&lt;p&gt;第二选择：.ai&lt;/p&gt;

&lt;p&gt;如果是 AI 产品项目，可以考虑：&lt;/p&gt;

&lt;p&gt;yourproduct.ai&lt;/p&gt;

&lt;p&gt;近几年很多 AI 创业公司都在使用。&lt;/p&gt;

&lt;p&gt;不过价格通常比 .com 贵不少。&lt;/p&gt;

&lt;p&gt;第三选择：其他后缀&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;p&gt;.net .io .xyz .run&lt;/p&gt;

&lt;p&gt;如果预算有限或者 .com 已经被注册，也完全可以使用。&lt;/p&gt;

&lt;p&gt;很多成功的网站最开始也并不是使用 .com。&lt;/p&gt;

&lt;p&gt;五、购买域名时的几个避坑建议&lt;/p&gt;

&lt;p&gt;1、优先选择短域名&lt;/p&gt;

&lt;p&gt;例如：&lt;/p&gt;

&lt;p&gt;freeai.run&lt;/p&gt;

&lt;p&gt;明显比：&lt;/p&gt;

&lt;p&gt;bestfreeaitoolswebsite.com&lt;/p&gt;

&lt;p&gt;更容易传播。&lt;/p&gt;

&lt;p&gt;2、避免数字和横线&lt;/p&gt;

&lt;p&gt;不推荐：&lt;/p&gt;

&lt;p&gt;my-ai-tool-123.com&lt;/p&gt;

&lt;p&gt;推荐：&lt;/p&gt;

&lt;p&gt;myaitool.com&lt;/p&gt;

&lt;p&gt;3、不要一次购买太多年&lt;/p&gt;

&lt;p&gt;很多新手刚开始创业就直接购买 5 年、10 年。&lt;/p&gt;

&lt;p&gt;实际上完全没有必要。&lt;/p&gt;

&lt;p&gt;建议：&lt;/p&gt;

&lt;p&gt;先购买 1 年。&lt;/p&gt;

&lt;p&gt;等项目跑起来之后再续费。&lt;/p&gt;

&lt;p&gt;4、看到喜欢的域名尽快注册&lt;/p&gt;

&lt;p&gt;域名属于全球唯一资源。&lt;/p&gt;

&lt;p&gt;你今天看到没人注册，不代表明天还在。&lt;/p&gt;

&lt;p&gt;很多人创业最大的遗憾之一，就是：&lt;/p&gt;

&lt;p&gt;当初觉得不着急，过几天再买。&lt;/p&gt;

&lt;p&gt;结果回来发现已经被别人注册了。&lt;/p&gt;

&lt;p&gt;六、我的建议&lt;/p&gt;

&lt;p&gt;如果你只是想练习建站：&lt;/p&gt;

&lt;p&gt;选择国内平台注册即可。&lt;/p&gt;

&lt;p&gt;如果你准备认真做出海项目：&lt;/p&gt;

&lt;p&gt;我个人更推荐：&lt;/p&gt;

&lt;p&gt;Cloudflare Registrar&lt;/p&gt;

&lt;p&gt;一个几十元的域名，就足够让你开启自己的第一个网站项目。&lt;/p&gt;

&lt;p&gt;不要等所有东西都准备好再开始。&lt;/p&gt;

&lt;p&gt;很多时候，一个域名就是一个项目的开始。&lt;/p&gt;</description>
      <author>my126sw</author>
      <pubDate>Sat, 20 Jun 2026 23:29:52 +0800</pubDate>
      <link>https://w2solo.com/topics/7565</link>
      <guid>https://w2solo.com/topics/7565</guid>
    </item>
    <item>
      <title>我做了个局部重绘 AI 工具：涂抹一下，想改哪改哪</title>
      <description>&lt;p&gt;把美工省掉。&lt;/p&gt;

&lt;p&gt;3 毛钱，修一张图。&lt;/p&gt;

&lt;p&gt;前阵子有个澄海玩具厂的客户，他们想生成玩具车的设计图，整张图风格都挺像样，问题就出在细节上——后视镜跟设计稿不一样。（对方要求保密，无法上图）&lt;/p&gt;

&lt;p&gt;要是整张图重来吧，费时间不说，明明看好的设计稿，重新生成就全部都变样了。&lt;/p&gt;

&lt;p&gt;他说：要是有个"局部重绘"就好了，把后视镜那块擦一擦，描述一下想要的形状，AI 顺手给改掉，效率能高不少。&lt;/p&gt;

&lt;p&gt;于是我就把这个工具做出来了。底层用的是目前顶级的 GPT-4 的 image2 模型，真实感与一致性都有保障。&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;工具超简单，整个页面就是一张画布，上传、生成、修改都在这上面进行，72 小时自动删除图片，保护版权、保护隐私。&lt;/p&gt;

&lt;p&gt;核心亮点：局部重绘&lt;/p&gt;

&lt;p&gt;用法也很简单：上传图片，鼠标选区涂抹，输入文字描述，AI 就会把那块区域智能替换掉。关键是，它还能保持原图的光影和风格，不至于改完后跟整张图不是一个画风。&lt;/p&gt;

&lt;p&gt;来个示例，先上传一张图片，如下图：&lt;/p&gt;

&lt;p&gt;图片
点击底部工具栏就可以上传，也可以生成图片。&lt;/p&gt;

&lt;p&gt;点击图片后，上方就会出现工具栏：&lt;/p&gt;

&lt;p&gt;图片
然后第 2 个就是局部重绘工具，可以用橡皮擦也可以用矩型把指定位置圈起来：&lt;/p&gt;

&lt;p&gt;图片
然后点右边的勾勾，就会出现提示示框：&lt;/p&gt;

&lt;p&gt;图片
告诉它：&lt;/p&gt;

&lt;p&gt;换成哆啦 A 梦
就这么简单。&lt;/p&gt;

&lt;p&gt;稍等一会，图就修改好了：&lt;/p&gt;

&lt;p&gt;图片
而且原图还给你保留着。&lt;/p&gt;

&lt;p&gt;再换一下墙壁上的照片：&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;这次换成大雄的照片吧：&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;这次只是用文字描述，我们来试个新的：局部图生图&lt;/p&gt;

&lt;p&gt;局部图生图&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;还是用刚才这张图，还是一样选择局部重绘工具，这次我们改下她的手机，把她的手机换成我们指定的手办，上传一张我们的图：&lt;/p&gt;

&lt;p&gt;图片
这时你会看到有两种模式选择：&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;参考重绘：当你想把图中物体作为参考物融入主图时使用，其结果可能与原图有差别，适合把卡通人物变成娃娃之类的场景。&lt;/p&gt;

&lt;p&gt;高保真迁移：当你想把图中物体 100% 融入主图时使用，适合把产品广告或人物合照之类的场景。&lt;/p&gt;

&lt;p&gt;现在这个手办，得用高保真模式，看看最后生成啥样：&lt;/p&gt;

&lt;p&gt;图片
那么什么情况下使用 “参考重绘” 呢？&lt;/p&gt;

&lt;p&gt;比如，你想把下面这只猫兄卡通变成娃娃：&lt;/p&gt;

&lt;p&gt;图片
这是一张手绘的卡通猫，想变成娃娃自然不能再用高保真，只能让它重绘，重绘后的图如下：&lt;/p&gt;

&lt;p&gt;图片&lt;/p&gt;

&lt;p&gt;核心亮点：支持多并发&lt;/p&gt;

&lt;p&gt;你可以同时生成、修改多张图，同时并行，互不干扰。&lt;/p&gt;

&lt;p&gt;除了局部重绘，还有其它的玩法：&lt;/p&gt;

&lt;p&gt;• 图片生成（文字生成图片）：一句话出图，适合快速出创意或找灵感。
 • 背景替换/去除：商品拍在杂乱场景也没事，一键换成白底或品牌背景，电商卖家会很方便。
 • 一键去水印：去掉角落的 logo 或水印，快速复用素材。
 • 智能洗稿（改写图片风格）：把一张图改成不同的风格，作为创作起点也不赖。
 • 修改尺寸：按平台规格快速裁剪和调整比例。
 • 滤镜美白：一些基础的调色和优化，省得再打开其他软件。
 • 裁剪翻转：常见编辑操作一应俱全。&lt;/p&gt;

&lt;p&gt;…………等等，自己去闹吧。&lt;/p&gt;

&lt;p&gt;图片
像美白的、去水印的，这些就不一一描述了，自己探索更多的可能性吧。&lt;/p&gt;

&lt;p&gt;小红书玩家还可以进行 X 稿：&lt;/p&gt;

&lt;p&gt;图片
不过我们小红书 X 稿也有专门的工具，这个只是配套而已。&lt;/p&gt;

&lt;p&gt;图片
让女生抱着哆啦 A 梦。&lt;/p&gt;

&lt;p&gt;图片
换背景。&lt;/p&gt;

&lt;p&gt;总的来说，画布操作也挺顺手：鼠标滚轮缩放、自由拖拽，细节看清楚后再涂抹，定位更准。&lt;/p&gt;

&lt;p&gt;使用方式：用完即走，隐私无忧&lt;/p&gt;

&lt;p&gt;使用方式上，主打一个"拖入即用"。图片直接拖进页面或点上传就开工，所有处理在云端完成，不用安装软件。我做了个"用完即走"的设计理念——图片仅保留 72 小时，之后自动清理，保护隐私。&lt;/p&gt;

&lt;p&gt;适用场景我简单列几个：&lt;/p&gt;

&lt;p&gt;• 电商卖家：快速修图、换背景、去水印，提升出图效率。
 • 设计师：找灵感、快速尝试不同方案、局部调整。
 • 普通用户：趣味改图、日常美化，门槛很低。&lt;/p&gt;

&lt;p&gt;修图价格约 0.3 元，其它的都是约 0.12 元，新用户可试用&lt;/p&gt;

&lt;p&gt;如果你也有这种痛点——局部要改、风格要一致、又不想整图重来，试试看。&lt;/p&gt;

&lt;p&gt;👉 复制以下网址体验：
&lt;a href="https://www.vicoco.cn/p/239" rel="nofollow" target="_blank"&gt;https://www.vicoco.cn/p/239&lt;/a&gt;&lt;/p&gt;</description>
      <author>zhengqiagood</author>
      <pubDate>Sat, 20 Jun 2026 21:06:02 +0800</pubDate>
      <link>https://w2solo.com/topics/7564</link>
      <guid>https://w2solo.com/topics/7564</guid>
    </item>
    <item>
      <title>同事每天催我 Code Review，我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;先说结论：用 GitHub Actions + Claude API 实现全自动 PR review，配置一次，以后每个 PR 推上去，AI 10 秒内给出详细评审意见，覆盖代码质量、潜在 bug、安全风险三个维度。这篇文章把完整配置都给你，拿走直接用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="背景：CR 慢是前端团队的通病"&gt;背景：CR 慢是前端团队的通病&lt;/h2&gt;
&lt;p&gt;我们团队有个不成文的规定：PR 提上去，要在 1 个工作日内完成 review。&lt;/p&gt;

&lt;p&gt;听起来很合理，但实际情况是这样的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;早上刚到公司，打开 GitHub，待 review 的 PR 已经排了 6 个&lt;/li&gt;
&lt;li&gt;每个 PR 少则 200 行，多则 800 行&lt;/li&gt;
&lt;li&gt;还有自己的需求要写&lt;/li&gt;
&lt;li&gt;还有各种会&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;于是每天我的 review 质量是这样的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;上午的 PR：认真看，写评论&lt;/li&gt;
&lt;li&gt;下午的 PR：大概扫一下&lt;/li&gt;
&lt;li&gt;晚上的 PR：approve，👍&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;然后有一天，同事 A 在群里 @ 了我：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"我那个 PR 提了两天了，能帮我看一下吗？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我翻出来一看——800 行，涉及三个模块。&lt;/p&gt;

&lt;p&gt;我当时脑子里只有一个念头：&lt;strong&gt;要是有人能替我先过一遍就好了。&lt;/strong&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="解决思路：AI 做初审，人做终审"&gt;解决思路：AI 做初审，人做终审&lt;/h2&gt;
&lt;p&gt;理想的工作流是这样的：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;开发者 push PR
    ↓
AI 自动分析 diff
    ↓
AI 在 PR 里发评论（10秒内）
    ↓
人工看 AI 的意见 + 做最终判断
    ↓
approve 或 request changes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好处显而易见：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI 处理掉 80% 的机械检查（代码风格、潜在空指针、未处理的 Promise reject）&lt;/li&gt;
&lt;li&gt;人只需要关注 AI 标注出的问题点 + 业务逻辑&lt;/li&gt;
&lt;li&gt;平均 review 时间从 30 分钟压缩到 8 分钟&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;坏处也要说清楚：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI 不理解你的业务逻辑，会漏掉业务层面的 bug&lt;/li&gt;
&lt;li&gt;AI 有时候会给"误报"，需要人来过滤&lt;/li&gt;
&lt;li&gt;不能完全替代人工 review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;所以定位是：AI 初审 + 人工终审，不是 AI 替代人工。&lt;/strong&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="实现方案：GitHub Actions + Claude API"&gt;实现方案：GitHub Actions + Claude API&lt;/h2&gt;&lt;h3 id="第一步：申请 Claude API Key"&gt;第一步：申请 Claude API Key&lt;/h3&gt;
&lt;p&gt;去 &lt;a href="https://console.anthropic.com" rel="nofollow" target="_blank" title=""&gt;console.anthropic.com&lt;/a&gt; 注册，免费额度足够测试用。&lt;/p&gt;

&lt;p&gt;把 Key 存到 GitHub 仓库的 Secrets：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;仓库 → Settings → Secrets and variables → Actions&lt;/li&gt;
&lt;li&gt;新建 &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="第二步：创建 workflow 文件"&gt;第二步：创建 workflow 文件&lt;/h3&gt;
&lt;p&gt;在你的仓库里创建 &lt;code&gt;.github/workflows/ai-review.yml&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AI Code Review&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;synchronize&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai-review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install @anthropic-ai/sdk @octokit/rest&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run AI Review&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ANTHROPIC_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;PR_NUMBER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.number }}&lt;/span&gt;
          &lt;span class="na"&gt;REPO_OWNER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository_owner }}&lt;/span&gt;
          &lt;span class="na"&gt;REPO_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.repository.name }}&lt;/span&gt;
          &lt;span class="na"&gt;BASE_SHA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.base.sha }}&lt;/span&gt;
          &lt;span class="na"&gt;HEAD_SHA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.event.pull_request.head.sha }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node .github/scripts/ai-review.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="第三步：创建核心脚本"&gt;第三步：创建核心脚本&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;.github/scripts/ai-review.js&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Anthropic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@anthropic-ai/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Octokit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@octokit/rest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANTHROPIC_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;octokit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Octokit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_TOKEN&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getDiff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`git diff &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BASE_SHA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;..&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HEAD_SHA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; -- '*.js' '*.ts' '*.tsx' '*.jsx' '*.vue'`&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 超过 8000 字符截断，避免超出 token 限制&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;... [diff truncated]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reviewWithClaude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`你是一个资深前端代码审查工程师，请对以下 PR diff 进行代码审查。

**审查重点：**
1. 潜在 Bug（空值引用、异步竞态、边界条件未处理）
2. 安全风险（XSS、敏感信息泄露、输入未校验）
3. 性能问题（不必要的重渲染、大对象序列化、内存泄漏）
4. 可维护性（函数过长、命名不清晰、重复代码）

**输出格式：**
用 Markdown 输出，包含以下几个部分：
- 🔴 严重问题（必须修复）
- 🟡 建议优化（可以改进）
- 🟢 代码亮点（做得好的地方）
- 📊 总体评分（1-10分，附简短理由）

如果没有问题，直接说"代码质量良好，无明显问题"。
用中文回复，简洁直接，不废话。

**PR Diff：**
&lt;/span&gt;&lt;span class="se"&gt;\`\`\`&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;span class="se"&gt;\`\`\`&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;postComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;REPO_OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;REPO_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PR_NUMBER&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;octokit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createComment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REPO_OWNER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;REPO_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;issue_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PR_NUMBER&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`## 🤖 AI Code Review\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n---\n*由 Claude AI 自动生成，仅供参考，请以人工审查为准*`&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Getting diff...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getDiff&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No JS/TS changes detected, skipping review.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sending to Claude for review...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;review&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reviewWithClaude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Posting comment...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;postComment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="第四步：推一个 PR 测试"&gt;第四步：推一个 PR 测试&lt;/h3&gt;
&lt;p&gt;随便改一个文件，提个 PR，大约 15-20 秒后，你会看到 AI 自动在 PR 下面发了一条评论。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="真实效果展示"&gt;真实效果展示&lt;/h2&gt;
&lt;p&gt;我们团队用了两周后，AI 的评论长这样：&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;🔴 严重问题（必须修复）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;第 47 行 &lt;code&gt;userData.profile.avatar&lt;/code&gt;：未做空值检查，当 &lt;code&gt;profile&lt;/code&gt; 为 &lt;code&gt;null&lt;/code&gt; 时会抛出 TypeError。建议改为 &lt;code&gt;userData.profile?.avatar&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;第 83 行：&lt;code&gt;useEffect&lt;/code&gt; 的依赖数组缺少 &lt;code&gt;userId&lt;/code&gt;，可能导致使用过期的 &lt;code&gt;userId&lt;/code&gt; 发请求，产生数据不一致。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟡 建议优化&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;第 92-115 行：&lt;code&gt;formatUserData&lt;/code&gt; 函数做了 3 件不同的事（格式化、过滤、排序），建议拆成 3 个函数，便于测试和复用。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🟢 代码亮点&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;错误处理写得很规范，catch 块没有直接吞掉错误，而是通过 &lt;code&gt;errorReporter.capture&lt;/code&gt; 上报，赞。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📊 总体评分：7/10&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;整体结构清晰，主要问题集中在空值防护上，修复后可以直接合并。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;看到这个，review 的人只需要：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;确认 AI 找出的问题是否真实存在（通常是）&lt;/li&gt;
&lt;li&gt;判断业务逻辑是否正确（这才是人工的价值所在）&lt;/li&gt;
&lt;li&gt;approve 或 request changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;平均节省 70% 的初审时间。&lt;/strong&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="进阶：按文件类型差异化 review"&gt;进阶：按文件类型差异化 review&lt;/h2&gt;
&lt;p&gt;不是所有文件都需要一样的审查策略。可以在 prompt 里加文件类型判断：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;buildPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileTypes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;focusMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;重点关注：参数校验、错误处理、幂等性、接口安全&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;重点关注：props 类型、副作用清理、渲染性能、无障碍属性&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;util&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;重点关注：边界条件、纯函数、测试覆盖&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;重点关注：状态更新的不可变性、selector 性能、副作用隔离&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;focus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;focusMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`你是资深前端工程师，请审查以下代码：

&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`**本次特别关注：**\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id="踩坑记录"&gt;踩坑记录&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;坑 1：diff 太大超出 token 限制&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;解决方案：只 review 修改行数 &amp;lt; 500 的文件，超过的给一个提示"文件变更过大，请人工重点审查"。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;坑 2：AI 给出"误报"，降低信任度&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;解决方案：在 prompt 里加一句 "如果你不确定是否是问题，不要写出来"。比 "尽可能找出所有问题" 效果好很多。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="现状"&gt;现状&lt;/h2&gt;
&lt;p&gt;现在我们团队的 CR 流程是这样的：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;开发提 PR&lt;/li&gt;
&lt;li&gt;AI 10 秒内完成初审，发评论&lt;/li&gt;
&lt;li&gt;reviewer 看 AI 评论 + diff，平均 8 分钟完成终审&lt;/li&gt;
&lt;li&gt;merge&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;那个之前每天催我 review 的同事 A，现在每次 AI 评论发出来，他比我更认真地研究 AI 说了什么。&lt;/p&gt;

&lt;p&gt;上周他跟我说：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"AI 给我找出了一个我自己写代码时没注意的空指针，这玩意儿比我认真。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr&gt;
&lt;h2 id="完整代码"&gt;完整代码&lt;/h2&gt;
&lt;p&gt;完整的配置文件我放在下面，可以直接 copy 到你的项目里：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.github/workflows/ai-review.yml&lt;/code&gt;&lt;/strong&gt;（上文已贴完整版）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;.github/scripts/ai-review.js&lt;/code&gt;&lt;/strong&gt;（上文已贴完整版）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;需要的环境变量：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;：从 Anthropic 控制台获取&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GITHUB_TOKEN&lt;/code&gt;：GitHub Actions 自带，不用手动配置&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;配置完之后，去提一个测试 PR，看着 AI 自动开始 review，还挺有成就感的。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="写在最后"&gt;写在最后&lt;/h2&gt;
&lt;p&gt;这套方案不是为了让人偷懒的——而是让&lt;strong&gt;人的精力花在刀刃上&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;机械的检查（空值、类型、格式）让 AI 做，业务逻辑、架构判断、团队规范这些需要上下文的判断，留给人。&lt;/p&gt;

&lt;p&gt;如果你的团队也有 CR 堆积的问题，可以直接拿这套配置用。有什么问题评论区说，我看到了会回。&lt;/p&gt;

&lt;p&gt;点赞收藏一下，下次出团队提效工具合集时方便你找回来。&lt;/p&gt;</description>
      <author>193577746</author>
      <pubDate>Sat, 20 Jun 2026 12:31:23 +0800</pubDate>
      <link>https://w2solo.com/topics/7563</link>
      <guid>https://w2solo.com/topics/7563</guid>
    </item>
    <item>
      <title>为了上 telegram 对接海外客户，我被一个登录界面卡了三天，还好最后解决了</title>
      <description>&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/freemanbrent40/079d019e-080c-4096-9fc6-06a11c99a1aa.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;上个月接了一个海外客户的单子，对方要求用某通讯工具沟通。我注册的时候，+86 手机号，验证码等了三天都没来，中间还交了两次 smsfee，钱花了，码还是没收到。&lt;/p&gt;

&lt;p&gt;为什么必须上这个工具？&lt;/p&gt;

&lt;p&gt;不是我想用，是客户在用。独立开发者接海外单，沟通工具绕不开。客户说"我们团队在这个上面"，你就得上去。&lt;/p&gt;

&lt;p&gt;一个做跨境的朋友说，他之前也遇到过，最后换了个客户端解决。基于官方开源版本编译，核心协议兼容，但登录通道不同。&lt;/p&gt;

&lt;p&gt;试了一下，直接登录成功，没有验证码，没有 smsfee，两分钟搞定。&lt;/p&gt;

&lt;p&gt;用了一周的实际体验&lt;/p&gt;

&lt;p&gt;登录方式绕过短信验证，直接设备授权。中文环境完整，连接稳定性不错，电信、联通、移动都试过，后台保活一周，消息推送没漏过。跟客户时差 12 小时，半夜来的消息，早上醒来能看到。&lt;/p&gt;

&lt;p&gt;功能上和官方版一样，聊天、频道、搜索、多账号切换，没发现缩水。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/freemanbrent40/b5f19579-35a5-4d0e-a005-99d5c953486e.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;官方路径：smsfee 交了几十块 + 三天时间 + 可能丢掉的客户&lt;/p&gt;

&lt;p&gt;这个路径：两分钟 + 客户保住&lt;/p&gt;

&lt;p&gt;给独立开发者的建议&lt;/p&gt;

&lt;p&gt;接海外单前，先确认沟通工具能不能正常登录&lt;/p&gt;

&lt;p&gt;遇到验证码问题，别死磕官方客户端，尝试替代方案&lt;/p&gt;

&lt;p&gt;时间比钱贵，三天够写完一个功能模块&lt;/p&gt;

&lt;p&gt;你们有没有因为某个工具的注册流程，差点丢掉客户或者机会？最后是怎么解决的？评论区聊聊，我帮你们避雷。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/freemanbrent40/2b7cd94d-adff-4ddc-9e4b-724d209f2577.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>freemanbrent40</author>
      <pubDate>Sat, 20 Jun 2026 11:43:03 +0800</pubDate>
      <link>https://w2solo.com/topics/7562</link>
      <guid>https://w2solo.com/topics/7562</guid>
    </item>
    <item>
      <title>SerpBase 运营两个月后，终于把 Google 搜索接进 Agent 这件事做顺了</title>
      <description>&lt;p&gt;两个月前，我在 W2solo 发过两篇文章：&lt;/p&gt;

&lt;p&gt;正式运营 6 天，拿到第一笔 $200：SerpBase 从立项到上线的一个月 (&lt;a href="https://w2solo.com/topics/7275" rel="nofollow" target="_blank"&gt;https://w2solo.com/topics/7275&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;做了个新站 SerpBase：想把 Google 搜索结果 API 做得便宜一点、稳一点 (&lt;a href="https://w2solo.com/topics/7254" rel="nofollow" target="_blank"&gt;https://w2solo.com/topics/7254&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;当时项目正式运营第 6 天，拿到了第一笔 $200。两个月过去，产品还在继续迭代，最近花了不少时间解决一件很实际的事：让 AI Agent 更方便地用 Google 搜索。&lt;/p&gt;

&lt;p&gt;很多 Agent 场景不需要自己搭浏览器自动化。折腾 Playwright、代理、验证码和页面结构，最后想要的往往只是标题、链接、摘要这些干净结果。&lt;/p&gt;

&lt;p&gt;所以做了两个开源集成：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/serpbase-dev/serpbase-skill" rel="nofollow" target="_blank"&gt;https://github.com/serpbase-dev/serpbase-skill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;给支持 Skill 的 AI 编程助手和 Agent 用，装好后可以直接搜索并拿结构化结果。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/serpbase-dev/serpbase-mcp" rel="nofollow" target="_blank"&gt;https://github.com/serpbase-dev/serpbase-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;给支持 MCP 的客户端用，把 Google 搜索作为 Agent 的一个工具接进去。&lt;/p&gt;

&lt;p&gt;我现在越来越觉得，Agent 的搜索能力不该是一个大工程。能稳定拿到实时信息，返回格式干净，价格别把小项目劝退，基本就够了。&lt;/p&gt;

&lt;p&gt;也想问问大家：你们给 Agent 接实时搜索时，现在主要用什么方案？自己爬、SerpAPI/Serper，还是别的？&lt;/p&gt;

&lt;p&gt;我们的官网是 (&lt;a href="https://serpbase.dev" rel="nofollow" target="_blank"&gt;https://serpbase.dev&lt;/a&gt;)，欢迎各位大佬前来指导&lt;/p&gt;</description>
      <author>serpbase</author>
      <pubDate>Sat, 20 Jun 2026 11:40:22 +0800</pubDate>
      <link>https://w2solo.com/topics/7561</link>
      <guid>https://w2solo.com/topics/7561</guid>
    </item>
    <item>
      <title>分享最近 AI 做的儿童启蒙产品：拍照学拼音（附兑换码）</title>
      <description>&lt;h2 id="📸 拍照学拼音｜从孩子身边开始的启蒙学习工具"&gt;📸 拍照学拼音｜从孩子身边开始的启蒙学习工具&lt;/h2&gt;
&lt;p&gt;最近儿子开始进入启蒙阶段。&lt;/p&gt;

&lt;p&gt;老婆陆续买了不少识字卡、拼音卡和启蒙玩具，每天都会陪着孩子一起认字、学拼音。&lt;/p&gt;

&lt;p&gt;陪孩子学习的过程中，我发现一个有意思的现象：&lt;/p&gt;

&lt;p&gt;孩子对卡片上的字兴趣其实有限，但对身边真实的事物特别感兴趣。&lt;/p&gt;

&lt;p&gt;看到小猫会问是什么，看到汽车会问怎么读，看到水果、玩具、绘本都会不停追问。&lt;/p&gt;

&lt;p&gt;作为一名产品开发者，我就在想：&lt;/p&gt;

&lt;p&gt;👉 能不能做一个让孩子从身边事物开始学习拼音和汉字的工具？&lt;/p&gt;

&lt;p&gt;于是利用 AI 开发了这款小程序——&lt;strong&gt;拍照学拼音&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=""&gt;&lt;img src="https://pinyin.qibanai.cn/uploads/cards/vi/fengmian.webp" width="600px" height="800px" alt="封面"&gt;&lt;/h2&gt;&lt;h2 id="🏠 首页展示"&gt;🏠 首页展示&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://pinyin.qibanhub.com/" title="" alt="Loading Page"&gt;&lt;/p&gt;

&lt;p&gt;👉 拍照学拼音 Loading Page 页面&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="🌱 为什么做它"&gt;🌱 为什么做它&lt;/h2&gt;
&lt;p&gt;相比传统的识字卡、拼音卡，我更希望孩子能够：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;看到什么，认识什么；拍到什么，学习什么。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;把现实世界和拼音、汉字自然关联起来。&lt;/p&gt;

&lt;p&gt;学习不一定非要坐在桌前。&lt;/p&gt;

&lt;p&gt;客厅里的玩具、路边的花草、公园里的小动物，都可以成为孩子的启蒙教材。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://pinyin.qibanai.cn/uploads/cards/vi/01.webp" width="600px" height="600px" alt="封面"&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="📷 核心功能：拍一拍，就会读"&gt;📷 核心功能：拍一拍，就会读&lt;/h2&gt;
&lt;p&gt;（这个功能目前还在打磨中，体验时可以多一点耐心）&lt;/p&gt;

&lt;p&gt;孩子拍一张照片后：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI 识别图片内容&lt;/li&gt;
&lt;li&gt;自动生成汉字&lt;/li&gt;
&lt;li&gt;自动生成拼音&lt;/li&gt;
&lt;li&gt;支持语音朗读&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="示例："&gt;示例：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;🍎 苹果 → 苹果（píng guǒ）&lt;/li&gt;
&lt;li&gt;🐱 小猫 → 猫（māo）&lt;/li&gt;
&lt;li&gt;🚗 汽车 → 汽车（qì chē）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 让孩子从熟悉的事物开始认识汉字和拼音&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="🧩 产品截图"&gt;🧩 产品截图&lt;/h2&gt;&lt;h3 id="🏠 首页"&gt;🏠 首页&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://pinyin.qibanai.cn/uploads/cards/vi/home.jpg" width="600px" height="800px" alt="首页截图"&gt;
)&lt;/p&gt;

&lt;hr&gt;
&lt;h3 id="🎮 启蒙小游戏专区"&gt;🎮 启蒙小游戏专区&lt;/h3&gt;
&lt;p&gt;目前已包含：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;猜数字&lt;/li&gt;
&lt;li&gt;井字棋&lt;/li&gt;
&lt;li&gt;识字测算&lt;/li&gt;
&lt;li&gt;识字大闯关（持续开发中）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 用亲子互动的方式提升孩子兴趣&lt;/p&gt;

&lt;p&gt;&lt;img src="https://pinyin.qibanai.cn/uploads/cards/vi/01.jpg" width="600px" height="800px" alt="小游戏截图"&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="🚀 当前进展"&gt;🚀 当前进展&lt;/h2&gt;
&lt;p&gt;产品上线一周多，目前已有 &lt;strong&gt;1000+ 用户体验&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;仍然处于早期版本，正在持续优化：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;拍照识别速度较慢（优化中）&lt;/li&gt;
&lt;li&gt;拼音学习内容分阶段建设中&lt;/li&gt;
&lt;li&gt;创意工具模块开发中&lt;/li&gt;
&lt;li&gt;启蒙小游戏逐步增加&lt;/li&gt;
&lt;li&gt;更多儿童启蒙内容规划中&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果遇到识别不准、响应较慢等问题，也欢迎反馈 🙏&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="🌈 未来想做什么"&gt;🌈 未来想做什么&lt;/h2&gt;
&lt;p&gt;除了 “拍照学拼音”，更希望它成为一个：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👨‍👩‍👧 亲子启蒙互动工具&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;未来方向包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;看图学拼音&lt;/li&gt;
&lt;li&gt;看图学汉字&lt;/li&gt;
&lt;li&gt;中英文启蒙&lt;/li&gt;
&lt;li&gt;儿童认知训练&lt;/li&gt;
&lt;li&gt;亲子共读工具&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 让家长陪伴孩子成长的过程更轻松、更有趣&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;img src="https://pinyin.qibanai.cn/uploads/cards/nav/qrcode.jpg" width="600px" height="600px" alt="封面"&gt;&lt;/p&gt;
&lt;h2 id="🎁 专属兑换码（限量）"&gt;🎁 专属兑换码（限量）&lt;/h2&gt;
&lt;p&gt;使用方式：
进入「个人中心 / 积分兑换」即可使用&lt;br&gt;
（每人每天限用一个）&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DY832QK9
DY4GSEJA
DYNJBDPM
DYLGXABK
DY2TD75Y
DYYEBVKL
DYDGYBFG

👉 用完可以在评论区说一声，方便其他朋友

![封面](https://pinyin.qibanai.cn/uploads/cards/nav/qrcode.jpg =600x800)

---

## 🤝 想听听大家的建议

如果你家里有学龄前儿童，或者做过教育产品，想请教几个问题：

- 这种“拍照学拼音”的方式是否有价值？
- 孩子是否愿意持续使用？
- 还有哪些启蒙功能值得加入？

---

第一次做儿童教育方向的产品，还有很多不足。

但希望可以持续打磨，做出一个真正帮助家长和孩子的工具。

欢迎体验、拍砖、提建议，也欢迎交流 👇

微信：Mianxinai

---

❤️ 感谢大家
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>onling</author>
      <pubDate>Sat, 20 Jun 2026 10:15:51 +0800</pubDate>
      <link>https://w2solo.com/topics/7560</link>
      <guid>https://w2solo.com/topics/7560</guid>
    </item>
  </channel>
</rss>
