<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>wuh.site - 博客订阅</title>
        <link>https://wuh.site</link>
        <description>吴尒红的个人博客内容</description>
        <lastBuildDate>Sat, 18 Jul 2026 06:53:34 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-cn</language>
        <copyright>© 2024 wuh.site</copyright>
        <item>
            <title><![CDATA[再读《坐忘歌》]]></title>
            <link>https://wuh.site/post/165</link>
            <guid>165</guid>
            <pubDate>Sun, 05 Jul 2026 12:32:22 GMT</pubDate>
            <description><![CDATA[## 再读《坐忘歌》

![image-20260705202606322](https://cdn.wuh.site/2026-07/1783254259449_download.png)

> 常默元气不伤，少思慧烛内光。
>
> 不怒百神和畅，不恼心地清凉。
>
> 不求无谄无曲，不执可圆可方。
>
> 不贪便是富贵，不苟何惧公堂。
>
> 味绝灵泉自降，气定真息自长。
>
> 触则形毙神游]]></description>
            <content:encoded><![CDATA[## 再读《坐忘歌》

![image-20260705202606322](https://cdn.wuh.site/2026-07/1783254259449_download.png)

> 常默元气不伤，少思慧烛内光。
>
> 不怒百神和畅，不恼心地清凉。
>
> 不求无谄无曲，不执可圆可方。
>
> 不贪便是富贵，不苟何惧公堂。
>
> 味绝灵泉自降，气定真息自长。
>
> 触则形毙神游，想则梦索尸僵。
>
> 气漏形归后土，念漏神归死乡。
>
> 心死方得神活，魄灭然后魂昌。
>
> 转物难穷妙理，应化不离真常。 
>
> 至精潜于恍惚，大象混于渺茫。
>
> 造化若知规矩，鬼神莫测行藏。
>
> 节饮节食少寐，是谓真人坐忘。
>
> -- 司马承祯

我们公司的一个同事，见面就给我吐槽压力很大，中年危机。我也不善言辞，不知道要怎么安慰他才好，只能跟他插诨打科，消解一下他的苦闷。

今天本来是给自己安排的游戏日，本想称着台风天在家里打一天游戏。不知道是不是他影响了我一下，早上7点醒过来，随口念了两句**不怒百神和畅，不恼心地清凉**。

可能是太长时间没有压力了，前后几句全给忘记了，所以只好临时改变了一下计划，今天还是读书日吧。

这首歌是一首道教的养气歌，司马承祯是唐代玄宗时期的著名道士，活了90多岁，非常难得。

同时，他还是李白的恩主，李白少年出川时遇到了他，后期的书法作品《上阳台帖》就是这两人的羁绊。

### 六戒

我还记得之前有一个玩笑，问: 如何让自己长命百岁，回答就是保持呼吸，不要断气。这个纯是瞎扯淡的，只能活跃气氛不能帮助他人。

我们来看一下大佬是如何劝人的，首先明确一点人家在几千年前活了90多岁，多少还是有点帮助的。

#### **常默元气不伤，少思慧烛内光**

这一段就是在劝我们不要胡说八道，胡思乱想，紊乱自己的磁场。后面人家就详细展开说了六种场景，给了我们一些参考。这首歌里面没有生僻字，跟白居易的风格一样，所见即所得，几乎没有理解难度。

人生一世不过3万多天，实在是太短了。

欲望，是最恐怖的东西。孔夫子说要克己复礼，何也？他所推崇的周礼在春秋末已经彻底破产，没有半点市场了，尊王攘夷成了笑话了。他忽略了人的贪心，他认为可以使用礼法的教育达到克己的目的，但是环境已经不允许了。

春秋以来的义战已经转化为孙子兵法中的兵不厌诈了。为了胜利可以不择手段，我们都在笑宋襄公的半渡不击，却没想到他也只是一个不死的老兵，新时代的船上已经没有他的位置了。

环境在方方面面影响着我们，但是我们先思考一下，我们真正的需求有哪些？

日不过三餐，夜不过一宿，四季的衣服8套已经足够了，出行除了在老家乡下，到处走都方便。我也不知道是不是我的需求太低，太容易满足，比起物质上的富足我更倾向于精神上的进步。

没了那么些乱七八糟的想法，我发现我的生活及其轻松。上班就好好上班，把自己的本质工作做好已经是非常好的了，很多人都做不好自己的工作。下班了就好好生活，给自己找一点乐子，玩游戏、写代码、找朋友聊天，玩累了就看看书、写写字。

此乐何极~



### 六真

中间4句不用看，直接看后四句。里面非常唯物的提出了六个修真的方法，但是我只需要最后一个。

#### 节饮节食少寐，是谓真人坐忘

年龄越来越大了，代谢能力也在慢慢减弱，现在得控制一下自己的体重，30来岁的人是不可以太胖的，那样形象非常不好，尤其是不能有小肚子。

节饮节食的意思并不是说让你少吃少喝，而是节制自己，饭吃八分饱，保留一点点饥饿感最好。

少寐的意思不是让你少睡觉，人家睡觉的时间是6个时辰12个小时，我现在的睡眠质量特别的差，也不知道为什么，1点睡去7点醒来。有的时候睡到8点，那简直是烧高香了，所以每天都是晕晕乎乎，身体素质贼差，很容易感冒。

<!-- wuh-site-metadata: {"cover":"https://cdn.wuh.site/2026-07/1783254259449_download.png"} -->]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[重启计划]]></title>
            <link>https://wuh.site/post/155</link>
            <guid>155</guid>
            <pubDate>Sun, 21 Jun 2026 14:56:38 GMT</pubDate>
            <description><![CDATA[这两天重新读了一下过去写过的博客，才发现我已经很久没有继续写博客了。现在都是在公司内部分享一些技术知识，而且年度总结也已经很久没有写了，这样不好。

继续学习阮老师, 每周发布一篇博客, 无限进步，开始重启计划~~]]></description>
            <content:encoded><![CDATA[这两天重新读了一下过去写过的博客，才发现我已经很久没有继续写博客了。现在都是在公司内部分享一些技术知识，而且年度总结也已经很久没有写了，这样不好。

继续学习阮老师, 每周发布一篇博客, 无限进步，开始重启计划~~]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[codex的开发范式]]></title>
            <link>https://wuh.site/post/135</link>
            <guid>135</guid>
            <pubDate>Sat, 07 Mar 2026 07:54:59 GMT</pubDate>
            <description><![CDATA[## codex的开发范式

在使用 Vibe Coding 的过程中，Codex 应如何规范开发范式?

一句话：**在 Vibe Coding 里，Codex 不应只是“写代码机器”，而应被规范成“按契约执行的工程代理（Engineering Agent）”。**

---

### 1. 先定“角色边界”：Codex 负责产出，人类负责决策

把职责分清楚，效率会高很多：

- **人类负责]]></description>
            <content:encoded><![CDATA[<h2>codex的开发范式</h2>
<p>在使用 Vibe Coding 的过程中，Codex 应如何规范开发范式?</p>
<p>一句话：<strong>在 Vibe Coding 里，Codex 不应只是“写代码机器”，而应被规范成“按契约执行的工程代理（Engineering Agent）”。</strong></p>
<hr>
<h3>1. 先定“角色边界”：Codex 负责产出，人类负责决策</h3>
<p>把职责分清楚，效率会高很多：</p>
<ul>
<li><strong>人类负责</strong>：需求优先级、架构取舍、风险接受、上线决策</li>
<li><strong>Codex 负责</strong>：代码实现、重构建议、测试补全、文档更新、脚手架</li>
</ul>
<blockquote>
<p>原则：<strong>AI 可执行，关键决策必须可追溯到人。</strong></p>
</blockquote>
<hr>
<h3>2.用“任务契约”驱动每次生成（不要直接一句话让它开写）</h3>
<p>每个任务都给 Codex 一个固定输入模板（像 mini-PRD）：</p>
<ol>
<li><strong>目标</strong>（要解决什么问题）</li>
<li><strong>范围</strong>（做什么 / 不做什么）</li>
<li><strong>输入输出契约</strong>（API、类型、错误码）</li>
<li><strong>约束</strong>（性能、安全、兼容性、依赖限制）</li>
<li><strong>验收标准</strong>（可测试、可观测、可回滚）</li>
<li><strong>交付物</strong>（代码 + 测试 + 文档 + 迁移脚本）</li>
</ol>
<hr>
<h3>3. 强制“先设计后编码”</h3>
<p>要求 Codex 每次先给：</p>
<ul>
<li>方案摘要（2~3 种，含 trade-off）</li>
<li>选型理由</li>
<li>影响面清单（模块、接口、数据结构）</li>
<li>风险与回滚策略</li>
</ul>
<p>通过后再开始写代码。</p>
<blockquote>
<p>这一步能显著减少“看起来能跑但不可维护”的代码。</p>
</blockquote>
<hr>
<h3>4. 开发流程标准化（建议 6 步）</h3>
<ol>
<li><strong>Plan</strong>：Codex 输出实施计划（文件级变更列表）</li>
<li><strong>Scaffold</strong>：先生成接口 / 类型 / 测试骨架</li>
<li><strong>Implement</strong>：分小步提交（每步可运行）</li>
<li><strong>Verify</strong>：单测、集成测试、lint、类型检查</li>
<li><strong>Explain</strong>：生成变更说明 + 风险点 + 使用示例</li>
<li><strong>Review Gate</strong>：人类审批后合并</li>
</ol>
<hr>
<h3>5. 代码质量“硬门槛”（不可协商）</h3>
<p>给 Codex 明确以下 gate，没过就不算完成：</p>
<ul>
<li>✅ <code class="notranslate">lint</code> / <code class="notranslate">format</code> 全绿</li>
<li>✅ 类型检查全绿（TS / pyright / mypy 等）</li>
<li>✅ 关键路径测试覆盖达标</li>
<li>✅ 无高危安全问题（注入、密钥泄漏、越权）</li>
<li>✅ 性能回归可解释（基线对比）</li>
</ul>
<hr>
<h3>6. 提示词（Prompt）规范：固定结构，减少随机性</h3>
<p>建议团队统一 Prompt 模板：</p>
<ul>
<li>背景与目标</li>
<li>当前代码上下文</li>
<li>技术约束</li>
<li>输出格式（必须含：代码、测试、迁移、文档）</li>
<li>禁止事项（如“禁止修改公共接口”“禁止引入新依赖”）</li>
<li>验收命令（例如 <code class="notranslate">npm test &amp;&amp; npm run lint</code>）</li>
</ul>
<hr>
<h3>7. 文档与可追溯性</h3>
<p>要求 Codex 每次变更同步输出：</p>
<ul>
<li><code class="notranslate">CHANGELOG</code> 条目</li>
<li>ADR（重要架构决策记录）</li>
<li>接口文档更新</li>
<li>回滚指南</li>
</ul>
<blockquote>
<p>没有文档的 AI 代码，长期一定会变成维护负担。</p>
</blockquote>
<hr>
<h3>8. 常见反模式（要避免）</h3>
<ul>
<li>❌ 让 Codex 一次性“重写整个模块”</li>
<li>❌ 没有测试就合并</li>
<li>❌ 只看“能跑”，不看边界条件和失败路径</li>
<li>❌ 让 AI 自行决定需求边界</li>
<li>❌ 不做 code review 就上线</li>
</ul>
<hr>
<h3>9.可直接执行的团队规则（简版）</h3>
<p>你可以把下面作为团队规范：</p>
<blockquote>
<p><strong>“所有 Codex 任务必须先有任务契约；所有生成代码必须附带测试与变更说明；所有高风险改动必须有人审；未通过质量 gate 禁止合并。”</strong></p>
</blockquote>
<hr>
<p>如果你愿意，我可以进一步给你一份<strong>可直接粘贴到团队 Wiki 的《Vibe Coding + Codex 开发规范模板》</strong>（包含 Prompt 模板、PR 模板、验收清单）。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[docker配置镜像源]]></title>
            <link>https://wuh.site/post/121</link>
            <guid>121</guid>
            <pubDate>Sun, 20 Oct 2024 09:23:54 GMT</pubDate>
            <description><![CDATA[之前用的Docker Desktop 这个工具可以直接在面板里面改，现在换成了podman，面板里面没有位置可以编辑了，在网上找了一些方法来解决问题。



### podman

这里有一个前提，我刚开始看的时候没有留意，导致查了好多资料，最后看大家都一样的写法，最后才发现了别人博客里面最开始就写了一句话: *如果**/etc/docker/daemon.json**这个文件有就直接]]></description>
            <content:encoded><![CDATA[<p>之前用的Docker Desktop 这个工具可以直接在面板里面改，现在换成了podman，面板里面没有位置可以编辑了，在网上找了一些方法来解决问题。</p>
<h3>podman</h3>
<p>这里有一个前提，我刚开始看的时候没有留意，导致查了好多资料，最后看大家都一样的写法，最后才发现了别人博客里面最开始就写了一句话: <em>如果</em>*/etc/docker/daemon.json**这个文件有就直接改，如果没有就新增一个。*</p>
<div class="highlight highlight-source-json"><pre class="notranslate"><span class="pl-ii">// vim /etc/docker/daemon.json</span>

{
  <span class="pl-ent">"registry-mirrors"</span>: [
    <span class="pl-s"><span class="pl-pds">"</span>https://docker.m.daocloud.io<span class="pl-pds">"</span></span>
  ]
}</pre></div>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/74c7acdbd5064060760a4ef59c177ef905c0d1691d1c3475bf1be8925e42ffa6/68747470733a2f2f7372632e7775682e736974652f323032342d30392f323032342d31302d32302d3038313933392e706e67"><img src="https://camo.githubusercontent.com/74c7acdbd5064060760a4ef59c177ef905c0d1691d1c3475bf1be8925e42ffa6/68747470733a2f2f7372632e7775682e736974652f323032342d30392f323032342d31302d32302d3038313933392e706e67" alt="image-20241020161925696" data-canonical-src="https://src.wuh.site/2024-09/2024-10-20-081939.png" style="max-width: 100%;"></a></p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1cc8c060b74caa2fecb308f94185c5bed84aef8724c14b9b2155499e3396af8d/68747470733a2f2f7372632e7775682e736974652f323032342d30392f323032342d31302d32302d3038323032302e706e67"><img src="https://camo.githubusercontent.com/1cc8c060b74caa2fecb308f94185c5bed84aef8724c14b9b2155499e3396af8d/68747470733a2f2f7372632e7775682e736974652f323032342d30392f323032342d31302d32302d3038323032302e706e67" alt="image-20241020162019965" data-canonical-src="https://src.wuh.site/2024-09/2024-10-20-082020.png" style="max-width: 100%;"></a></p>
<h3>docker run</h3>
<div class="highlight highlight-source-shell"><pre class="notranslate">docker run -d -P m.daocloud.io/docker.io/library/镜像名称

样例:
docker run -d -P m.daocloud.io/docker.io/library/mongo</pre></div>
<p>除此之外，还有另一种方法，直接用docker把容器跑起来，在镜像前面把代理的域名加上去就可以了。我就是没有把podman的代理问题解决，改用了这种方式，可以快速搞定。</p>
<p>在github上面找到了一个收集代理源[仓库<a href="https://github.com/DaoCloud/public-image-mirror">public-image-mirror</a>](<a href="https://github.com/DaoCloud/public-image-mirror">https://github.com/DaoCloud/public-image-mirror</a>)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用vitepress搭建wiki]]></title>
            <link>https://wuh.site/post/92</link>
            <guid>92</guid>
            <pubDate>Sat, 13 Apr 2024 10:04:50 GMT</pubDate>
            <description><![CDATA[## 使用vitepress搭建wiki



![image-20240413153801040](https://src.wuh.site/2024-04/2024-04-13-073812.png)

![image-20240413170409041](https://src.wuh.site/2024-04/2024-04-13-090412.png)

前面几个月一直在]]></description>
            <content:encoded><![CDATA[<h2>使用vitepress搭建wiki</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a692a8dc2ab12d3d9465167a6d52851f7f4d49ab4be75cdc1921dd50dbb3b43a/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3037333831322e706e67"><img src="https://camo.githubusercontent.com/a692a8dc2ab12d3d9465167a6d52851f7f4d49ab4be75cdc1921dd50dbb3b43a/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3037333831322e706e67" alt="image-20240413153801040" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-073812.png" style="max-width: 100%;"></a></p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/c1c9ee7652f7aff4e44b24d3074e2f602d75371e36bded0283a0b155da467c88/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3039303431322e706e67"><img src="https://camo.githubusercontent.com/c1c9ee7652f7aff4e44b24d3074e2f602d75371e36bded0283a0b155da467c88/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3039303431322e706e67" alt="image-20240413170409041" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-090412.png" style="max-width: 100%;"></a></p>
<p>前面几个月一直在学习bebal、eslint这种AST相关的知识，一直没有时间去写一篇正儿八经的博客，刚好体验了一下vitepress，在这里记录一下我是如何使用vitepress将我的知识仓库<a href="https://github.com/stack-wuh/blog">blog</a>做成<strong>wiki</strong>的。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/7da14171092f93821c4965dc9e1be59998192bfb6bf911237e1c60b41d0ad8aa/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3037333932322e706e67"><img src="https://camo.githubusercontent.com/7da14171092f93821c4965dc9e1be59998192bfb6bf911237e1c60b41d0ad8aa/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3037333932322e706e67" alt="image-20240413153919880" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-073922.png" style="max-width: 100%;"></a></p>
<p>先展示一下我的文件目录结构，所有文件全部放在<strong>docs</strong>目录下，例如AST、Koa和工作周报这种比较特殊的文件夹是以关键字命名，剩余的博客全部是以年份，年份-月份，年份-月份-博客标题方式命名。</p>
<p>在vitepress的环境中，可以直接指定其工作目录为<strong>docs</strong>这样我们就可以快速地搭建出项目的基本目录。至于如何使用vitepress大家可以快速移步至<a href="https://vitepress.dev/zh/guide/getting-started" rel="nofollow">vitepress的官网</a>。在这里不做过多的介绍，浪费大家太多的时间，使用的步骤非常简单。</p>
<p>下面列出大家可能需要解决的问题:</p>
<ol>
<li>vitepress不会自动生成菜单和导航，需要你自己维护</li>
<li>vitepress采用约定式路由，文件路径即为路由地址</li>
<li>分组维护菜单时必须保证其键值与路由匹配</li>
<li>配合github actoins自动构建发布wiki</li>
</ol>
<h3>一、如何自动生成菜单</h3>
<p>为了处理上述的问题一与问题二，我们必须先认识一下vitepress的配置文件。在我们执行vitepress的init指令后，会在工作目录下生成<strong>index.md</strong>文件与**.vitepress**目录。</p>
<p>其中，<strong>index.md</strong>文件就是项目的首页，在这个页面中可以维护这个网站的快捷入口、标题、描述，具体的就是下面这个样式，这个模板就是vitepress提供的默认模板。</p>
<div class="highlight highlight-text-md"><pre class="notranslate"><span class="pl-s">---</span>
<span class="pl-c"><span class="pl-c">#</span> https://vitepress.dev/reference/default-theme-home-page</span>
<span class="pl-ent">layout</span>: <span class="pl-s">home</span>

<span class="pl-ent">hero</span>:
  <span class="pl-ent">name</span>: <span class="pl-s"><span class="pl-pds">"</span>shadow's wiki<span class="pl-pds">"</span></span>
  <span class="pl-ent">text</span>: <span class="pl-s"><span class="pl-pds">"</span>Fragmented knowledge manager<span class="pl-pds">"</span></span>
  <span class="pl-ent">tagline</span>: <span class="pl-s">碎片化知识管理库</span>
  <span class="pl-ent">image</span>: <span class="pl-s">https://user-images.githubusercontent.com/34117238/117454439-b7d41d00-af78-11eb-8b6f-7e4be67d9aa8.jpeg</span>
  <span class="pl-ent">actions</span>:
    - <span class="pl-ent">theme</span>: <span class="pl-s">brand</span>
      <span class="pl-ent">text</span>: <span class="pl-s">主站点 - wuh.site</span>
      <span class="pl-ent">link</span>: <span class="pl-s">https://wuh.site</span>
    - <span class="pl-ent">theme</span>: <span class="pl-s">alt</span>
      <span class="pl-ent">text</span>: <span class="pl-s">开放API - api.wuh.site</span>
      <span class="pl-ent">link</span>: <span class="pl-s">https://api.wuh.site/v2</span>
    - <span class="pl-ent">theme</span>: <span class="pl-s">alt</span>
      <span class="pl-ent">text</span>: <span class="pl-s">文档站点 - docs.wuh.site</span>
      <span class="pl-ent">link</span>: <span class="pl-s">https://docs.wuh.site</span>

<span class="pl-ent">features</span>:
  - <span class="pl-ent">title</span>: <span class="pl-s">搬山计划</span>
    <span class="pl-ent">icon</span>: <span class="pl-s">{ src: 'https://user-images.githubusercontent.com/34117238/117454439-b7d41d00-af78-11eb-8b6f-7e4be67d9aa8.jpeg', width: '120px', height: '120px' }</span>
    <span class="pl-ent">details</span>: <span class="pl-s">自我修养,犹如搬山</span>
    <span class="pl-ent">link</span>: <span class="pl-s">/$blog/2021/2021-05/搬山计划.html</span>
  - <span class="pl-ent">title</span>: <span class="pl-s">2022年度总结</span>
    <span class="pl-ent">details</span>: <span class="pl-s">每年年中发布一次的年度总结</span>
    <span class="pl-ent">icon</span>: <span class="pl-s">{ src: 'https://src.wuh.site/2022-02/2022-02-08-124302.png', width: '120px', height: '120px' }</span>
    <span class="pl-ent">link</span>: <span class="pl-s">/$blog/2022/2022-01/2022年度总结.html</span>
  - <span class="pl-ent">title</span>: <span class="pl-s">进取</span>
    <span class="pl-ent">icon</span>: <span class="pl-s">{ src: 'https://src.wuh.site/2022-09/20220901.001.png', width: '120px', height: '120px' }</span>
    <span class="pl-ent">details</span>: <span class="pl-s">静以修身，俭以养德。勿以善小而不为，勿以恶小而为之。</span>
    <span class="pl-ent">link</span>: <span class="pl-s">/$blog/2022/2022-09/进取.html</span>
<span class="pl-s">---</span>
</pre></div>
<p>另外，在**.vitepress<strong>中存在一个</strong>config.mjs**文件，它就是整个项目的配置文件了，下面是我的配置文件：</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">defineConfig</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'vitepress'</span>
<span class="pl-k">import</span> <span class="pl-s1">navGenerator</span> <span class="pl-k">from</span> <span class="pl-s">'../../plugins/nav-ganerator'</span>

<span class="pl-c">// https://vitepress.dev/reference/site-config</span>
<span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-en">defineConfig</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">title</span>: <span class="pl-s">"shadow's wiki"</span><span class="pl-kos">,</span>
  <span class="pl-c1">description</span>: <span class="pl-s">"Fragmented knowledge manager"</span><span class="pl-kos">,</span>
  <span class="pl-c1">titleTemplate</span>: <span class="pl-s">'吴尒红'</span><span class="pl-kos">,</span>
  <span class="pl-c1">head</span>: <span class="pl-kos">[</span>
    <span class="pl-kos">[</span><span class="pl-s">'link'</span><span class="pl-kos">,</span> <span class="pl-kos">{</span> <span class="pl-c1">rel</span>: <span class="pl-s">'icon'</span><span class="pl-kos">,</span> <span class="pl-c1">href</span>: <span class="pl-s">'https://wuh.site/_next/image?url=%2Ficons%2F64.png&amp;w=64&amp;q=75'</span> <span class="pl-kos">}</span><span class="pl-kos">]</span><span class="pl-kos">,</span>
    <span class="pl-kos">[</span>
      <span class="pl-s">'script'</span><span class="pl-kos">,</span>
      <span class="pl-kos">{</span> <span class="pl-c1">async</span>: <span class="pl-s">''</span><span class="pl-kos">,</span> <span class="pl-c1">src</span>: <span class="pl-s">'https://www.googletagmanager.com/gtag/js?id=G-X4ZVBQXW9E'</span> <span class="pl-kos">}</span>
    <span class="pl-kos">]</span><span class="pl-kos">,</span>
    <span class="pl-kos">[</span>
      <span class="pl-s">'script'</span><span class="pl-kos">,</span>
      <span class="pl-kos">{</span><span class="pl-kos">}</span><span class="pl-kos">,</span>
      <span class="pl-s">`window.dataLayer = window.dataLayer || [];</span>
<span class="pl-s">      function gtag(){dataLayer.push(arguments);}</span>
<span class="pl-s">      gtag('js', new Date());</span>
<span class="pl-s">      gtag('config', 'G-X4ZVBQXW9E');`</span>
    <span class="pl-kos">]</span>
  <span class="pl-kos">]</span><span class="pl-kos">,</span>
  <span class="pl-c1">themeConfig</span>: <span class="pl-kos">{</span>
    <span class="pl-c">// https://vitepress.dev/reference/default-theme-config</span>
    <span class="pl-c1">nav</span>: <span class="pl-kos">[</span>
      <span class="pl-kos">{</span> <span class="pl-c1">text</span>: <span class="pl-s">'首页'</span><span class="pl-kos">,</span> <span class="pl-c1">link</span>: <span class="pl-s">'/'</span> <span class="pl-kos">}</span>
    <span class="pl-kos">]</span><span class="pl-kos">,</span>

    <span class="pl-c1">sidebar</span>: <span class="pl-kos">{</span><span class="pl-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c1">socialLinks</span>: <span class="pl-kos">[</span>
      <span class="pl-kos">{</span> <span class="pl-c1">icon</span>: <span class="pl-s">'github'</span><span class="pl-kos">,</span> <span class="pl-c1">link</span>: <span class="pl-s">'https://github.com/stack-wuh/blog/tree/gh-page'</span> <span class="pl-kos">}</span><span class="pl-kos">,</span>
      <span class="pl-kos">{</span> <span class="pl-c1">icon</span>: <span class="pl-s">'twitter'</span><span class="pl-kos">,</span> <span class="pl-c1">link</span>: <span class="pl-s">'https://twitter.com/wuh131420'</span> <span class="pl-kos">}</span>
    <span class="pl-kos">]</span><span class="pl-kos">,</span>

    <span class="pl-c1">footer</span>: <span class="pl-kos">{</span>
      <span class="pl-c1">message</span>: <span class="pl-s">'MIT License.'</span><span class="pl-kos">,</span>
      <span class="pl-c1">copyright</span>: <span class="pl-s">'Copyright ©2023. shadow'</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c1">editLink</span>: <span class="pl-kos">{</span>
      <span class="pl-c1">text</span>: <span class="pl-s">'去github编辑'</span><span class="pl-kos">,</span>
      <span class="pl-c1">pattern</span>: <span class="pl-s">'https://github.com/stack-wuh/blog/blob/master/docs/:path'</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c1">lastUpdatedText</span>: <span class="pl-s">'最后更新于'</span><span class="pl-kos">,</span>
    <span class="pl-c1">lastUpdated</span>: <span class="pl-c1">true</span><span class="pl-kos">,</span>

    <span class="pl-c1">search</span>: <span class="pl-kos">{</span>
      <span class="pl-c1">provider</span>: <span class="pl-s">'local'</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c1">outline</span>: <span class="pl-kos">{</span>
      <span class="pl-c1">level</span>: <span class="pl-kos">[</span><span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">]</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>

    <span class="pl-c1">logo</span>: <span class="pl-kos">{</span>
      <span class="pl-c1">src</span>: <span class="pl-s">'https://wuh.site/_next/image?url=%2Ficons%2F64.png&amp;w=64&amp;q=75'</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">vite</span>: <span class="pl-kos">{</span>
    <span class="pl-c1">plugins</span>: <span class="pl-kos">[</span><span class="pl-en">navGenerator</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">]</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">markdown</span>: <span class="pl-kos">{</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">sitemap</span>: <span class="pl-kos">{</span>
    <span class="pl-c1">hostname</span>: <span class="pl-s">'https://wuh.site'</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">rewrites</span>: <span class="pl-kos">{</span>
    <span class="pl-s">'([0-9]{4})/(.*)'</span>: <span class="pl-s">'$blog/([0-9]{4})/(.*)'</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>
  <span class="pl-c1">outDir</span>: <span class="pl-s">'wiki.wuh.site'</span><span class="pl-kos">,</span>
  <span class="pl-c1">srcExclude</span>: <span class="pl-kos">[</span><span class="pl-s">'**/README.md'</span><span class="pl-kos">,</span> <span class="pl-s">'**/*.js'</span><span class="pl-kos">,</span> <span class="pl-s">'**/*.png'</span><span class="pl-kos">,</span> <span class="pl-s">'**/*.assets'</span><span class="pl-kos">]</span><span class="pl-kos">,</span>
  <span class="pl-c1">metaChunk</span>: <span class="pl-c1">true</span><span class="pl-kos">,</span>
  <span class="pl-c1">base</span>: <span class="pl-s">'/blog/'</span><span class="pl-kos">,</span>
  <span class="pl-c1">ignoreDeadLinks</span>: <span class="pl-c1">true</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span></pre></div>
<p>如果不出意外的话，在你执行<strong>pnpm init</strong>以及 <strong>pnpm dev</strong>之后，会出现由vitepress提供的默认页面。但是你的工作目录下的文件并没有自动生成菜单。</p>
<p>现在我们回到刚刚开始的问题，如何自动生成菜单和导航？</p>
<p>有两种方法，第一种是常规方法，把路由一个个在<strong>themeConfig.sidebar</strong>中维护进去，还有一种是利用其编译时的能力，写一个vite插件，直接在编译时改掉vite上下文中的配置文件。</p>
<p>大家回到<strong>config.mjs</strong>文件中，仔细看一下我在<strong>vite</strong>中配置了一个插件<a href="https://github.com/stack-wuh/blog/blob/gh-page/plugins/nav-ganerator/index.js">navGenerator</a>。在这个插件中我们只需要将文件路径转化为路由地址就可以了，然后在vite的上下文中的themeConfig.sidebar 改写为我们重新生成的对象就可以了。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-en">navGenerator</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">return</span> <span class="pl-kos">{</span>
    <span class="pl-c1">name</span>: <span class="pl-s">'nav-generator'</span><span class="pl-kos">,</span>
    <span class="pl-en">configResolved</span><span class="pl-kos">(</span><span class="pl-s1">config</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-k">const</span> <span class="pl-kos">{</span> vitepress <span class="pl-kos">}</span> <span class="pl-c1">=</span> <span class="pl-s1">config</span>
      <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-c1">!</span><span class="pl-s1">vitepress</span><span class="pl-kos">)</span> <span class="pl-k">return</span>
      <span class="pl-k">const</span> <span class="pl-s1">menus</span> <span class="pl-c1">=</span> <span class="pl-en">slideGroupByHead</span><span class="pl-kos">(</span><span class="pl-s1">vitepress</span><span class="pl-kos">.</span><span class="pl-c1">pages</span><span class="pl-kos">)</span>

      <span class="pl-v">Reflect</span><span class="pl-kos">.</span><span class="pl-en">deleteProperty</span><span class="pl-kos">(</span><span class="pl-s1">menus</span><span class="pl-kos">,</span> <span class="pl-s">'序言'</span><span class="pl-kos">)</span>
      <span class="pl-s1">vitepress</span><span class="pl-kos">.</span><span class="pl-c1">userConfig</span><span class="pl-kos">.</span><span class="pl-c1">themeConfig</span><span class="pl-kos">.</span><span class="pl-c1">sidebar</span> <span class="pl-c1">=</span> <span class="pl-s1">menus</span>
      <span class="pl-s1">vitepress</span><span class="pl-kos">.</span><span class="pl-c1">userConfig</span><span class="pl-kos">.</span><span class="pl-c1">themeConfig</span><span class="pl-kos">.</span><span class="pl-c1">nav</span> <span class="pl-c1">=</span> <span class="pl-en">transformToNav</span><span class="pl-kos">(</span><span class="pl-s1">menus</span><span class="pl-kos">)</span>
    <span class="pl-kos">}</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p><strong>vite</strong>中的插件开发极其简单，利用<strong>vite</strong>提供的能力在其对应的钩子中，直接改其上下文的对象，就可以满足我们的需求。</p>
<p>我在刚开始做的时候也去找了一些博客看了一下前人是怎么做的，后来我发现他们的做法有点没必要。他们在利用<strong>vite</strong>的钩子在生成正常的路由地址后，去改写了<strong>config.mjs</strong>源文件中的<strong>sidebar</strong>对象，可实际上完全没有必要。</p>
<p>无论是<strong>webpack</strong>还是<strong>vite</strong>它们的构建流程都是链式的，它代表着上一个插件如果改动了上下文中的配置是会影响下一个插件的。所以完全不用去改源文件，只需要改动钩子中暴露出来的<strong>vitepress context</strong>，就可以满足需求。</p>
<p>但是有一个大前提，这个过程必须发生在最终生成文件的的插件之前。我们已知vitepress将md文件转换成html是利用的<strong>markdown-it</strong>插件，所以必须将<strong>navGenerator</strong>插件的触发时间提前。</p>
<p>正好<strong>configResolved</strong>钩子是最前面的那个入口，而且在此时vitepress已经完成了目录的解析，在此时我们已经可以非常完整地拿到工作目录下全部的md文件了。</p>
<p>插件的全部代码可以点击链接在github中的<a href="https://github.com/stack-wuh/blog/blob/gh-page/plugins/nav-ganerator/index.js">plugins/nav-generator</a>查看。</p>
<h3>二、如何正确维护多分组sidebar</h3>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/00c83c8f8e6dcaf2ea8b8fbefd1322b294ada604714cc8f4a7f87233a9148fb0/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3038353433392e706e67"><img src="https://camo.githubusercontent.com/00c83c8f8e6dcaf2ea8b8fbefd1322b294ada604714cc8f4a7f87233a9148fb0/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3038353433392e706e67" alt="image-20240413165436184" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-085439.png" style="max-width: 100%;"></a></p>
<p>但是分组多侧边栏这里有一个小坑要注意一下。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1fd943db92a8d51b7165d19ff03e89075450dfd43b469b783b12d2aef3fc673e/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3038353634352e706e67"><img src="https://camo.githubusercontent.com/1fd943db92a8d51b7165d19ff03e89075450dfd43b469b783b12d2aef3fc673e/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3038353634352e706e67" alt="image-20240413165641489" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-085645.png" style="max-width: 100%;"></a></p>
<p>以我的项目文档为例，最后生成的文档对应的对象应该是下面这样，我只截取一部分展示。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/2f89c79f615cf7fbb82bf399c98b99695c43e4adfe759924c7073b722f84a1e1/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3039303135302e706e67"><img src="https://camo.githubusercontent.com/2f89c79f615cf7fbb82bf399c98b99695c43e4adfe759924c7073b722f84a1e1/68747470733a2f2f7372632e7775682e736974652f323032342d30342f323032342d30342d31332d3039303135302e706e67" alt="image-20240413170148327" data-canonical-src="https://src.wuh.site/2024-04/2024-04-13-090150.png" style="max-width: 100%;"></a></p>
<p>与生成sidebar同理，nav的数据也可以继续利用这种方法生成。最后的效果就是大家看到的封面图那样。</p>
<h3>三、自动构建发布</h3>
<p>继续利用我们之前介绍过的<strong>github actions</strong>帮助我们自动构建发布。同样在vitepress的官网中提供的一个<a href="https://vitepress.dev/zh/guide/deploy#github-pages" rel="nofollow">工作流示例</a>。</p>
<p><strong>github actions</strong>是一个非常友好的工作流，在之前我已经写了一篇博客，详细地介绍了我是如何actions实现了我的博客项目自动构建发布，可以移步原文<a href="https://wuh.site/post/Github%20Actions%20%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%BA%94%E7%94%A8" rel="nofollow">Github Actions 自动部署应用</a>。</p>
<p>下面是我的<a href="https://github.com/stack-wuh/blog/blob/gh-page/.github/workflows/deploy.yaml">工作流配置文件</a>:</p>
<div class="highlight highlight-source-yaml"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> 构建 VitePress 站点并将其部署到 GitHub Pages 的示例工作流程</span>
<span class="pl-c"><span class="pl-c">#</span></span>
<span class="pl-ent">name</span>: <span class="pl-s">Deploy VitePress site to Pages</span>

<span class="pl-ent">on</span>:
  <span class="pl-c"><span class="pl-c">#</span> 在针对 `main` 分支的推送上运行。如果你</span>
  <span class="pl-c"><span class="pl-c">#</span> 使用 `master` 分支作为默认分支，请将其更改为 `master`</span>
  <span class="pl-ent">push</span>:
    <span class="pl-ent">branches</span>: <span class="pl-s">[gh-page]</span>

  <span class="pl-c"><span class="pl-c">#</span> 允许你从 Actions 选项卡手动运行此工作流程</span>
  <span class="pl-ent">workflow_dispatch</span>:

<span class="pl-c"><span class="pl-c">#</span> 设置 GITHUB_TOKEN 的权限，以允许部署到 GitHub Pages</span>
<span class="pl-ent">permissions</span>:
  <span class="pl-ent">contents</span>: <span class="pl-s">read</span>
  <span class="pl-ent">pages</span>: <span class="pl-s">write</span>
  <span class="pl-ent">id-token</span>: <span class="pl-s">write</span>

<span class="pl-c"><span class="pl-c">#</span> 只允许同时进行一次部署，跳过正在运行和最新队列之间的运行队列</span>
<span class="pl-c"><span class="pl-c">#</span> 但是，不要取消正在进行的运行，因为我们希望允许这些生产部署完成</span>
<span class="pl-ent">concurrency</span>:
  <span class="pl-ent">group</span>: <span class="pl-s">pages</span>
  <span class="pl-ent">cancel-in-progress</span>: <span class="pl-c1">false</span>

<span class="pl-ent">jobs</span>:
  <span class="pl-c"><span class="pl-c">#</span> 构建工作</span>
  <span class="pl-ent">build</span>:
    <span class="pl-ent">runs-on</span>: <span class="pl-s">ubuntu-latest</span>
    <span class="pl-ent">steps</span>:
      - <span class="pl-ent">name</span>: <span class="pl-s">Checkout</span>
        <span class="pl-ent">uses</span>: <span class="pl-s">actions/checkout@v4</span>
        <span class="pl-ent">with</span>:
          <span class="pl-ent">fetch-depth</span>: <span class="pl-c1">0</span> <span class="pl-c"><span class="pl-c">#</span> 如果未启用 lastUpdated，则不需要</span>
      - <span class="pl-ent">uses</span>: <span class="pl-s">pnpm/action-setup@v3 </span><span class="pl-c"><span class="pl-c">#</span> 如果使用 pnpm，请取消注释</span>
        <span class="pl-ent">with</span>:
          <span class="pl-ent">version</span>: <span class="pl-c1">8</span>
      <span class="pl-c"><span class="pl-c">#</span> - uses: oven-sh/setup-bun@v1 # 如果使用 Bun，请取消注释</span>
      - <span class="pl-ent">name</span>: <span class="pl-s">Setup Node</span>
        <span class="pl-ent">uses</span>: <span class="pl-s">actions/setup-node@v4</span>
        <span class="pl-ent">with</span>:
          <span class="pl-ent">node-version</span>: <span class="pl-c1">20</span>
          <span class="pl-ent">cache</span>: <span class="pl-s">pnpm </span><span class="pl-c"><span class="pl-c">#</span> 或 pnpm / yarn</span>
      - <span class="pl-ent">name</span>: <span class="pl-s">Setup Pages</span>
        <span class="pl-ent">uses</span>: <span class="pl-s">actions/configure-pages@v4</span>
      - <span class="pl-ent">name</span>: <span class="pl-s">Install dependencies</span>
        <span class="pl-ent">run</span>: <span class="pl-s">pnpm install </span><span class="pl-c"><span class="pl-c">#</span> 或 pnpm install / yarn install / bun install</span>
      - <span class="pl-ent">name</span>: <span class="pl-s">Build with VitePress</span>
        <span class="pl-ent">run</span>: <span class="pl-s">pnpm run docs:build </span><span class="pl-c"><span class="pl-c">#</span> 或 pnpm docs:build / yarn docs:build / bun run docs:build</span>
      - <span class="pl-ent">name</span>: <span class="pl-s">Upload artifact</span>
        <span class="pl-ent">uses</span>: <span class="pl-s">actions/upload-pages-artifact@v3</span>
        <span class="pl-ent">with</span>:
          <span class="pl-ent">path</span>: <span class="pl-s">docs/wiki.wuh.site</span>

  <span class="pl-c"><span class="pl-c">#</span> 部署工作</span>
  <span class="pl-ent">deploy</span>:
    <span class="pl-ent">environment</span>:
      <span class="pl-ent">name</span>: <span class="pl-s">github-pages</span>
      <span class="pl-ent">url</span>: <span class="pl-s">${{ steps.deployment.outputs.page_url }}</span>
    <span class="pl-ent">needs</span>: <span class="pl-s">build</span>
    <span class="pl-ent">runs-on</span>: <span class="pl-s">ubuntu-latest</span>
    <span class="pl-ent">name</span>: <span class="pl-s">Deploy</span>
    <span class="pl-ent">steps</span>:
      - <span class="pl-ent">name</span>: <span class="pl-s">Deploy to GitHub Pages</span>
        <span class="pl-ent">id</span>: <span class="pl-s">deployment</span>
        <span class="pl-ent">uses</span>: <span class="pl-s">actions/deploy-pages@v4</span>
</pre></div>
<p>在使用<strong>vitepress</strong>搭建wiki库之前，先切一个<strong>gh-page</strong>分支出来，后期我们做自动构建主要是以这个分支为主，而不是master分支。</p>
<p>注意，我们只需要改几处就可以使github正常工作了:</p>
<ol>
<li>构建分支，将其改为gh-page</li>
<li>将打包器改为使用pnpm</li>
<li>将指令也改为pnpm配套指令</li>
<li>更改产出文件目录</li>
</ol>
<p>与此同时，项目内部的<strong>config.mjs</strong>文件产出目录也需要改一下，因为github pages的部署路由会自动在前面加上/blog/，所以项目的basePath也需要加一个前缀/blog/。</p>
<p>到此为止，全部的流程就介绍完啦~~~</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[如何使用zLibrary]]></title>
            <link>https://wuh.site/post/65</link>
            <guid>65</guid>
            <pubDate>Sun, 11 Jun 2023 03:23:39 GMT</pubDate>
            <description><![CDATA[## 如何使用zLibrary

![](https://src.wuh.site/2023-06/2023-06-11-030612.png)

昨天下了一天的雨，闲着实在没什么事情做，就在微信阅读里面找了一本书《长安的荔枝》来读，读的正在兴头上呢，结果出现了下面这个恶心的东西。不得不说，现在的微信读书没有之前好用了，腾讯总是习惯于把一款优秀的产品做成垃圾。

<img src="https:/]]></description>
            <content:encoded><![CDATA[<h2>如何使用zLibrary</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/54f09a6a7b5d412fe021e23747bfc6f20520725bf5109349934df4110244cf9d/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033303631322e706e67"><img src="https://camo.githubusercontent.com/54f09a6a7b5d412fe021e23747bfc6f20520725bf5109349934df4110244cf9d/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033303631322e706e67" alt="" data-canonical-src="https://src.wuh.site/2023-06/2023-06-11-030612.png" style="max-width: 100%;"></a></p>
<p>昨天下了一天的雨，闲着实在没什么事情做，就在微信阅读里面找了一本书《长安的荔枝》来读，读的正在兴头上呢，结果出现了下面这个恶心的东西。不得不说，现在的微信读书没有之前好用了，腾讯总是习惯于把一款优秀的产品做成垃圾。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/aa46189b3439f25102b33be6e0045402c75d233a589532384e3b83fdaa01c208/68747470733a2f2f7372632e7775682e736974652f323032332d30342f323032332d30362d31312d576563686174494d473130342e6a706567"><img src="https://camo.githubusercontent.com/aa46189b3439f25102b33be6e0045402c75d233a589532384e3b83fdaa01c208/68747470733a2f2f7372632e7775682e736974652f323032332d30342f323032332d30362d31312d576563686174494d473130342e6a706567" width="400px" data-canonical-src="https://src.wuh.site/2023-04/2023-06-11-WechatIMG104.jpeg" style="max-width: 100%;"></a></p>
<p>实在是受不了这种，我是提倡知识付费的，但是白嫖还是快乐的。我想起了之前看到的一个视频里面提到过一个免费的在线图书馆，资源贼拉多，它就是大名鼎鼎的<a href="https://lib-boxnfxb7fl57xmwt2nd5h4gx.1lib.fr/" rel="nofollow">zlibrary</a></p>
<p>这个网站的官网已经被封了，一些镜像站也被封了。我是在telegram里面找到了一些组群，在里面找到了一个可以使用的机器人：<a href="https://t.me/fbooki" rel="nofollow">https://t.me/fbooki</a></p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6a1ad6a16dd653c57fa3411ff2420014a8c8ee4b6cfff957fb96525682b2f9a5/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313234362e706e67"><img src="https://camo.githubusercontent.com/6a1ad6a16dd653c57fa3411ff2420014a8c8ee4b6cfff957fb96525682b2f9a5/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313234362e706e67" alt="" data-canonical-src="https://src.wuh.site/2023-06/2023-06-11-031246.png" style="max-width: 100%;"></a></p>
<p>这个机器人会发一些可以使用链接地址，大家可以自行点击使用。下面我贴一个镜像站：<a href="https://lib-boxnfxb7fl57xmwt2nd5h4gx.1lib.fr/%E3%80%82" rel="nofollow">https://lib-boxnfxb7fl57xmwt2nd5h4gx.1lib.fr/。</a></p>
<p>除此之外，还有一种的暗网访问的方法，这里贴一个教程链接:<a href="https://www.youtube.com/watch?v=pK3LzbT271E" rel="nofollow">https://www.youtube.com/watch?v=pK3LzbT271E</a></p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a3affd395ce8a1a6675822443c49eeb6c450725357270fa667538a2c56d991a9/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313634302e706e67"><img src="https://camo.githubusercontent.com/a3affd395ce8a1a6675822443c49eeb6c450725357270fa667538a2c56d991a9/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313634302e706e67" alt="" data-canonical-src="https://src.wuh.site/2023-06/2023-06-11-031640.png" style="max-width: 100%;"></a></p>
<p>其使用方式是一样一样的，点击书籍链接进入明细就可以看到下载按钮了，我们直接使用默认的下载类型，然后在微信读书里面导入本地文件，就也可以继续阅读了。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e131b7a34f27e6549d9bf96fc97d6b3a9b929d75b9bc3da3152be4a3834ef8e3/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313930382e706e67"><img src="https://camo.githubusercontent.com/e131b7a34f27e6549d9bf96fc97d6b3a9b929d75b9bc3da3152be4a3834ef8e3/68747470733a2f2f7372632e7775682e736974652f323032332d30362f323032332d30362d31312d3033313930382e706e67" alt="" data-canonical-src="https://src.wuh.site/2023-06/2023-06-11-031908.png" style="max-width: 100%;"></a></p>
<p><strong>注意</strong>:</p>
<ol>
<li>使用zlibrary有一个大前提，准备好科学上网</li>
</ol>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[复杂函数设计与治理-分治法]]></title>
            <link>https://wuh.site/post/41</link>
            <guid>41</guid>
            <pubDate>Sun, 29 Jan 2023 09:30:40 GMT</pubDate>
            <description><![CDATA[## 复杂函数设计与治理-分治法

在项目中，经常会遇到的一种情况，就是大段大段的逻辑代码，各种各样的逻辑全局集中到了主函数的内部，在上一次的【盘活运力】的review中，我给大家描述了一下，我是怎么处理大段逻辑代码的，这里是记录性质的博客。

对于可复用性要求较高的公共函数、公共文件的封装或者是逻辑的处理。可以对比去看一下重构之前的代码，大段的逻辑代码集中在一个函数内部，导致一个函数的逻辑杂糅，]]></description>
            <content:encoded><![CDATA[<h2>复杂函数设计与治理-分治法</h2>
<p>在项目中，经常会遇到的一种情况，就是大段大段的逻辑代码，各种各样的逻辑全局集中到了主函数的内部，在上一次的【盘活运力】的review中，我给大家描述了一下，我是怎么处理大段逻辑代码的，这里是记录性质的博客。</p>
<p>对于可复用性要求较高的公共函数、公共文件的封装或者是逻辑的处理。可以对比去看一下重构之前的代码，大段的逻辑代码集中在一个函数内部，导致一个函数的逻辑杂糅，一个方法甚至有几百行，这都是需要优化的地方。</p>
<p>从我个人的经验来看，对于公共方法，有以下几个关键点:<br>
高灵活性<br>
高区块性<br>
高责任性</p>
<p>高灵活性<br>
其实，灵活性就是可扩展性。</p>
<p>我们在写公共的函数的时候，无论是mixin文件还是utils工具文件，都要做到的一点就是，一定要操作空间，一旦这个函数内部的逻辑不满足了，还可以通过外部传入的逻辑，来实现我的最终目的，而不用改动公共函数的内部代码。</p>
<p>怎么留足操作空间呢？就是在关键的逻辑位置提供一个函数，可以满足外部传入的需求。</p>
<p>高区块性<br>
区块性，就是说将一大段函数逻辑，拆分为若干个逻辑片段。</p>
<p>既然是逻辑杂糅了，那就必然可以将一段杂糅的逻辑切片成多段逻辑，然后按照执行的顺序依次执行，到了最后的结果就是将多段函数的执行结果就是大函数的执行结果，这种方法就叫分治。</p>
<p>高责任性<br>
指函数职责的单一性要强，对于公共函数一定要做到，一个方法一个功能。</p>
<p>对于单一职责我们一直放在嘴边，但是完成的力度一直不够，我们可以回想一下现在的代码，很多情景下，对于多个地方用到了相同的公共函数的位置，经常会来新声明一个函数。而这个新函数的作用就是将多个公共函数放在一起，然后在页面上就调用这个新函数。</p>
<p>对于这个新函数，你能说它职责单一了吗？</p>
<p>一旦遇到了特殊场景，大部分开发人员就会在新函数内部，使用各种if/else的逻辑判断来执行对应的函数，随着迭代次数越来越多，逻辑越来越复杂，新函数就成了另一个杂糅函数，换一句话说，它不纯了。</p>
<p>分治法<br>
分治法，是一种经典的数学算法，取分而治之之意。目的是将一个复杂的问题划分为多个相同或者是相似的小问题，分开解决。</p>
<p>对于具体实现可以看下图代码，<a href="http://gitlab.ky-tech.com.cn/kuasheng-h5/coo-quality-monitor/blob/test/src/components/rank-table/mixins/base.mixin.js" rel="nofollow">文件地址</a>：</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/215317409-efec7a0d-9b3c-4dd4-8b93-0cf8f99244a7.png"><img src="https://user-images.githubusercontent.com/34117238/215317409-efec7a0d-9b3c-4dd4-8b93-0cf8f99244a7.png" alt="image" style="max-width: 100%;"></a><br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/215317422-278c5ed5-8a13-4bf4-bd7d-cc1bb134d1f7.png"><img src="https://user-images.githubusercontent.com/34117238/215317422-278c5ed5-8a13-4bf4-bd7d-cc1bb134d1f7.png" alt="image (1)" style="max-width: 100%;"></a></p>
<p>这一段是我们经常遇到的处理表格的请求逻辑，它是一个非常典型的、可复用性要求较高的、可分治的案例。</p>
<p>它是一个mixin混入文件，给9个表格业务组件提供了全部的逻辑支持，基本没有出现什么问题。分治点已经标出，大家可以点击文件链接进去自由查看细节。</p>
<p>大家可以仔细看一下，上面说的三点在这个案例中已经全部体现出来了。</p>
<p>对于一个区块内部的逻辑，可以将它分成两块，一部分由函数体内部提供一个默认函数，同时支持外部传入函数，留足了操作空间，灵活性极佳。</p>
<p>每一个区块内部的函数，只管理它负责部分的功能，可以清晰的看到我标出的5个分治点，就是其区块性最好的体现。</p>
<p>现在项目中有大量的业务代码，可以提供给大家练手的机会，可以尽情地去使用分治法。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[通过axios请求反查文件路径]]></title>
            <link>https://wuh.site/post/40</link>
            <guid>40</guid>
            <pubDate>Sun, 29 Jan 2023 09:27:35 GMT</pubDate>
            <description><![CDATA[## 通过axios请求反查文件路径

现在ERP以及支持通过Element面板查找使用组件的文件地址，但是还有一种情景是比较特殊的。在批量改完cooHttp优化需求之后，还可以通过发起的ajax的请求来查找发起请求的文件路径。

如下图，即为ERP支持的使用组件的文件地址:
![image](https://user-images.githubusercontent.com/34117]]></description>
            <content:encoded><![CDATA[<h2>通过axios请求反查文件路径</h2>
<p>现在ERP以及支持通过Element面板查找使用组件的文件地址，但是还有一种情景是比较特殊的。在批量改完cooHttp优化需求之后，还可以通过发起的ajax的请求来查找发起请求的文件路径。</p>
<p>如下图，即为ERP支持的使用组件的文件地址:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/215317269-bf8dd78b-856b-453c-977d-d376164205de.png"><img src="https://user-images.githubusercontent.com/34117238/215317269-bf8dd78b-856b-453c-977d-d376164205de.png" alt="image" style="max-width: 100%;"></a></p>
<p>如何通过ajax反查调用文件位置<br>
打开NewWork面板中的Initiator栏<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/215317285-90b67cf8-550c-4515-98f3-42617f1b3769.png"><img src="https://user-images.githubusercontent.com/34117238/215317285-90b67cf8-550c-4515-98f3-42617f1b3769.png" alt="image (1)" style="max-width: 100%;"></a></p>
<p>鼠标移入对应的接口处，就可以看到请求的执行栈，标红处是依次触发的方法，标蓝处是执行方法时对应的文件位置<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/215317288-c56e8146-8111-48d7-960f-66eac5679908.png"><img src="https://user-images.githubusercontent.com/34117238/215317288-c56e8146-8111-48d7-960f-66eac5679908.png" alt="image (2)" style="max-width: 100%;"></a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[进取]]></title>
            <link>https://wuh.site/post/39</link>
            <guid>39</guid>
            <pubDate>Sun, 25 Sep 2022 09:12:40 GMT</pubDate>
            <description><![CDATA[## 进取

![](https://src.wuh.site/2022-09/20220901.001.png)

> 吾日三省吾身，为人谋而不忠乎？与朋友交而不信乎？传不习乎？

最近，准确地说是昨天，发生了一件值得让我深思的事情。“我并没有学会珍惜”是我思考之后得出的结果。

我想我必须把这件事情记录一下，留给未来的自己，值得反复体会。

### 回忆

首先我家没什]]></description>
            <content:encoded><![CDATA[<h2>进取</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3ae7db1fa8b78b8db0154e240c22ea70c0f065b8e937351fd305965525cc9fe0/68747470733a2f2f7372632e7775682e736974652f323032322d30392f32303232303930312e3030312e706e67"><img src="https://camo.githubusercontent.com/3ae7db1fa8b78b8db0154e240c22ea70c0f065b8e937351fd305965525cc9fe0/68747470733a2f2f7372632e7775682e736974652f323032322d30392f32303232303930312e3030312e706e67" alt="" data-canonical-src="https://src.wuh.site/2022-09/20220901.001.png" style="max-width: 100%;"></a></p>
<blockquote>
<p>吾日三省吾身，为人谋而不忠乎？与朋友交而不信乎？传不习乎？</p>
</blockquote>
<p>最近，准确地说是昨天，发生了一件值得让我深思的事情。“我并没有学会珍惜”是我思考之后得出的结果。</p>
<p>我想我必须把这件事情记录一下，留给未来的自己，值得反复体会。</p>
<h3>回忆</h3>
<p>首先我家没什么底子，就是一个普普通通的农民家庭，从小到大没什么依仗都是靠我爸一个人独立奋斗，唯二的就是我的亲人们时不时地帮助，什么帮助呢？帮你做一做耗时的农活。</p>
<p>棉花，一种经济作物，但是现在它越来越廉价。</p>
<p>种棉花是体力活，它不像插秧苗直接插到水地里，唯一的相同点就是人必须得弯着腰，直到把家里的棉花田里全部种满，那个时候人才能得到一点点的休息时间。</p>
<p>有一种棉是开心棉，很好摘。还有一种，是闭口的，是淋了雨，打了风，掉落在地里的。这种不好搞，要暴晒之后，才能剥开外壳。</p>
<p>我印象中最深刻的画面就是我爸一个人，一台电视机，两大筐闭口棉，干到半夜1点过，而明天他早上5点又要早起下地了。</p>
<p>太阳，太炽热了，太残酷了，太无情了。</p>
<p>我能体会到，那段时间，准确地说是那十年，他很累。</p>
<p>现在，他在工厂里面上班，他终于脱离了面朝黄土背朝天的日子。</p>
<h3>虚无的狂欢</h3>
<p>我陷入了一种虚无，精神上的虚无。整整一个月的迟到，扣了2000块。刚开始我觉得没什么，就这样，它只是我工资的一小部分，更何况那段时间我确实感觉很累很累，早上睡不醒，晚上睡不着，头痛胃痛啥都有。</p>
<p>想吃啥吃啥，想买啥买啥，美其名曰太累，身体不好，需要搞点好东西改善一下伙食，现在回过头去看，简直是浪费，我忘记了过去的我了，我忘记了那一段艰苦的日子。</p>
<p>我很久没有读书了，最近沉迷上了王者荣耀，连胜让我觉得很过瘾，吸引我一直打下去。唯一让我欣慰地是，我没有染上一些陋习。</p>
<p>不赌不嫖不偷不抢，我还是我。迷失的是那个积极进取、热爱读书的我，我已经不再是我了。</p>
<p>我可以把一些客观因素归结到繁重的工作吗？是天天加班导致的心力交瘁？还是自己已经甘于沉沦了，甘愿躲在过去的阴影里面？</p>
<h3>求己</h3>
<p>我忘记了我们小学时候学过的《论语》了，还记得“吾日三省吾身”吗？还记得《劝学》吗？</p>
<p>我怎么可以把一切问题推给外部环境，我忘记了“适者生存”的丛林法则。如果我一直抱着这种想法，我终将被社会淘汰，成为优秀的猎食者的晚餐。</p>
<p>我突然之间想起了《人间失格》，自我催眠的弱者，怎么可能在这个社会丛林正常的生存。如果能在一些文学作品中看到自己的样子，说明这本小说是一个最基础的社会缩影，它是现实的。</p>
<p>试着通过这类文学作品去反推，看看自己在小说中的结局，它又是魔幻的。</p>
<p>魔幻的现实是残酷的，是悲剧的，是无法挣脱的枷锁，是禁锢自己的牢笼。</p>
<p>不去主动地打破牢笼，就失去了向上的阶梯， 将被永远的困在地牢，不见光明。失去了阳光，失去了一切。</p>
<p>我想起了刚上班的那段时间，上下班的路上我在思考怎么写那些业务代码，因为我接手的第一个项目就做砸了，当时是我的领导保了我，给了我第二次机会。那真是一段令人无法忘记的回忆。</p>
<h3>变化</h3>
<p>我觉得思考的东西应该是要深刻的。写到这里我想先停一下。</p>
<p><strong>越是深刻的东西越是简单</strong>。归根究底，就是我进入社会的这5年，过的太顺利了。顺利到我还没有学会<strong>珍惜</strong>。</p>
<p>回顾了一下我的履历，我是在大佬的爱护下成长的。我的每一位领导年龄都比我大，我想他们对我的这种爱护之情，包容之心和同事之谊，就是我成长的养分。</p>
<p>我听说，我的同事们私底下对我的评价还不错，他们都认为我的业务水平还可以，但其实我已经在原地踏步了一年，我想我已经很落后了。</p>
<p><strong>技术</strong>是个很容易替代的东西。我认为，一个刚毕业的大学生，给他足够的训练时间，外加一位负责的领导指导一下，可以极大地减少他上手的代价。</p>
<p>所以，遇到了这样的一个领导或者是同事，他又愿意和你交流，愿意给你分析一些问题，是一件幸福的事情，是一件值得珍惜的事情。同时，这样的同事是值得深交的，很多事情，有高人指点可以免去你很多的时间。</p>
<p>同时，在自己力所能及的范围内，对后浪们也要有一种<strong>爱护</strong>之情。他们只是比我入行晚而已，我的优势只是比他们提前入行，见过的东西多一些，见过套路多一些，除此以外，我没有任何<strong>优势</strong>。</p>
<h3>启程</h3>
<p>无言是最好的告白。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[丧钟为谁而鸣]]></title>
            <link>https://wuh.site/post/38</link>
            <guid>38</guid>
            <pubDate>Mon, 04 Apr 2022 12:48:43 GMT</pubDate>
            <description><![CDATA[## 丧钟为谁而鸣

![](https://src.wuh.site/2022-02/2022-04-04-%E5%B0%81%E9%9D%A2%E5%9B%BE.key.001.png)

> 勿忧勿忧，欲说还休；不休不休，至死方休。

此刻，我一边喝着酒，一边想着一些骚话。

先来一口，开摆。

也不知道为什么起了这样一个标题，可能是忽然之间想起来这么一本书，内容是什么一]]></description>
            <content:encoded><![CDATA[<h2>丧钟为谁而鸣</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/4fe21eca145ab39d2cd0bf79f8d8203d96e157e3fa201edcbc2a99d0bee8ae32/68747470733a2f2f7372632e7775682e736974652f323032322d30322f323032322d30342d30342d2545352542302538312545392539442541322545352539422542452e6b65792e3030312e706e67"><img src="https://camo.githubusercontent.com/4fe21eca145ab39d2cd0bf79f8d8203d96e157e3fa201edcbc2a99d0bee8ae32/68747470733a2f2f7372632e7775682e736974652f323032322d30322f323032322d30342d30342d2545352542302538312545392539442541322545352539422542452e6b65792e3030312e706e67" alt="" data-canonical-src="https://src.wuh.site/2022-02/2022-04-04-%E5%B0%81%E9%9D%A2%E5%9B%BE.key.001.png" style="max-width: 100%;"></a></p>
<blockquote>
<p>勿忧勿忧，欲说还休；不休不休，至死方休。</p>
</blockquote>
<p>此刻，我一边喝着酒，一边想着一些骚话。</p>
<p>先来一口，开摆。</p>
<p>也不知道为什么起了这样一个标题，可能是忽然之间想起来这么一本书，内容是什么一时之间也想不起更多了。既然内容想不起来了，那就直接用他的标题吧。</p>
<p>如果非要给未来定义一个颜色，那我的未来一定是灰色，或者我认为我的未来是灰色。矛盾的对立统一在我的身上得到了相当明显的体现，换一种描述，那就叫它“纠缠”吧，再也不用纠结它的实体了，它就是抽象的存在。</p>
<p>我的生活轨迹就像是齿轮一样，每天都在重复做一样的事情，我很想改变他，最后却发现我无能为力，能改变的只能是我自己。</p>
<p>就这样，我在生活的漩涡中越陷越深。同时，我很庆幸我还没有结婚，还没有孩子，还没有家庭，还没有那如山的压力。我毫不怀疑，我可以想象出这样的一种压力可以把一个家庭家长的腰彻底压垮。</p>
<p>我已在漩涡中，挣扎太久，我变老了，我想我快失去动力了。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2022年度总结]]></title>
            <link>https://wuh.site/post/37</link>
            <guid>37</guid>
            <pubDate>Tue, 08 Feb 2022 12:59:52 GMT</pubDate>
            <description><![CDATA[## 2022年度总结

![cover](https://src.wuh.site/2022-02/2022-02-08-124302.png)

> 不要停步不前，每一天都要做出一点改变。

在开始分析之前，我想是不是需要一些数据模型来判断，在2021-2022年度我的个人发展是曲折向前的呢，还是原地踏步呢？

回头一想，还是算了吧。没有必要这么卷自己了，下面的数据留给阅读者自]]></description>
            <content:encoded><![CDATA[<h2>2022年度总结</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/f2f3e6b5c69372e759e61287dcbe9b5cd30515de83ee79e90ba1316becee419d/68747470733a2f2f7372632e7775682e736974652f323032322d30322f323032322d30322d30382d3132343330322e706e67"><img src="https://camo.githubusercontent.com/f2f3e6b5c69372e759e61287dcbe9b5cd30515de83ee79e90ba1316becee419d/68747470733a2f2f7372632e7775682e736974652f323032322d30322f323032322d30322d30382d3132343330322e706e67" alt="cover" data-canonical-src="https://src.wuh.site/2022-02/2022-02-08-124302.png" style="max-width: 100%;"></a></p>
<blockquote>
<p>不要停步不前，每一天都要做出一点改变。</p>
</blockquote>
<p>在开始分析之前，我想是不是需要一些数据模型来判断，在2021-2022年度我的个人发展是曲折向前的呢，还是原地踏步呢？</p>
<p>回头一想，还是算了吧。没有必要这么卷自己了，下面的数据留给阅读者自己对比吧。</p>
<h3>阅读不是打发时间的一种消遣</h3>
<blockquote>
<p>书本之外的世界很大，书本之内的乾坤也不小。</p>
</blockquote>
<p>现在，我不爱和人谈论的内容之一就是: ”你最爱看什么的类型的小说“，那没有意义。</p>
<p>和去年一样的套路，还是先列出今年的书单吧：</p>
<ol>
<li>这个女人不寻常呀! -- 《两京十五日》</li>
<li>有的时候一本书名就是一段故事 -- 《西线无战事》</li>
<li>有很多人喜欢项羽，也有很多人喜欢刘邦，我不一样，我喜欢曹操~~ -- 《楚汉双雄》</li>
<li>三等、三惹的韵脚诗美如画，一如中国画的留白是留给观者的遐想，它的意境无边 --《天青色等烟雨》</li>
<li>《三国演义》是中国的，也是世界的，更是小日本学不会的~~ --《银河英雄传说》</li>
<li>狄仁杰的魅力，吸引了老外创作了这一系列的案件故事，尽管后面我看不太下去了 --《大唐狄公传》</li>
<li>完全放弃了，不看了 --《剑来》</li>
<li>孤独是自己最大的敌人吗？或许没有希望才是！--《一个叫欧维的男人决定去死》</li>
<li>我记得之前的系列原名是叫“谋杀官员”，在两年之前我很喜欢看，这次是重温。 --《高智商犯罪》</li>
<li>敲了一段话还是删除了，算了，他们是历史 --《五代十国的枭雄们》</li>
<li>等待与希望 --《基督山伯爵》</li>
<li>一半是吃人恶魔，一半是救赎神明，我应该怎么说呢，还是大家自己去看吧。 --《沉默的羔羊》</li>
<li>我看了后记才知道，这一部小说的诞生前后经过了四十年，小半个世纪打磨出来的故事集确实比《后续》看起来更有感觉，更精彩。 --《夜谭十记》</li>
</ol>
<p>人的耐心是有上限的，每一个人的上限都会不一样，甚至于每一个人在不同的时期面对相同的事情，其承受度都是弹性的，比如我对《剑来》的耐心已经消磨完了，越来越看不下去了。作者对其热门IP产品的消费是不是也要考虑一下读者的想法呀。</p>
<p>我喜欢古龙小说，他对笔下的大侠们战斗方式和战斗场景的描写极其简洁，往往几十个字就描述了一段精彩的战斗或者是前文铺下的伏笔，最后揭露出来让人大呼过瘾，只叫痛快。武侠小说和这种玄幻小说又有什么差异呢？这么多年过去了，我们仍然爱着古龙，和他笔下的那些大侠。</p>
<hr>
<p>《基督山伯爵》是本年度内耗时最长的小说。不得不说作者设计的一些场景起承转合，尤其是终章善有善报的结局，当然最让人受不了的是那种不缺钱的“钞能力”。</p>
<p><strong>等待和希望</strong>就是基督山伯爵一生的写照，他的上半生经历了被人陷害入狱，陷入了无尽的黑暗与等待之中。出狱后获得宝藏，在逍遥与复仇之间抉择，当然最后的结局是他复仇成功，那他呢？在复仇过程中，他的得与失孰多孰少呢？他失去的是那一个青春与活力的少年之心，在谋划复仇的过程中已经不复存在了。那他得到的呢？</p>
<p>所以他的上半生的关键字就是<strong>等待</strong>。</p>
<p>伯爵是一个善良的人，他宽恕了他的敌人，他原谅了背叛了他的恋人，他挽救了另一对陷入热恋的男女，同时他也拯救了自己。他不敢想一个高高在上的公主居然爱上了自己，当他带着公主乘帆远航，又回到了无边无垠的大海时，他在上半生失去的，在下半生重新得到了。人世间最幸福的事情莫过于失而复得。</p>
<p>所以他的下半生的关键字就是<strong>希望</strong>。</p>
<p>朋友们不要失去希望。</p>
<hr>
<p>我发现日本特别喜欢三国题材，不信你去看一看《银河英雄传说》。其故事架构计划和《三国演义》一毛一样，不同的是，其故事时代在未来，将战场嫁接到了太空。</p>
<p>刚开始我想看一看他能写出什么不一样的故事，现在一看，还是别了吧。看《三国演义》更加的原滋原味。</p>
<p>我在看电视剧”一计害三贤“时，看到了一条弹幕，汉大将军起于卫青而终于姜维，姜维别号“天水麒麟”。多酷啊！！！</p>
<p>而在姜维出场之前，那么多的风流人物，俱往矣！</p>
<hr>
<p>我在回乡的途中读完了《夜谭十记》的前五篇，在返程途中读完了后五篇。是巧合还是有意为之？我说不清了。</p>
<p>一群科员，一群无所事事的科员，一群喜欢乱扯谈的无所事事的科员，一群喜欢乱扯谈的无所事事的坐冷板凳的科员，最后留下了十记。</p>
<p>他们是那一个时代的缩影，流水的官老爷，铁打的科员，一成不变的是底层的劳苦大众。</p>
<p>峨眉山人，羌江钓徒，三家村夫，无是楼主，不第秀才，山城走卒，巴陵野老，穷通道士，野狐禅师，砚耕斋主，我还记得的这些科员的雅号，仿佛我也身在其中，他们带着令人心酸的往事，迎面走进屋来。</p>
<p>各位，容我先泡上一壶茶，再摆上几条板凳。来吧，开摆。</p>
<h3>一撇一捺之谓道</h3>
<p>“搬山计划”一直在继续，但是执行地断断续续。</p>
<p>我越来越喜欢写字，但是字一直写得不好看，以前信笺上的开头都写一句“见字如面”，如果我给一些朋友写信，那他们一定看不下去。</p>
<p>我知道字的结构要合理了，字才好看。用笔的力与势要中庸协调了，字的结构就合理了。但是我却不得入其门，我反思得出结果，其一练得少，其二路子野，其三任意潇洒，不循其法，不得其势，其四我再也没有那么多的精力了。</p>
<blockquote>
<p>过刚者易折，善柔者不败。</p>
</blockquote>
<p>“搬山计划”的最终目的就是训练自己，以中正平和为目标，磨练自己的冲动随性。半年多过去了，我个人认为还是得到了一些矫正。</p>
<p>一阴一阳之谓道，典出《易经》。我仔细地回味了一下，决定随意发挥一下，一撇一捺之谓道，以合方寸之间。</p>
<p>动与静两种态，就好比是阴与阳。互相成就，互相印证，此消彼长。</p>
<p>在自我磨练的过程中，我的“动”态慢慢地被消磨掉了，我的熵变低了，变得相对稳定了，换一句话说，我变得成熟了。</p>
<p>今年，我27岁了，我还很年轻，还有很多人没有遇见，很多事情没有经历。或许在不久的将来，我会选择冲冠一怒，也会选择沉默不言。</p>
<p>这是合理的，人不可能永远是被理性武装的动物，“动”和“静”就是一种动态的，互相侵略和互相抵御的过程。我甚至认为理性都是动态存在的状态，时间的不同，空间的不同，场景的不同，都是影响调整状态的元素。</p>
<h3>用到了哪些新玩意</h3>
<p><strong>redux</strong>家族中又多了一个新朋友，<strong>rematch</strong>。结构与dva相似，打算在三月份做一个音乐播放页面，与网页顶部的播放器控件联动。</p>
<p><strong>express</strong>阵营中也多了一个新朋友，<strong>nest</strong>。号称是nodejs化的spring boot，用了一下确实很简单，让我想起了很久之前的用过的angular，写起来很爽。</p>
<p>简单的玩了一下<strong>AST</strong>转换，玩的很吃力，不是很懂，有很多的问题没有解决，最大的问题就是，有很多问题出现了都不知道怎么描述我的问题，这才是最大的问题。</p>
<p><strong>github actions</strong>让自动化变得简单。github官网有一个菜单入口<strong>MarketPlace</strong>，没错里面就是一些常用的actions，具体怎么玩可以看github官方案例，也可以先看一下我的<a href="https://wuh.site/post/Github%20Actions%20%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%BA%94%E7%94%A8" rel="nofollow">Github Actions 自动部署应用</a>实现笔记。</p>
<p><strong>docker</strong>让我的应用部署起飞。我的应用已经全部docker化了，可以先看一下我的实现<a href="https://wuh.site/post/Docker%E9%95%9C%E5%83%8F%E7%9A%84%E5%88%B6%E4%BD%9C%E4%B8%8E%E4%BD%BF%E7%94%A8" rel="nofollow">Docker镜像的制作与使用</a>。</p>
<p><a href="https://binaryify.github.io/NeteaseCloudMusicApi/#/?id=neteasecloudmusicapi" rel="nofollow">NeteaseCloudMusicApi</a>支持了音乐播放列表的后台动态控制。我的播放列表终于不再裸奔了。</p>
<p><strong>mongodb</strong>嗯~~暂时没什么，好像有一些新的比较好玩的工具，没时间去试。</p>
<p><strong>nginx-js</strong>可以用js的语法去配置nginx了，这个不错，我想去尝试一下，刚好马上证书到期了，这个很期待。</p>
<p><strong>webComponent</strong>仔细看了一下github的网站结构，我发现好像github早就开始使用webcomponent了。试玩了一下，感觉还是很不错的，要是可以把组件的事件代理解决一下就好啦，如同react一般地去使用component元素。</p>
<p><strong>preact</strong>相当舒服的react mini版本，基本适配了react的全部api，使用起来还是不错的。</p>
<p><strong>webpack5 和 vite</strong>今年的明星项目莫过于vite了，试了一下vite+v3感觉相当棒，顺便把之前搭过的微前端的基座应用换成了vite。</p>
<h3>B站的神奇之旅</h3>
<p>在去年我看过了一系列的纪录片，相比现在的一些电视剧，纪录片都比他们有意思。</p>
<p>卸载抖音我丝毫没有犹豫，那没什么大不了，但是b站让我很难做呀。</p>
<p>我几乎每天都混迹在B站，今年的我很幸运见证了最快百万王冰冰，可鸽可泣小约翰。美食主播盗月社带给我的是快乐，嘉佑生宣让我重新认识了那些课本上的熟人，想不到短短的一句“庆历四年春”的背后居然还有这么多的波折。</p>
<p>我喜欢《深夜食堂》，也说不出究竟喜欢哪里，或者是喜欢哪一些人，可能只是喜欢日剧夏日午后般的平淡。尤其推荐《凡人修仙传》，看的很爽，真的很不错。</p>
<p>《肖申克的救赎》是我每年必看的电影，他提醒着我无论在什么环境里面生活多久也不要放弃自己，永远保持希望，不要被环境同化。</p>
<p>《怦然心动》令人触动，我到哪里去找我的初恋，你大爷的，为什么我现在才看这部电影~~</p>
<p>《戚继光》短短的六集所展现的内容比起那些三十几集连续剧强太多了，我觉得电视剧可以退出历史舞台了，把钱拿来做方块人都比他强。</p>
<p>《湮灭》根据《遗落的南境》改编，说实话很受震撼，但是电影最后所表达的究竟是什么意思，顶塔消失了，他们已经是新人类了，始终牢记<strong>是反射而非复制</strong>。</p>
<p>更离谱的是，可以看到各大高校的课程分享，我已经在b站看过了好几个up主赏析《红楼梦》，而且讲起来条条是道，很感慨啊，我还是书读少了。因为我看到的和别人看到的差别居然这么大。</p>
<p>除此之外，我还在b站里面找到了一些专业相关的课程，有关于nodejs、mongodb、flutter和docker。学习的平台已经搭建好了，接下来就是看自己寻找靠谱的视频资料了。</p>
<p>直播行业将会是这个娱乐时代中最普遍的职业，门槛最低的职业。只需要一台手机就可以开启直播了，我试着玩了一下B站的直播，操作很简单。当然有时间会看一下游戏直播，我最近很喜欢iwanna这个游戏，注意可不是喜欢玩，是喜欢看别人玩。</p>
<h3>我在云村待了2000多个小时</h3>
<p>如何开启自我保护机制？如果没有答案，那就戴上耳机。</p>
<p>每天早上醒来，已经形成了一种习惯，首先打开网抑云，随机播放。出门时戴上耳机，隔绝了整个世界。如果可以打字交流，绝不会说话。</p>
<p>我沉迷在《金风玉露》当中无法自拔，它真的很好听~~</p>
<p>笛声悠长，散播这无尽的缠绵哀怨。我看到歌名就联想到了“金风玉露一相逢，便胜却人间无数”，不知道他在期待着什么，只知道留下的是如汉水般连绵不绝的遗憾。</p>
<p>来，拿出笛子，先来一个欢快的，让大家折磨一下。</p>
<h3>反思</h3>
<blockquote>
<p>遇到问题不暴露，暴露之后不解决，解决之后不总结，总结之后不记录，等于这个问题我从未经历，从未解决。</p>
</blockquote>
<p>各位客官，别太相信自己的大脑，它的存储保质期真不太长~~</p>
<p>现在真实地发生在自己的身上，是因为年纪的关系还是其他的问题，很多东西长时间不去接触，再次谈论的时候我发现，我的记忆是一片空白。很多问题分明之前已经解决过，但是一些重复问题还是需要去google一下。</p>
<p>所以现在遇到问题了，我会提前把问题截图记下来，相关的google链接也会记下来，提供一些简洁的描述，增强自己的记忆力。它就是我的问题检索索引，最重要的是，不要简单的复制粘贴，手敲一下增强记忆。</p>
<p><strong>不求甚解的理念不适合专业性较强的问题</strong>。业务相关、专业相关的文章应该持有的态度应该是庖丁解牛，而不是不求甚解。我现在一直在看之前群里发的一些面试题，并不是为了准备面试，而是面试题里面体现出了很多我不会，不了解的东西。我认为<strong>专精</strong>是专业性文章的指导方针。</p>
<p><strong>记录和归类</strong>貌似也是一个学科，每一个人都需要自己去寻找适合自己的方式，以达到构建一种高效的储存和读取模型。我曾经在b站上面看到了一个分类的视频，看到之后很受教育，但是我现在仍然在摸索的过程中。</p>
<p>分析问题，一般我是围绕几个点：“是什么？为什么？怎么做？”。首先分析一下他是什么类型的问题，我之前是不是也遇到过类似的问题，那样就可以快速检索得出结果。既然是与之前遇到的问题相似，那它为什么表现出了一个独有的特性，那是不是也有其他的问题延伸出来。最后已经列出了全部的线索，结合一下前期的遇到的问题和解答步骤，尝试做出针对当前问题的解答。</p>
<p><strong>从分析问题到得出结果</strong>，它是一个过程。能不能分析出什么问题是前期准备，能不能解决问题是最终结果。也许很多情景下，我的能力不足以解决我分析出来的结果，但是我相信一定有解决这些问题的高人存在。所以，有没有解决问题的能力，并不影响我尝试分析问题。</p>
<h3>阶段性结束了</h3>
<p>又一年结束了。</p>
<p>我还是一如往常，没有长进，没有改变，孤身一人。</p>
<p>乾上坤下，又一年开始了。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Github Actions 自动部署应用]]></title>
            <link>https://wuh.site/post/36</link>
            <guid>36</guid>
            <pubDate>Mon, 13 Dec 2021 13:59:22 GMT</pubDate>
            <description><![CDATA[## 认识Github Actions

![](https://src.wuh.site/2021-12/2021-12-13-135531.png)

> 什么是github actions? 我们可以使用github actions做一些什么事情?怎么实现我们的需求?

我们在日常的开发过程中，部署过程中或者是更新日志的发布，一定会重复地执行一些操作。我一直在寻找和尝试一些简单、]]></description>
            <content:encoded><![CDATA[<h2>认识Github Actions</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ab14701461467128ac467b5798454c479efcdb1bd6f3a5eb6d4439033ef8c79c/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d31332d3133353533312e706e67"><img src="https://camo.githubusercontent.com/ab14701461467128ac467b5798454c479efcdb1bd6f3a5eb6d4439033ef8c79c/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d31332d3133353533312e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-13-135531.png" style="max-width: 100%;"></a></p>
<blockquote>
<p>什么是github actions? 我们可以使用github actions做一些什么事情?怎么实现我们的需求?</p>
</blockquote>
<p>我们在日常的开发过程中，部署过程中或者是更新日志的发布，一定会重复地执行一些操作。我一直在寻找和尝试一些简单、自动化的操作，免去一些重复操作。</p>
<p>首先说明，我也是头一次运用github actions，不过是在完成了一些操作之后，反过头来记录一些我是怎么做的。</p>
<h3>什么是Github Actions</h3>
<p>先从一个简单的配置文件，来认识一下github actions。<code class="notranslate">.github/workflows/first.yml</code></p>
<div class="highlight highlight-source-yaml"><pre class="notranslate"><span class="pl-ent">name</span>: <span class="pl-s">Github Actions Demo First</span>

<span class="pl-ent">on</span>: <span class="pl-s">[push]</span>

<span class="pl-ent">jobs</span>:
  <span class="pl-ent">logger</span>: 
    <span class="pl-ent">runs-on</span>: <span class="pl-s">ubuntu-latest</span>
    <span class="pl-ent">steps</span>:
      - <span class="pl-ent">name</span>: <span class="pl-s"><span class="pl-pds">'</span>runner task1<span class="pl-pds">'</span></span>
        <span class="pl-ent">run</span>: <span class="pl-s">echo 'actions runner task1'</span>
      - <span class="pl-ent">run</span>: <span class="pl-s">echo 'actions runner task2'</span>
      - <span class="pl-ent">run</span>: <span class="pl-s">echo 'actions runner task3'</span></pre></div>
<p>首先文件的类型是<code class="notranslate">yaml</code>,文件名的后缀是<code class="notranslate">yml</code>，所以我们需要提前学习一下yml的语法。其语法和json的语法很相似，上面的yml文件翻译为json，其实就是这个样子:</p>
<div class="highlight highlight-source-json"><pre class="notranslate">{
  <span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>Github Actinon Demo First<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"on"</span>: [<span class="pl-s"><span class="pl-pds">"</span>push<span class="pl-pds">"</span></span>],
  <span class="pl-ent">"jobs"</span>: {
    <span class="pl-ent">"logger"</span>: {
      <span class="pl-ent">"runs-on"</span>: <span class="pl-s"><span class="pl-pds">"</span>ubuntu-latest<span class="pl-pds">"</span></span>,
      <span class="pl-ent">"steps"</span>: [
        {
          <span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>runner task1<span class="pl-pds">"</span></span>,
          <span class="pl-ent">"run"</span>: <span class="pl-s"><span class="pl-pds">"</span>echo 'actions runner task1'<span class="pl-pds">"</span></span>
        },
        {
          <span class="pl-ent">"run"</span>: <span class="pl-s"><span class="pl-pds">"</span>echo 'actions runner task1'<span class="pl-pds">"</span></span>
        },
				{
          <span class="pl-ent">"run"</span>: <span class="pl-s"><span class="pl-pds">"</span>echo 'actions runner task1'<span class="pl-pds">"</span></span>
        }        
      ]
    }
  }
}</pre></div>
<p>只要是在语句之前加上<code class="notranslate">-</code>号，那么它的父级会自动解析为数组，在<code class="notranslate">:</code>之后的换行符会解析为对象。其语法对比json来讲，<strong>更加简单</strong>。</p>
<p>不出意外，其执行成功的结果就是这个样子:</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/53c43a67ad516b59d6e0b38d32d8fba679e9041eb824756704621cb709b46b2f/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30362d3132353432312e6a7067"><img src="https://camo.githubusercontent.com/53c43a67ad516b59d6e0b38d32d8fba679e9041eb824756704621cb709b46b2f/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30362d3132353432312e6a7067" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-06-125421.jpg" style="max-width: 100%;"></a></p>
<h3>文件的结构分析</h3>
<p>在github官方对github actions的文档描述看，上面的例子虽然简单，但是已经包含了事件流的基础元素。</p>
<ul>
<li>Workflows</li>
<li>Events</li>
<li>Jobs</li>
<li>Actions</li>
<li>Runners</li>
</ul>
<p>现在对比这么一看，跟我之前写过的<code class="notranslate">docker-compose</code>的文件结构相当相似。要知道上面的元素全部是复数，就是说可以有一个也可以有多个，只要保证了基本的结构不错误，那你可以随意的加多个任务。</p>
<p>需要注意的是，对于Jobs下的子任务，都需要指定<code class="notranslate">runs-on</code>属性，要不然会抛出：</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">ERRO[0000] <span class="pl-s"><span class="pl-pds">'</span>runs-on<span class="pl-pds">'</span></span> key not defined <span class="pl-k">in</span> Github Actions Demo First/tags </pre></div>
<p><strong>Workflows</strong>文件一般是放在<code class="notranslate">.github/workflows</code>文件夹内部，我看了好几个开源项目的文件目录大致上都是这样，因为github会自动拉取这个文件目录下以<code class="notranslate">.yml</code>结尾的文件作为任务文件。</p>
<p><strong>Events</strong>是一个关键点。下面我贴上两个地址，是github actions的官网上对于Events模块的描述。<a href="https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows">events-that-trigger-workflows</a>,<a href="https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#on">workflow-syntax-for-github-actions</a>。<code class="notranslate">on</code>可以监听到的事件官网上提供了一个索引表，和它们相关的写法和用法。同时不单单是对事件，还可以针对单独的分支进行事件监听。</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">name: Github Actions Demo Second

on: 
  push: 
    branches: 
      - main
  pull_request:
    branches:
      - main
  schedule:
    - cron: <span class="pl-s"><span class="pl-pds">'</span>/5 * * *<span class="pl-pds">'</span></span>
    
  jobs:
  	reb:
    	runs-on: ubuntu-latest
      steps: 
        - name: <span class="pl-s"><span class="pl-pds">'</span>push main<span class="pl-pds">'</span></span>
          run: <span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>push events<span class="pl-pds">'</span></span></pre></div>
<p><strong>Events.schedule</strong>定时任务。在文档上<code class="notranslate">schedule</code>出现的位相当靠前，估计这个是一个相当不错的特性。它的函数是一些云函数，官网给出了一些例子，但是我目前还没有测试，所以先放着，以后再玩。</p>
<p><strong>Jobs</strong>和它的一系列参数列表和<a href="https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idenv">语法</a>。Jobs是Github Actions最核心的元素了吧，我们需要的各种各样的功能能不能实现，怎么实现就依赖于怎么实现。其中，我们比较关注就是一些环境变量问题。<code class="notranslate">env</code>提供了这一功能，另外<code class="notranslate">use</code>和<code class="notranslate">with</code>成对使用。</p>
<p>其中，介绍Jobs任务的另一种使用，串联。任务可以是单行，也可以是多个任务有先后、互相依赖的关系存在。所以在github actions中提供了<strong>jobs.jobs_id.needs</strong> 这个配置项，让我们可以个性化配置。使用方法也简单</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">jobs: 
	reb: 
		runs-on: ubuntu-latest
		needs:
			- first_task
			_ second_task
		steps:
			- name: <span class="pl-s"><span class="pl-pds">'</span>thrid_task<span class="pl-pds">'</span></span>
			- run: <span class="pl-c1">echo</span> <span class="pl-s"><span class="pl-pds">'</span>thrid_task<span class="pl-pds">'</span></span></pre></div>
<p><code class="notranslate">jobs.jobs_id.runs-on</code>表示在哪一个虚拟机执行任务。 现在提供的虚拟机，可能我们日常使用<code class="notranslate">ubuntu</code>就够了。它有以下几个选项，可能以后还会再增加。</p>
<markdown-accessiblity-table><table role="table">
<thead>
<tr>
<th>虚拟机</th>
<th>Runs-on label</th>
</tr>
</thead>
<tbody>
<tr>
<td>Windows Server 2022</td>
<td>windows-2022</td>
</tr>
<tr>
<td>Windows Server 2019</td>
<td>windows-latest</td>
</tr>
<tr>
<td>Windows Server 2016</td>
<td>windows-2016</td>
</tr>
<tr>
<td>Ubuntu 20.04</td>
<td>ubuntu-latest</td>
</tr>
<tr>
<td>Ubunti 18.04</td>
<td>ubuntu-18.04</td>
</tr>
<tr>
<td>macOS Big Sur 11</td>
<td>macos-11</td>
</tr>
<tr>
<td>macOS Catalina 10.15</td>
<td>macos-latest</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<h3>Docker 的自动编译和推送</h3>
<blockquote>
<p>这是一个github 官方提供的例子，actions来自于docker官方仓库。</p>
<p>可以查看我的<a href="https://github.com/stack-wuh/wuh.site/blob/main/.github/workflows/docker-push.yml">编译yml</a>，也可以直接查看github<a href="https://docs.github.com/cn/actions/publishing-packages/publishing-docker-images#">官方例子</a>。对比一下，你就会发现没有什么太大的差异，只是我换成了分支名，而github例子使用的hashid。</p>
</blockquote>
<p>因为需要上传Docker Image镜像到Docker Hub，可以使用由docker官方提供的几个actions：</p>
<ol>
<li>docker/login-action 登录用，只有登录状态下才可以推送镜像</li>
<li>docker/metadata-actions 配置image的版本号</li>
<li>docker/build-push-action 编译和推送</li>
</ol>
<h3>Release 版本更新</h3>
<p>不得不承认，有很多的工作或者是操作都可以用一些工具自动生成。比如，我现在项目的更新日志，仍然还是在本地执行脚本，生成日志之后再推送到github。</p>
<p>每一次更新，发布release版本时，还需要把本次更新的内容复制粘贴到版本说明中。看起来可以改变一下，让这一步工作自动化进行。</p>
<p>版本更新CI/CD的一个重要环节，其价值不可谓不巨大，可以极其方便地控制一些手动操作。尽管现在有一个工具可以了本地测试，但是还是有缺陷，在我做完了全部的流程之后，我回过头来仔细分析了一下。我之所以干的这么不顺利，就是因为我不太了解linux和虚拟机相关的知识。</p>
<p>另外不太熟悉github actions相关的进阶的玩法。由此可见，我这种英语不行，我看着文档上面例子，也可以做出一些我想要的功能。另外也归功于github actions的仓库，里面准备了一大批日常使用的功能，完全解决了我的需求。</p>
<p>现在介绍使用的actions:</p>
<pre class="notranslate"><code class="notranslate">+ **actions/checkout@v2** 应该算是使用频率最高的actions了吧，只要是涉及到了git相关的操作就离不开它
+ actions/setup-node@v1 选择任务执行的nodejs版本，可以控制其版本号
+ **release-drafter/release-drafter@v5** 生成release notes的一个actions，可以生成这个版本号的提交日志
+ **appleboy/ssh-action@master** 服务器登录执行指令
</code></pre>
<p>注意:</p>
<pre class="notranslate"><code class="notranslate">1. 在使用release-drafter的过程中，必须使用pull_request 这样才可以拿到每一次分支的更新日志
1. appleboy/ssh-action 需要注意的是有多种连接服务器的方式，如果使用的用户名+密码，需要查看远程服务器的是否支持连接
1. 如果条件允许，还是拆分多个任务比较好，不要都写在一个任务里面
</code></pre>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ClashX 的使用记录]]></title>
            <link>https://wuh.site/post/35</link>
            <guid>35</guid>
            <pubDate>Sun, 05 Dec 2021 02:17:45 GMT</pubDate>
            <description><![CDATA[## ClashX 的使用记录

![](https://src.wuh.site/2021-12/2021-12-05-021507.png)

我之前用的是google浏览器的的一个插件，大多数朋友可能都有用过，就是**GHelper**。

但是在公司内部，不知道出于什么原因，也可能是内网的原因，这个插件失效了。所以只能另寻他法，终于找到了一个几乎不用啥配置的工具，但是也需要交一]]></description>
            <content:encoded><![CDATA[<h2>ClashX 的使用记录</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ce5b9ef314ce17515db58ad78bd65ff4ffcfc02c7940ab3a9702f1d289ddcaaf/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30352d3032313530372e706e67"><img src="https://camo.githubusercontent.com/ce5b9ef314ce17515db58ad78bd65ff4ffcfc02c7940ab3a9702f1d289ddcaaf/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30352d3032313530372e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-05-021507.png" style="max-width: 100%;"></a></p>
<p>我之前用的是google浏览器的的一个插件，大多数朋友可能都有用过，就是<strong>GHelper</strong>。</p>
<p>但是在公司内部，不知道出于什么原因，也可能是内网的原因，这个插件失效了。所以只能另寻他法，终于找到了一个几乎不用啥配置的工具，但是也需要交一点点保护费。</p>
<h3>Mac上使用</h3>
<p>在Mac上使用特别的简单，因为我本身的意愿就是找一个零配置的工具。</p>
<p>而且，Clashx在Mac上的表现也相当的亮眼，颜值还是不错的。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/2621c95f5370fa5707afb64b5490c01b518d0c2026162a9970888207efeb7095/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d31322d30342d3032303031382e6a7067"><img src="https://camo.githubusercontent.com/2621c95f5370fa5707afb64b5490c01b518d0c2026162a9970888207efeb7095/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d31322d30342d3032303031382e6a7067" alt="clashx-setting" data-canonical-src="https://src.wuh.site/2021-08/2021-12-04-020018.jpg" style="max-width: 100%;"></a></p>
<p>在交保护费的平台拿到clash的订阅地址，点开菜单栏的猫头，找到配置-&gt;托管配置-&gt;管理。把你的clash订阅地址贴到管理里面，之后更新列表，不出意外的话，在成功更新之后就可以看到代理服务器列表了。<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1eb03d468dd6c1f9f3e67a412f5f6a5b48a3b04b9c4c3f5137ae31d48824e958/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3032343135372e706e67"><img src="https://camo.githubusercontent.com/1eb03d468dd6c1f9f3e67a412f5f6a5b48a3b04b9c4c3f5137ae31d48824e958/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3032343135372e706e67" alt="dingyue" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-024157.png" style="max-width: 100%;"></a></p>
<p>我选择的代理模式是规则模式，打开系统代理之后。打开浏览器输入google看一下，不出意外现在是可以访问外网了。</p>
<p>这是不同于win10平台的一点，在window平台上，用浏览器的无痕模式可以直接访问外网，但是普通模式不可以，还需要用switchomage这个插件做转发。<strong>真是有够麻烦的</strong>。</p>
<p>最后，附上clashx在Mac平台的下载地址<a href="https://github.com/yichengchen/clashX/releases/download/1.72.0/ClashX.dmg" title="clashX">clashX</a>，版本号是<strong>1.72.0</strong>。在Mac上使用极其简单的，几乎没有费什么工夫就成功的跑了起来，完全没有遇到什么麻烦。</p>
<h3>window10 的 Clash</h3>
<p>在window平台的上的客户端不再是ClashX，而是Clash。都是一家人没什么太大的区别，都是基于go。不得不说，在各个平台使用Clash都很简单，几乎没遇到什么大的麻烦，但是在window上需要多处理一点。</p>
<p>在这里附上Clash的下载地址<a href="https://github.com/Fndroid/clash_for_windows_pkg/releases" title="clash_for_window">clash_for_window</a>(<a href="https://github.com/Fndroid/clash%5C_for%5C_windows%5C_pkg/releases)%E3%80%82%E8%AF%A5%E9%93%BE%E6%8E%A5%E6%9D%A5%E8%87%AA%E4%BA%8E**github**%EF%BC%8C%E8%AF%B7%E6%94%BE%E5%BF%83%E4%BD%BF%E7%94%A8%E3%80%82">https://github.com/Fndroid/clash\_for\_windows\_pkg/releases)。该链接来自于**github**，请放心使用。</a></p>
<p>首先，如果没有买飞机票，请先交保护费买一张飞机票，获得clash的订阅地址。另外还需要给google浏览器装一个插件<strong>Proxy switchyOmega</strong>。</p>
<h3>Android 的 Clash</h3>
<p>第一贴上<a href="https://github.com/Kr328/ClashForAndroid/releases">clash_for_android</a>的下载地址：<a href="https://github.com/Kr328/ClashForAndroid/releases%EF%BC%8C%E8%AF%A5%E9%93%BE%E6%8E%A5%E6%9D%A5%E8%87%AA%E4%BA%8E**github**%EF%BC%8C%E8%AF%B7%E6%94%BE%E5%BF%83%E4%BD%BF%E7%94%A8%E3%80%82">https://github.com/Kr328/ClashForAndroid/releases，该链接来自于**github**，请放心使用。</a></p>
<p>在进入app之后，引入眼帘还是熟悉的一个黑色的猫头。接下来的操作还是老一套，点开配置进入配置页之后，点击右上角**+**图标，会进入“创建配置”页。进入”创建配置”页之后，选择从URL导出，这里就是贴上clash的订阅地址。</p>
<p>完成这些操作之后，回到首页。看一下第一栏的文案，如果是“运行中”就表示已经正常代理了，打开手机浏览器，进入google浏览器，或者是打开twitter。如果是“已停止”就点击启动，不出什么以外，就可以正常使用了。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ede2f24ac14d9ec06716241e3e0688b1c2ec755b7d05fff4fb806d2736abaecc/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d323032313132303430322e706e67"><img src="https://camo.githubusercontent.com/ede2f24ac14d9ec06716241e3e0688b1c2ec755b7d05fff4fb806d2736abaecc/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d323032313132303430322e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-2021120402.png" style="max-width: 100%;"></a><br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fed7357fc182cfae24611a031750d7eae20700853aa6aa283e2cd44aed234e26/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d32303231313132303430332e706e67"><img src="https://camo.githubusercontent.com/fed7357fc182cfae24611a031750d7eae20700853aa6aa283e2cd44aed234e26/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d32303231313132303430332e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-20211120403.png" style="max-width: 100%;"></a></p>
<p>手机上的操作就这么简单。</p>
<p>只要是找的源足够靠谱，那代理的网速应该差不了多少，足够日常的使用。</p>
<p>注意：</p>
<ol>
<li><a href="https://merlinblog.xyz/wiki/ClashX.html" title="macos clashx教程" rel="nofollow">clashx教程 — MacOS</a></li>
<li><a href="https://youyun222.net/user" title="优云666" rel="nofollow">飞机场-优云666</a></li>
<li><a href="http://www.caogon.com/auth/register" title="飞世云" rel="nofollow"> 飞机场-飞世云 </a></li>
</ol>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[基于TS重构NextJs应用]]></title>
            <link>https://wuh.site/post/34</link>
            <guid>34</guid>
            <pubDate>Sun, 05 Dec 2021 01:54:06 GMT</pubDate>
            <description><![CDATA[## 基于TS重构NextJs应用

![](https://src.wuh.site/2021-12/2021-12-05-020136.png)

> 在10.1的假期中，我用TS重写了博客的前端应用，同时用sass改写了全部组件的样式。对于组件的设计，全部借鉴于ant design的设计规范和开发规范。

第一版的Next应用写的不是很满意，很多代码和实现都不是我喜欢的那一种。恰]]></description>
            <content:encoded><![CDATA[<h2>基于TS重构NextJs应用</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a2d45de7095cfbf8f0af5f1f56dffa7958c0b0c61de888f654ac01da28ab075c/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30352d3032303133362e706e67"><img src="https://camo.githubusercontent.com/a2d45de7095cfbf8f0af5f1f56dffa7958c0b0c61de888f654ac01da28ab075c/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30352d3032303133362e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-05-020136.png" style="max-width: 100%;"></a></p>
<blockquote>
<p>在10.1的假期中，我用TS重写了博客的前端应用，同时用sass改写了全部组件的样式。对于组件的设计，全部借鉴于ant design的设计规范和开发规范。</p>
</blockquote>
<p>第一版的Next应用写的不是很满意，很多代码和实现都不是我喜欢的那一种。恰逢10.1假期，改写了大部分的组件的代码。</p>
<p>由于近期的工作比较多，平时又很累一直没顾得上写一写，这一次重写遇到的问题和解决的方法，以及对整个应用工程化的实现的记录。现在已经过去了两个多月了，很多细节已经回想不起来了。没办法，只能看着现在的代码总结一下。</p>
<h3>提交规范</h3>
<p>无论我们做任何项目，从规范代码提交的开始，应该是对整个项目最负责的体现。</p>
<p>不知道从什么时候开始，我个人的提交规范就朝着angular的方向了。我记得当时我看了一篇讲述angular提交规范的博客，当时一看顿时觉得仪式感太强了，整个commit记录一眼看过去相当整齐，从那时起，我觉得angular规范是最好的。</p>
<p>代码规范和样式美化选用 <em>prettier</em> 和 <em>eslint</em> 。代码的样式美化和统一，给我的感觉就是舒服。这里没什么可以说的，网上的教程一大把，但是我偷懒了，对于react的规则，我用是的umijs的规则，当然nextjs自身的规则继续保留。</p>
<p>只要是严格的遵循了angular的提交规范，就可以使用<a href="https://github.com/conventional-changelog/conventional-changelog"> conventional-changelog </a>工具，快速的生成本次发布的版本的更新日志，这里附上近期的<a href="https://github.com/stack-wuh/wuh.site/releases">更新日志</a>。大致就是以下这个样子，看起来就是满满的仪式感。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/41e9f979fd56cd57e4fa824499c45d2dfc285e589d604c6fb9247d662225b33a/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3037303330362e706e67"><img src="https://camo.githubusercontent.com/41e9f979fd56cd57e4fa824499c45d2dfc285e589d604c6fb9247d662225b33a/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3037303330362e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-070306.png" style="max-width: 100%;"></a></p>
<p>Github Actions用起来的感觉就是一个字，太爽了！之前一直不会用，一直在研究到底是怎么玩的。直到看阮老师的博客，发现了一个新的工具<a href="https://github.com/nektos/act">act</a>，可以在本地调试github actions。可以监听git的merge事件，来做一些自动化操作。</p>
<p>所以现在，我把主分支切成了main分支，每一次的功能迭代改为pull merge操作。因为我看到了next的官网上有推荐，可以使用Vercel持续集成应用，这样每一次的merge操作就可以自动发布到Vercel容器了。</p>
<h3>组件的设计规范</h3>
<p>基本原则还是遵照我之前的总结<a href="https://wuh.site/post/%E6%B5%85%E5%B0%9D%E4%B8%80%E4%B8%8BUI%E8%AE%BE%E8%AE%A1" rel="nofollow">《浅尝一下UI设计》</a>，基本的设计不变，但是改成sass函数之后，整个css部分变得更加地整齐、清晰和简单。</p>
<p>这里不得不提到sass中的函数和混入，在sass的官网中有它们相当具体地实现。这次我用到的基本都是Map类型操作。我举一个相当简单的用例，实现组件的大中小三种类型的样式函数。文件名: <code class="notranslate">vars.scss</code></p>
<div class="highlight highlight-source-css-scss"><pre class="notranslate">	<span class="pl-v">$font-size-base</span>: <span class="pl-c1">14<span class="pl-k">px</span></span>;
	<span class="pl-v">$compose-base</span>: <span class="pl-c1">8<span class="pl-k">px</span></span>;
	<span class="pl-v">$sizes</span>: ((<span class="pl-c1">small</span>, <span class="pl-v">$font-size-base</span> <span class="pl-k">-</span> <span class="pl-c1">2<span class="pl-k">px</span></span>, <span class="pl-v">$compose-base</span> <span class="pl-k">*</span> <span class="pl-c1">0.5</span>),
	  (<span class="pl-c1">middle</span>, <span class="pl-v">$font-size-base</span>, <span class="pl-v">$compose-base</span>),
	  (<span class="pl-c1">large</span>, <span class="pl-v">$font-size-base</span><span class="pl-c1">+</span><span class="pl-c1">2<span class="pl-k">px</span></span>, <span class="pl-v">$compose-base</span><span class="pl-c1">*</span><span class="pl-c1">2</span>));
	
	<span class="pl-k">@mixin</span> <span class="pl-en">getSizes</span> () {
	
	  <span class="pl-k">@each</span> <span class="pl-v">$size</span>,
	  <span class="pl-v">$fontsize</span>,
	  <span class="pl-v">$padding</span> <span class="pl-k">in</span> <span class="pl-v">$sizes</span> {
	    <span class="pl-e">.is-<span class="pl-v">#{<span class="pl-v">$size</span>}</span></span> {
	      <span class="pl-c1"><span class="pl-c1">font-size</span></span>: <span class="pl-v">$fontsize</span>;
	      <span class="pl-c1"><span class="pl-c1">padding</span></span>: <span class="pl-v">$padding</span>;
	    }
	  }
	}</pre></div>
<p>在调用<code class="notranslate">getSizes</code>函数之后，自动生成了<code class="notranslate">.is-small</code>、<code class="notranslate">.is-middle</code>和<code class="notranslate">.is-large</code>三个类名，对应着组件的三种大小状态。在此处我只定义了<code class="notranslate">基本字体大小</code>和<code class="notranslate">内边距</code>两种属性，如果需要扩展属性，可以很轻易地实现。</p>
<p>其编译之后的代码如下:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fca685e6ce01f731288fe1e2e2e810fa0b5f409864c595b6056177205ff5d95d/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3037333531362e706e67"><img src="https://camo.githubusercontent.com/fca685e6ce01f731288fe1e2e2e810fa0b5f409864c595b6056177205ff5d95d/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3037333531362e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-073516.png" style="max-width: 100%;"></a></p>
<p>所以，我们可以借助类似的一些自定义函数，在快速完成我们样式代码的同时减少代码量。less和sass其功能相差不大，基本功能都可以实现，具体的一些功能函数可以参考ant的代码实现。</p>
<h3>React.FC 全函数式组件的实现</h3>
<p>完全舍弃类组件，全部由函数式组件构建。</p>
<p>如果你不会做，不妨跟着会做的人做。</p>
<p>在本次更新中，很多组件都是模仿ant。包括对于TS的使用下的React组件定义，自定义组件对外暴露的属性，组件内部classname的命名和条件渲染，大量代码都借鉴了ant。</p>
<p>Hooks的实现借鉴了另一个开源库<code class="notranslate">ahooks</code>，但是hooks文件的规则还是沿用umijs。</p>
<p>当然，audio的单例模式实现也发生了一些变化。在init阶段的单例实现没有任何变化，但是我创建了一个全局的context，在这个context中新建了ref来保存audio实例。整个应用似乎不太需要Redux。</p>
<p>主题切换，不再使用原方案，改为使用脚本实现。同时，bubble泡泡也改为使用脚本实现。你可以直接下载<a href="https://src.wuh.site/scripts/bubble.js" rel="nofollow">bubble.js</a>(<a href="https://src.wuh.site/scripts/bubble.js)%E8%84%9A%E6%9C%AC%E4%BD%93%E9%AA%8C%E3%80%82" rel="nofollow">https://src.wuh.site/scripts/bubble.js)脚本体验。</a></p>
<h3>Accessibility 可访问性指标</h3>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d923c21f7405672a34bed82029d6b910195c959d4416dc9d609a0ed5ca75c6b5/68747470733a2f2f7372632e7775682e736974652f636f6d6d6f6e2f617269612e706e67"><img src="https://camo.githubusercontent.com/d923c21f7405672a34bed82029d6b910195c959d4416dc9d609a0ed5ca75c6b5/68747470733a2f2f7372632e7775682e736974652f636f6d6d6f6e2f617269612e706e67" alt="aria" data-canonical-src="https://src.wuh.site/common/aria.png" style="max-width: 100%;"></a><br>
在google浏览器的性能测试工具中，就有_Accessibility_指标。在ant的实现中，我们可以发现<code class="notranslate">role</code> 和 <code class="notranslate">aria-*</code> 属性。当时我看到的时候很迷惑，因为我从来没见到过html元素的属性中，有role这个属性。知道后来我听了_《重学前端》_这门课，我才知道原来是这么回事。</p>
<p>除此之外，还有键盘的可访问性，那就是<code class="notranslate">tabindex</code>。其对应的键盘按件就是<code class="notranslate">tab</code>键。在对一个html元素配置该属性之后，就可以通过<code class="notranslate">tab</code>键聚焦。如下:</p>
<div class="highlight highlight-text-html-basic"><pre class="notranslate">  <span class="pl-kos">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">tabindex</span>='<span class="pl-s">0</span>'<span class="pl-kos">&gt;</span>hello<span class="pl-kos">&lt;/</span><span class="pl-ent">div</span><span class="pl-kos">&gt;</span></pre></div>
<p>我们都知道在Html5 中发布了一些新的元素，这一些元素被称之为<strong>语义化标签</strong>，我记得在当时，我是完全用section标签取代了div标签。现在我的大部分标签改回了div。</p>
<p>所以，在一轮的重构中，我对大量的元素加入了role属性，覆盖率大致上达到了80%。只要是涉及到了可交互的组件基本上完成了配置。页面可点击按钮全部换成button元素和a元素。</p>
<p>或许，我们都应该听老师傅的话：<strong>如果你不知道的怎么用语义化标签，那就不要用</strong></p>
<h3>App的结构化优化，NextSEO和点击事件上报</h3>
<p>一个网站的SEO是极其重要的，所以在一次的重构中，我选择了<strong>NextSEO</strong>库，不再使用自己维护的代码实现。这个仓库满足了我全部的需求，因为我只需要配置google结构化，标题，关键字这一些属性，其他的我并不需要。</p>
<p>Gtag可以完成满足我的上报需求。首先我对页面的按钮进行了基础分类，大致分为了: <code class="notranslate">normal</code>、<code class="notranslate">loadmore</code>、<code class="notranslate">link</code>、<code class="notranslate">share</code>、<code class="notranslate">behivor</code>。这样，我完成了页面点击按钮的事件上报。</p>
<p>接口上报还没来得及做，现在我的服务后台换成了Nest应用，很多功能都没有时间去做。</p>
<h3>自动化构建，Docker的一键更新和发布</h3>
<p>我优化了<code class="notranslate">Dockerfile</code>构建文件，改成了分段式构建。</p>
<p>早前我是自己的野路子，能把应用跑起来就行，但是后来我发现，构建的Docker镜像太大了，感觉告诉我有点点不太对劲儿。在我改了构建文件之后，现在我的镜像的体积是91M。</p>
<p>构建步骤大致分为三个阶段: 初始化、构建、运行时。</p>
<p>本次升级内容，如下：</p>
<ol>
<li>不再使用npm, 改为使用yarn</li>
<li>改为使用ali的镜像源，减少依赖的安装时间</li>
<li>安装<code class="notranslate">jq</code>一个json文件的解析工具</li>
<li>改为分段式构建</li>
</ol>
<div class="highlight highlight-source-shell"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> ==================== Deps ==============</span>
<span class="pl-c"><span class="pl-c">#</span> =================== 安装依赖 =============</span>
FROM mhart/alpine-node as deps
LABEL maintainer = <span class="pl-s"><span class="pl-pds">"</span>shadow [wuh131420@gmail.com][6]<span class="pl-pds">"</span></span>
  
WORKDIR /usr/src/app
  
COPY package.json yarn.lock /usr/src/app/
  
RUN apk add jq
RUN npm config <span class="pl-c1">set</span> registry https://registry.npmmirror.com
RUN yarn
  
<span class="pl-c"><span class="pl-c">#</span> ================== Builder ================</span>
<span class="pl-c"><span class="pl-c">#</span> ================= 编译 ===================</span>
FROM mhart/alpine-node as builder
WORKDIR /usr/src/app
  
.......
  
<span class="pl-c"><span class="pl-c">#</span> ============== Runing ===========</span>
<span class="pl-c"><span class="pl-c">#</span> ============== 运行时 ===========</span>
FROM mhart/alpine-node AS runner
WORKDIR /usr/src/app
  
ENV NODE<span class="pl-cce">\_</span>ENV production
...
  
USER nextjs
  
EXPOSE 3000
  
CMD [<span class="pl-s"><span class="pl-pds">"</span>yarn<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>start<span class="pl-pds">"</span></span>]</pre></div>
<p>更为关键的是自动构建，自动升级和镜像清理脚本，结合一下<code class="notranslate">github actions</code>，一切都变得舒服了起来。</p>
<h3>RSS 聚合内容的实现</h3>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/0e67b62a158b2aa3d105f478e916dc28247656278d7af7765b4af349720eedfa/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3038343031312e706e67"><img src="https://camo.githubusercontent.com/0e67b62a158b2aa3d105f478e916dc28247656278d7af7765b4af349720eedfa/68747470733a2f2f7372632e7775682e736974652f323032312d31322f323032312d31322d30342d3038343031312e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-12/2021-12-04-084011.png" style="max-width: 100%;"></a></p>
<p>只要有优质的订阅源，我们完全可以只使用RSS阅读器，就可以享受阅读的乐趣。它是一个信息板，只关注我想关注的内容。所以现在的一些博客网站都会配置rss。</p>
<p>怎么配置实现rss就成了我们需要关注的内容啦。</p>
<p>在这里我推荐使用<a href="https://www.npmjs.com/package/feed" title="rss-feed" rel="nofollow">Feed</a>(<a href="https://www.npmjs.com/package/feed)%EF%BC%8C%E4%BD%86%E6%98%AF%E6%88%91%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%A8%8D%E6%9C%89%E4%B8%8D%E5%90%8C%E3%80%82" rel="nofollow">https://www.npmjs.com/package/feed)，但是我的实现稍有不同。</a></p>
<p>每一次更新博客之后，都需要更新维护的rss.xml文件，只有这个文件更新了，订阅器才会有更新推送。现在我把这个功能集成到了我的管理后台，我的feed文件托管在aliOSS，这个是我的<a href="https://src.wuh.site/common/rss.xml" rel="nofollow">feed</a>(<a href="https://src.wuh.site/common/rss.xml)%E3%80%82" rel="nofollow">https://src.wuh.site/common/rss.xml)。</a></p>
<h3>web worker 来一个自动切换主题的实现</h3>
<p>我用 <code class="notranslate">web worker</code> 注册一个时间轮询器，用于获取当前设备的时间。白天使用<code class="notranslate">light</code>模式，晚上变为<code class="notranslate">dark</code>模式。怎么让它们实现自动切换就是一个比较指的研究的问题啦。</p>
<p>难道要在主线程中加一个定时器，让它每次30分钟更新一次吗？</p>
<p>或许，有别的方式。在不占用主线程的资源的前提下，还可以监听时间的变化，在满足条件的前提下，切换网站的主题模式。</p>
<p>这是一个相当简单的实现，如果你感兴趣，可以在项目的源文件里面，查看相关的代码。</p>
<h3>图片格式转化为webp</h3>
<p><code class="notranslate">.webp</code>类型的文件，从文件可压缩的大小的比率上看具有相当的优势。但是目前为止，我只是把网站的背景图片和部分封面图改为了<code class="notranslate">.wepb</code>，大部分文件仍然还是<code class="notranslate">.png</code>。</p>
<p>来自于h5的新标签<code class="notranslate">picture</code>，提供了非常棒的降级方案，只需要配置额外的基础源就可以放心使用webp文件。</p>
<p>看起来，需要实现一下转换图片的格式了</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ssh免密登录]]></title>
            <link>https://wuh.site/post/33</link>
            <guid>33</guid>
            <pubDate>Sun, 07 Nov 2021 10:07:17 GMT</pubDate>
            <description><![CDATA[## ssh免密登录

![](https://src.wuh.site/2021-08/2021-11-07-ssh.001.jpeg)

免密登录，用到的就是一个公钥。如果之前在机器上用过github的ssh模式，那你一定还记得，秘钥生成到哪一个文件夹下了。



用到的指令就一个 **ssh-keygen**,几乎可以不用加任何参数，直接生成一对key文件: `id_rsa.]]></description>
            <content:encoded><![CDATA[<h2>ssh免密登录</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3cb10b2f7527edfea3870771769b01a7eb45800d8da2032589d2ff5711fea062/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d31312d30372d7373682e3030312e6a706567"><img src="https://camo.githubusercontent.com/3cb10b2f7527edfea3870771769b01a7eb45800d8da2032589d2ff5711fea062/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d31312d30372d7373682e3030312e6a706567" alt="" data-canonical-src="https://src.wuh.site/2021-08/2021-11-07-ssh.001.jpeg" style="max-width: 100%;"></a></p>
<p>免密登录，用到的就是一个公钥。如果之前在机器上用过github的ssh模式，那你一定还记得，秘钥生成到哪一个文件夹下了。</p>
<p>用到的指令就一个 <strong>ssh-keygen</strong>,几乎可以不用加任何参数，直接生成一对key文件: <code class="notranslate">id_rsa.pub</code>和<code class="notranslate">id_rsa</code></p>
<div class="highlight highlight-source-shell"><pre class="notranslate">ssh-keygen --help

 usage: ssh-keygen [-q] [-b bits] [-C comment] [-f output_keyfile] [-m format]
                  [-N new_passphrase] [-t dsa <span class="pl-k">|</span> ecdsa <span class="pl-k">|</span> ed25519 <span class="pl-k">|</span> rsa]
       ssh-keygen -p [-f keyfile] [-m format] [-N new_passphrase]
                   [-P old_passphrase]
       ssh-keygen -i [-f input_keyfile] [-m key_format]
       ssh-keygen -e [-f input_keyfile] [-m key_format]
       ssh-keygen -y [-f input_keyfile]
       ssh-keygen -c [-C comment] [-f keyfile] [-P passphrase]
       ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]
       ssh-keygen -B [-f input_keyfile]
       ssh-keygen -D pkcs11
       ssh-keygen -F hostname [-lv] [-f known_hosts_file]
       ssh-keygen -H [-f known_hosts_file]
       ssh-keygen -R hostname [-f known_hosts_file]
       ssh-keygen -r hostname [-g] [-f input_keyfile]
       ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]
       ssh-keygen -f input_file -T output_file [-v] [-a rounds] [-J num_lines]
                  [-j start_line] [-K checkpt] [-W generator]
       ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider]
                  [-n principals] [-O option] [-V validity_interval]
                  [-z serial_number] file ...
       ssh-keygen -L [-f input_keyfile]
       ssh-keygen -A [-f prefix_path]
       ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]
                  file ...
       ssh-keygen -Q -f krl_file file ...
       ssh-keygen -Y check-novalidate -n namespace -s signature_file
       ssh-keygen -Y sign -f key_file -n namespace file ...
       ssh-keygen -Y verify -f allowed_signers_file -I signer_identity
       		-n namespace -s signature_file [-r revocation_file]</pre></div>
<p>在本地生成的key文件，推送到服务器上，在此之前先看下服务器的ssh服务开启了没有，没有开启的打开就好。</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">systemctl status sshd

systemctl start sshd</pre></div>
<p>在服务器上，设置一下<code class="notranslate">.ssh</code>和<code class="notranslate">authorized_keys</code>的权限，网上有部分资料将权限设置之后，免密登录才生效。</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">sudo chmod 700 <span class="pl-k">~</span>/.ssh
sudo chmod 600 <span class="pl-k">~</span>/.ssh/authrized_keys</pre></div>
<p>设置之后，测试一下，看看免密登录能不能成功：</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">ssh root@101.101.101.101</pre></div>
<p>只要可以正常进入云服务器就说明已经生效了，如果还不行的，检查一下配置文件的路径或者是权限。</p>
<p>最后，在本地的<code class="notranslate">.ssh</code>目录，新增一个配置文件<code class="notranslate">config</code>:</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">Host aliyun
    user root 
    hostname 192.168.1.1 
    IdentityFile /Users/root/.ssh/id_rsa  (密钥的本地地址)</pre></div>
<p>执行一下<code class="notranslate">ssh aliyun</code>，就可以登录云服务器了。</p>
<h3>参考资料</h3>
<ul>
<li><a href="https://segmentfault.com/a/1190000021000360" rel="nofollow">SSH 免密登陆配置</a></li>
</ul>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Docker镜像的制作与使用]]></title>
            <link>https://wuh.site/post/32</link>
            <guid>32</guid>
            <pubDate>Sun, 29 Aug 2021 12:21:43 GMT</pubDate>
            <description><![CDATA[

## Docker镜像的制作与使用

![docker-hub](https://src.wuh.site/2021-08/2021-08-29-090210.png)

最近github的速度是在是太慢了，实在是受不了了，所以只好把镜像的编译工作放在了本地。在本地制作镜像然后托管到dockerhub，直接使用线上镜像了。

**换一句话描述: 之前在服务器做镜像，现在在本地做]]></description>
            <content:encoded><![CDATA[<h2>Docker镜像的制作与使用</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/2287238bd41ec4ff2bbda58b46d8dce43e024685769c2f4c8d951883e3a2bc68/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3039303231302e706e67"><img src="https://camo.githubusercontent.com/2287238bd41ec4ff2bbda58b46d8dce43e024685769c2f4c8d951883e3a2bc68/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3039303231302e706e67" alt="docker-hub" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-090210.png" style="max-width: 100%;"></a></p>
<p>最近github的速度是在是太慢了，实在是受不了了，所以只好把镜像的编译工作放在了本地。在本地制作镜像然后托管到dockerhub，直接使用线上镜像了。</p>
<p><strong>换一句话描述: 之前在服务器做镜像，现在在本地做镜像。</strong></p>
<p>首先，介绍一下，这次更换部署方式用了哪一些工具和一些使用的坑，更多关于使用的方法和问题的排查。</p>
<ol>
<li>docker</li>
<li>docker-compose</li>
<li>Bash</li>
<li>Npm/yarn &amp; nodejs</li>
</ol>
<p><strong>基本的流水线节点</strong>大致如下:</p>
<ol>
<li>第一步: 本地制作镜像文件</li>
<li>第二步: 推送镜像文件至远程dockerhub</li>
<li>第三步：服务器更新镜像文件</li>
<li>第四步：重启容器，重启nginx</li>
</ol>
<p>连接服务器更新的脚本，没有提交到github，但是我会讲一下我是怎么做的。</p>
<h3>docker</h3>
<p>具体的安装流程可以百度一下，网上有很多的教程，就不具体说了。这里贴上一些我经常查看的一些网站，当然都是关于docker的。</p>
<ol>
<li><a href="https://docs.docker.com/engine/reference/run/" rel="nofollow">docker-run</a>(docker的官方文档，当前链接为docker的指令集文档)</li>
<li><a href="https://yeasy.gitbook.io/docker_practice/compose/introduction" rel="nofollow">docker从入门到实践</a>(中文版的docker文档，文档很详细，基本满足我现在的需求)</li>
<li><a href="https://www.coder.work/article/41485" rel="nofollow">docker.restart</a>(镜像更新后，不断机更新重启容器)</li>
</ol>
<p>简单列一下我用的比较多的一些docker的指令：</p>
<ul>
<li>docker build</li>
<li>docker run</li>
<li>docker pull</li>
<li>docker push</li>
<li>docker tag</li>
<li>docker create</li>
<li>docker login</li>
<li>docker config</li>
<li>docker restart</li>
</ul>
<p>首先，我是将镜像文件托管到了docker的官方网站，所以login是必须要执行的一个指令。除此之外，每一个镜像文件必须指定两个版本号。<code class="notranslate">docker pull</code>指令默认拉取的是<code class="notranslate">docker-image:latest</code>版本号，同时我必须将这个镜像打上另一个版本号，以防需要镜像回退。</p>
<p>首先，在bin目录下创建一个脚本文件，执行环境指定为node，<code class="notranslate">docker-push.sh</code></p>
<div class="highlight highlight-source-shell"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#!</span>/usr/src/env node</span></pre></div>
<p>所以，在<code class="notranslate">push</code>操作之前必须先只执行一句代码，<code class="notranslate">docker-push.sh</code>:</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">docker build -t <span class="pl-s"><span class="pl-pds">'</span>shadowu/wuh.site:latest<span class="pl-pds">'</span></span> -t <span class="pl-s"><span class="pl-pds">'</span>shadowu/wuh.site:1.6.0<span class="pl-pds">'</span></span></pre></div>
<p>另外一个版本号，来自于<code class="notranslate">package.json</code>文件中的<code class="notranslate">version</code>字段，基于这个文件可以更新一下执行的脚本:</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">version=<span class="pl-s"><span class="pl-pds">$(</span>node -e <span class="pl-s"><span class="pl-pds">"</span>(function () { </span></span>
<span class="pl-s"><span class="pl-s">  const path = require('path')</span></span>
<span class="pl-s"><span class="pl-s">  const pathname = path.resolve(__dirname, './package.json')</span></span>
<span class="pl-s"><span class="pl-s">  console.log(require(pathname).version) </span></span>
<span class="pl-s"><span class="pl-s">})()<span class="pl-pds">"</span></span><span class="pl-pds">)</span></span>

docker build -t <span class="pl-s"><span class="pl-pds">'</span>shadowu/wuh.site:latest<span class="pl-pds">'</span></span> -t <span class="pl-s"><span class="pl-pds">'</span>shadowu/wuh.site:<span class="pl-pds">'</span></span><span class="pl-smi">$version</span></pre></div>
<p>执行环境指定为node了，我才可以用nodejs的模块化拿到<code class="notranslate">package.json</code>文件里面的<code class="notranslate">version</code>，这个是我能想到的最简单的方法。</p>
<p>然后，在脚本指令里面，为这个脚本加上一个命令:</p>
<div class="highlight highlight-source-json"><pre class="notranslate"><span class="pl-ent">"scripts"</span>: {
  <span class="pl-ent">"build:docker"</span>: <span class="pl-s"><span class="pl-pds">"</span>./bin/docker-push.sh<span class="pl-pds">"</span></span>
}</pre></div>
<p>镜像的文件制作``Dockerfile`，可以访问我之前写过的一篇<a href="https://wuh.site/post/2021-03/%E4%BB%8EPM2%E5%88%B0docker%2C%20%E7%A6%BB%E4%B8%8D%E5%BC%80%E7%9A%84Nginx" rel="nofollow">《从PM2到docker, 离不开的Nginx》</a>,不用写太多，简单制作一下，先让项目可以用docker跑起来，其他的再说。</p>
<h3>docker-compose</h3>
<p>在很早之前，docker-compose还是需要单独安装，但在更新了docker的版本后，docker-cli里面集成了docker-compose，相当的方便，我在<a href="https://github.com/stack-wuh/react-router-config#readme">项目的描述文件</a>里面记录了两种启动容器的方式。一种是用docker-compose 启动本地制作镜像，另一种是docker启动线上镜像。</p>
<p>在项目里面我提供了<a href="https://github.com/stack-wuh/react-router-config/blob/v2/docker-compose.yml">docker-compose.yml</a>的执行文件，在不考虑其他优化的前提下，用docker-compose启动镜像是如此的简单。</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">version: <span class="pl-s"><span class="pl-pds">"</span>3<span class="pl-pds">"</span></span>

services: 
  nextjs_app:
    build: ./
    ports: 
      - 3100:3000</pre></div>
<p>必须的配置项就这么简单，但是优化镜像体积的时候，我们还需要用到volume挂载卷，和一个针对<code class="notranslate">node_modules</code>的专用镜像。两个镜像之间的网络桥接用到的<code class="notranslate">network</code>。</p>
<p>目前我遇到的，比较麻烦的处理就是这两个，因为也是头一次做，很多东西都需要慢慢摸索。</p>
<p>在之前版本中，服务器端的执行脚本是这个样子:</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">   frontend:
    build: frontend
    ports:
      - 3100:3000
    stdin_open: <span class="pl-c1">true</span>
    container_name: frontend
    restart: always
    depends_on:
      - backend
    networks:
     - react-express
     - mongo-db</pre></div>
<p>现在不用执行编译过程，简单改一下，直接使用镜像名+版本号就好:</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">   frontend:
    image: shadowu/wuh.site:latest
    ports:
      - 3100:3000
    stdin_open: <span class="pl-c1">true</span>
    container_name: frontend
    restart: always
    depends_on:
      - backend
    networks:
     - react-express
     - mongo-db</pre></div>
<p>你永远可以使用且可以只使用 <strong>docker-compose up -d</strong> 指令，来完成你想完成的任意操作。</p>
<h3>Bash</h3>
<p>首先，介绍一下有关bash相关的教程<a href="https://wangdoc.com/bash/startup.html#%E7%99%BB%E5%BD%95-session" rel="nofollow">《Bash脚本教程》</a>(来自于阮老师的教程，链接地址直接指向了Bash的启动环境篇)。</p>
<p>教程的内容很多，但是我用到的实际上也没几个，目前只会写一点相当基础的语句，但是没关系，可以慢慢来。</p>
<p>现在使用的一个<code class="notranslate">source</code>指令，用来加载同步服务器端的脚本文件。</p>
<div class="highlight highlight-source-shell"><pre class="notranslate">ssh username@ip

$ password</pre></div>
<p>这个是比较常用，使用ssh登录服务器的操作。输入密码是必不可少的一步。只有密码正确了才可以操作服务器，我已经将一些基础的操作全部做成了脚本，现在只差服务器的同步。那么有没有一种方法可以免去输密码的这一步？</p>
<p>我用到的一种就是安全证书。</p>
<p>能力有限，原理我说不清，感兴趣的自己百度。</p>
<h3>执行结果与相关问题</h3>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/291b8a62e5b0c4a3f9ff0b54ff7418ca5a1a9a65cbdd8756ccd73ebd0d19ae37/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130313734372e706e67"><img src="https://camo.githubusercontent.com/291b8a62e5b0c4a3f9ff0b54ff7418ca5a1a9a65cbdd8756ccd73ebd0d19ae37/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130313734372e706e67" alt="result" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-101747.png" style="max-width: 100%;"></a></p>
<p>执行脚本之后，能够正常的走到这一步说明没有遇到问题，而且已经推送成功了。</p>
<p>初次制作的时间还是比较长的达到了43s，别慌，之后的编译过程会快一点。有些问题需要注意下：</p>
<ol>
<li>
<p>看一下执行过程，停留在yarn install 的过程特别耗时，有一次达到了200s+，只好改成淘宝的镜像源了。</p>
</li>
<li>
<p>volume的配置项，不管我放到哪里都感觉没用，也不知道是不是使用的姿势不对。但是我看到了一种方法就是将node_modules单独做成一个镜像，容器之间是可以互相访问，免去每一次制作镜像都需要安装依赖，后面实践一下。</p>
</li>
<li>
<p>启动容器一定要加上端口号，容器默认端口是3000，但是浏览器访问3000端口是没办法正常访问的，这里我测试过，加上一个映射端口就没问题。</p>
</li>
<li>
<p>docker-hub设置为公共源，才可以用到一些三方工具，比如生成一个icon标签放在github上面。</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/078cc01590104fbeb97927f762fb0c22a9c90ac7ca22652466b1e0886cf02844/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130323933352e706e67"><img src="https://camo.githubusercontent.com/078cc01590104fbeb97927f762fb0c22a9c90ac7ca22652466b1e0886cf02844/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130323933352e706e67" alt="github-icon-label" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-102935.png" style="max-width: 100%;"></a></p>
</li>
<li>
<p>注意nodejs的版本，有很多莫名的问题是nodejs的版本带来的问题，linux上可以使用的<code class="notranslate">n</code>这个工具，可以快速的切换nodejs的版本</p>
</li>
<li>
<p><code class="notranslate">WORKDIR</code>是指app在容器里面运行的文件目录，在遇到镜像可以正常制作，但是容器死活起不来的时候，可以减掉一些镜像文件的配置项，进入到容器里面去看一下究竟遇到了什么问题</p>
</li>
</ol>
<h3>docker的常用指令</h3>
<p><code class="notranslate">docker container ls -a</code> <code class="notranslate">docker image ls -a</code> <code class="notranslate">docker stop container_id &amp; rm contaier_id``docker image rm image_id</code></p>
<p>以上是使用的频率最多的一些指令，同时我们还会用到 <code class="notranslate">docker container inspect</code>和<code class="notranslate">docker image inspect</code>，它们是用来查询容器和镜像的基础配置的。</p>
<ul>
<li>必须删除容器才可以删除创建容器的镜像，而再此之前，必须先停掉容器，才可以删除容器。</li>
<li><code class="notranslate">docker run</code>和<code class="notranslate">docker create</code> 在创建容器的时候，其实没啥大区别，需要注意的是，最好加上<code class="notranslate">-it</code>配置，在容器正常启动后会返回容器id</li>
<li>就用<code class="notranslate">docker-compose</code>，有了它一切变得简单起来</li>
</ul>
<h3>工具</h3>
<p><a href="https://www.docker.com/products/docker-desktop" rel="nofollow">Docker Desktop</a></p>
<p>官方提供的一个工具，使用简单。</p>
<ol>
<li>可以相当直观的看到现在使用的机器上面镜像和运行的容器</li>
</ol>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/8b59f5663b6168bee5df9691d90595b30a43c713ab9b744eac235c73cedb8f20/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130353931302e706e67"><img src="https://camo.githubusercontent.com/8b59f5663b6168bee5df9691d90595b30a43c713ab9b744eac235c73cedb8f20/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3130353931302e706e67" alt="desktop-about" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-105910.png" style="max-width: 100%;"></a></p>
<ol start="2">
<li>
<p>可以看到目前容器占用的资源</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/7bfd25d3066831bbee64d97216a951833df68902e328e0c0f3509d5b3e03990e/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3131303032302e706e67"><img src="https://camo.githubusercontent.com/7bfd25d3066831bbee64d97216a951833df68902e328e0c0f3509d5b3e03990e/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3131303032302e706e67" alt="desktop-memery" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-110020.png" style="max-width: 100%;"></a></p>
</li>
<li>
<p>可以看到一些变量属性</p>
</li>
</ol>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d59890495f42c2ad2a48d9b4307a28536815234de9283b39b5fd6f062be5f1f8/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3131303033352e706e67"><img src="https://camo.githubusercontent.com/d59890495f42c2ad2a48d9b4307a28536815234de9283b39b5fd6f062be5f1f8/68747470733a2f2f7372632e7775682e736974652f323032312d30382f323032312d30382d32392d3131303033352e706e67" alt="desktop-env" data-canonical-src="https://src.wuh.site/2021-08/2021-08-29-110035.png" style="max-width: 100%;"></a></p>
<ol start="4">
<li>可以快速布置k8s任务</li>
</ol>
<p>======= 分割线以下是更新内容 =======</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ javascript中的继承]]></title>
            <link>https://wuh.site/post/31</link>
            <guid>31</guid>
            <pubDate>Mon, 10 May 2021 11:35:15 GMT</pubDate>
            <description><![CDATA[<img width="969" alt="prototype" src="https://user-images.githubusercontent.com/34117238/117653161-a6805000-b1c6-11eb-946d-fbd351e80665.png">

## javascript中的继承

这两天没事，在翻看红宝书的继承篇，重新学习了一下下js中的继承。出于]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/117653161-a6805000-b1c6-11eb-946d-fbd351e80665.png"><img width="969" alt="prototype" src="https://user-images.githubusercontent.com/34117238/117653161-a6805000-b1c6-11eb-946d-fbd351e80665.png" style="max-width: 100%;"></a></p>
<h2>javascript中的继承</h2>
<p>这两天没事，在翻看红宝书的继承篇，重新学习了一下下js中的继承。出于对Es6中class 类继承的好奇，我在babel里面试了一下，才发现Es6中class类继承，实际是寄生组合式继承，也是一下我要介绍的一种， 如图：</p>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/23af0d2190fda3625dd632fa1538205244d9ec3e800434047ac78edbcc80faf2/68747470733a2f2f7372632e7775682e736974652f323032312d30352f323032312d30352d31302d3038313930382e706e67"><img src="https://camo.githubusercontent.com/23af0d2190fda3625dd632fa1538205244d9ec3e800434047ac78edbcc80faf2/68747470733a2f2f7372632e7775682e736974652f323032312d30352f323032312d30352d31302d3038313930382e706e67" alt="" data-canonical-src="https://src.wuh.site/2021-05/2021-05-10-081908.png" style="max-width: 100%;"></a></p>
<p>在红宝书中主要介绍了一下5中实现继承的方案：</p>
<ol>
<li>原型链继承</li>
<li>构造函数继承</li>
<li>组合式继承</li>
<li>原型继承</li>
<li>寄生继承</li>
<li>寄生组合式继承</li>
</ol>
<p>以下，我只记录它们主要的设计代码和基本原理，其实例可以访问我的<a href="https://codesandbox.io/dashboard/all/js%20--%20%E7%BB%A7%E6%89%BF?workspace=ebfb60f6-b82b-4dbb-95e9-2e5ecd4a085d" rel="nofollow">codesandbox</a>，里面有继承篇详细的例子。</p>
<h3>原型链继承</h3>
<p>基本思想就是利用原型，让一个引用类型可以继承使用另一个引用类型的属性和方法。详情查看例子<a href="https://codesandbox.io/s/inherit--prototype-kgvtr" rel="nofollow">原型链继承</a>。</p>
<p>每一个构造函数都有一个原型对象，而原型对象中又有一个指针指向构造函数，实例也有一个指向原型对象的指针。如果让原型对象等于另一个类型的实例，那该原型对象就具有了另一个类型的构造函数。如果另一个类型的原型中又有另一个类型的实例，层层递进就有形成了一种实例与原型的链条，这个就是<strong>原型链</strong>。</p>
<p>对SubType的原型对象改写为SuperType的实例，此时可以将SuperType称之为SubType的超类，那SubType即为子类。</p>
<p>如果继续将SubType作为超类，对SubType2改写原型对象，那SubType2将同时具有SuperType和SubType的属性和方法，尽管SupType2不是SuperType的子类。这个就是继承链最简单的一个实现例子，</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">SuperType</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'super'</span>
<span class="pl-kos">}</span>
<span class="pl-v">SuperType</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">getName</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">SubType</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'sub'</span>
<span class="pl-kos">}</span>

<span class="pl-v">Sub</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">SuperType</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-v">Sub</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">getSubName</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">SubType2</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
<span class="pl-v">SubType2</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">SubType</span><span class="pl-kos">(</span><span class="pl-kos">)</span></pre></div>
<p><strong>注意：</strong></p>
<ol>
<li>需要注意的是，重写子类原型的语句必须出现在声明Sub原型方法之前，原因很简单，因为原型链继承是重写子类原型对象。重写语句后自定义子类的属性和方法会被删除。</li>
<li>在使用原型链继承时，如果超类中声明了复杂类型，后代子类会共享复杂类型的值。比如：子类1 更新了一个数组的元素的值，本次更新会反应到子类2。<strong>这个也是原型链继承的一个最大的缺点。</strong></li>
<li>不能使用对象字面量去创建原型方法，因为使用字面量后实质上是重写了原型链，切断与原来的原型链之间的联系。</li>
<li>没有办法在不影响全部实例的前提下，给超类的构造函数传递参数。</li>
</ol>
<h3>借用构造函数</h3>
<p>在子类的构造函数中调用超类的构造函数，即为借用构造函数的基本原理。详情查看例子<a href="https://codesandbox.io/s/inherit--constructor-dhlco" rel="nofollow">借用构造函数</a></p>
<p>借用构造函数方法的出现就是为了解决原型链继承的复杂类型值会被各个实例共享的问题。</p>
<p>在子类的构造函数中调用超类的构造函数，其实质是将超类绑定在this中的属性复制到子类中，只有在调用子类的构造函数时，才执行超类的构造函数，所以现在的参数问题得以解决，各个实例间不会互相影响。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">Super</span> <span class="pl-kos">(</span><span class="pl-s1">name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'super'</span> <span class="pl-c1">||</span> <span class="pl-s1">name</span>
<span class="pl-kos">}</span>
<span class="pl-k">function</span> <span class="pl-v">Sub</span> <span class="pl-kos">(</span><span class="pl-s1">name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-v">Super</span><span class="pl-kos">.</span><span class="pl-en">call</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">,</span> <span class="pl-s1">name</span><span class="pl-kos">)</span>

	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'sub'</span>	
<span class="pl-kos">}</span></pre></div>
<p><strong>注意：</strong></p>
<ol>
<li>相对于原型链继承，借用构造函数可以单独给实例传递参数了。因为属性是绑定在this上面的，只有在创建实例的时候才赋值，所以实例之间互不影响。</li>
<li>但是，在解决了复杂类型值的问题之后，借用构造函数又有一个新的问题。属性和方法全部绑定在this上面，所以只能在构造函数内部继续声明其他的属性和方法，<strong>扩展性降低。</strong></li>
<li>同时，在超类的原型中定义的属性，对于子类而言不可见。<strong>所以必须在超类的构造函数中声明属性。</strong></li>
</ol>
<h3>组合继承</h3>
<p>利用原型链实现方法的基础和利用构造函数实现属性的继承，就是组合继承的基本原理。结合了原型链和借用构造函数的技术，同时具有了它们的优点。详情查看例子<a href="https://codesandbox.io/s/inherit--combine-scxx5" rel="nofollow">组合继承</a></p>
<p>在重写了子类的原型后，Sup.prototype实质上指向了Super.prototype，在Sup.prototype.constructor指向的是Super，这里需要手动将Sub.prototype.constructor指向Sub。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">Super</span> <span class="pl-kos">(</span><span class="pl-s1">name</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'super'</span> <span class="pl-c1">||</span> <span class="pl-s1">name</span>
<span class="pl-kos">}</span>
<span class="pl-v">Super</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-en">getName</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">Sub</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-v">Super</span><span class="pl-kos">.</span><span class="pl-en">call</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span>
	
	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">age</span> <span class="pl-c1">=</span> <span class="pl-c1">20</span>
<span class="pl-kos">}</span>

<span class="pl-v">Sub</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">Super</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-v">Sub</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span><span class="pl-kos">.</span><span class="pl-c1">constructor</span> <span class="pl-c1">=</span> <span class="pl-v">Sub</span></pre></div>
<p><strong>注意：</strong></p>
<ol>
<li>组合继承唯一一点就是需要两次调用超类的构造函数。</li>
</ol>
<h3>原型式继承</h3>
<p>没有严格意义的构造函数，原型可以基于一个对象生成另外一个新对象，还不必为它声明额外的类型，就是原型式继承的基本原理。详情查看例子<a href="https://codesandbox.io/s/inherit--prototypal-c1o3b" rel="nofollow">原型式继承</a></p>
<p>原型继承的实现特别简单，公式一样的三句代码。object函数实际是创建基于传入的对象o，生成的副本。每一个由object函数生成的副本，其状态都被共享了。</p>
<p>但是对实例进行扩展的方法是不会被共享的。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">object</span> <span class="pl-kos">(</span><span class="pl-s1">o</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">function</span> <span class="pl-v">F</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
  <span class="pl-v">F</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span> <span class="pl-c1">=</span> <span class="pl-s1">o</span>
  <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-v">F</span><span class="pl-kos">(</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span></pre></div>
<p><strong>注意：</strong></p>
<ol>
<li>其复杂类型值的问题，如同原型链继承一样，会被每一个实例共享</li>
<li>在es5中，已经新增Object.create方法，其效果与object方法一致</li>
</ol>
<h3>寄生式继承</h3>
<p>寄生式继承，是与原型式继承密不可分的。其基本思想就是，仅创建一个封装继承过程的函数，在函数内部对新对象进行增强，然后返回增强的新对象。详情查看例子<a href="https://codesandbox.io/s/inherit--parasitic-49rq6" rel="nofollow">寄生式继承</a></p>
<p>就这样在由寄生式继承的函数返回的新对象，就有了源对象origin的属性和增强的属性。</p>
<p>所以，寄生式继承和原型式继承，主要针对的是对象间的继承，而非自定义构造函数。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">inherit</span> <span class="pl-kos">(</span><span class="pl-s1">o</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">var</span> <span class="pl-s1">prototype</span> <span class="pl-c1">=</span> <span class="pl-en">object</span><span class="pl-kos">(</span><span class="pl-s1">o</span><span class="pl-kos">)</span>
  <span class="pl-s1">prototype</span><span class="pl-kos">.</span><span class="pl-en">getName</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span>
  <span class="pl-kos">}</span>
  
  <span class="pl-k">return</span> <span class="pl-s1">prototype</span>
<span class="pl-kos">}</span></pre></div>
<p><strong>注意：</strong></p>
<ol>
<li>其缺点与借用构造函数相似，其封装过程全部在函数内部，没有办法进行扩展。</li>
</ol>
<h3>寄生组合式继承</h3>
<p>寄生组合式继承，指的是通过构造函数来继承属性，通过原型链的混成形式来继承方法。其基本原理就是： 不必为了子类的原型而调用超类的构造函数，我们需要的就是超类原型的一个副本。详情查看例子<a href="https://codesandbox.io/s/inheritance--parasitic-combination-9pytp" rel="nofollow">寄生组合式继承</a></p>
<p>可以使用寄生式继承来继承超类的原型，再将结果指定给子类的原型。</p>
<p>寄生组合继承，可以减去一步在子类外部调用的超类构造函数，避免将一些额外的属性附加到子类的原型链中，而且原型链还能保持不变。</p>
<p>所以，开发人员一致认为寄生组合式继承是引用类型最理想的继承范式。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-v">Super</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-c1">=</span> <span class="pl-s">'super'</span>
<span class="pl-kos">}</span>
<span class="pl-v">Super</span><span class="pl-kos">.</span><span class="pl-c1">ptototype</span><span class="pl-kos">.</span><span class="pl-en">getName</span> <span class="pl-c1">=</span> <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>  <span class="pl-k">return</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">name</span> <span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">Sub</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">subname</span> <span class="pl-c1">=</span> <span class="pl-s">'sub'</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-en">inherit</span> <span class="pl-kos">(</span><span class="pl-s1">subType</span><span class="pl-kos">,</span> <span class="pl-v">SuperType</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
	<span class="pl-k">const</span> <span class="pl-s1">prototype</span> <span class="pl-c1">=</span> <span class="pl-en">object</span><span class="pl-kos">(</span><span class="pl-v">SuperType</span><span class="pl-kos">)</span>
	<span class="pl-s1">prototype</span><span class="pl-kos">.</span><span class="pl-c1">constructor</span> <span class="pl-c1">=</span> <span class="pl-s1">subType</span>
	<span class="pl-s1">subType</span><span class="pl-kos">.</span><span class="pl-c1">prototype</span> <span class="pl-c1">=</span> <span class="pl-s1">prototype</span>
	
	<span class="pl-k">return</span> <span class="pl-s1">prototype</span>
<span class="pl-kos">}</span>

<span class="pl-en">inherit</span><span class="pl-kos">(</span><span class="pl-v">Sub</span><span class="pl-kos">,</span> <span class="pl-v">Super</span><span class="pl-kos">)</span></pre></div>
<p>可以回到顶部，查看babel对class类继承实现的转换，仔细一对比，发现其实没有什么大的不同，从实现思想上来说是一致的。</p>
<h3>Class 与 extends</h3>
<p>ES6终于实现了基于类继承的方案了。可以使用extends关键字实现继承, 但是在子类中必须使用super关键字，因为子类没有自己的this。</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">Parent</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-v">Child</span> <span class="pl-k">extends</span> <span class="pl-v">Parent</span> <span class="pl-kos">{</span>
  <span class="pl-en">constructor</span> <span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-s1">props</span><span class="pl-kos">)</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p>在ES5中，先创建的是子类的this，然后将父类的属性和方法添加到子类的this当中。 在ES6中，先将父类的实例添加到this中，然后用子类的构造函数去修改this。</p>
<p><strong>注意：</strong></p>
<ol>
<li>在大多数浏览器的Es5的实现中，都存在一个<code class="notranslate">__proto__</code>属性，该属性总是指向对应构造函数的prototype属性。Class作为构造函数的语法糖，同时具有<code class="notranslate">__proto__</code>与<code class="notranslate">prototype</code>两条继承链。</li>
<li>子类的<code class="notranslate">__proto__</code>属性，表示构造函数的继承，总是指向父类。 <code class="notranslate">Child.__proto__ === Parent</code></li>
<li>子类prototype中的<code class="notranslate">__proto__</code>，表示方法的继承，总是指向父类的<code class="notranslate">prototype</code>。  <code class="notranslate">Child.prototype.__proto__ === Parent.prototype</code></li>
<li>在类继承中，<code class="notranslate">__proto__</code>属性是层层嵌套的，子类的<code class="notranslate">__proto__</code>属性的<code class="notranslate">__proto__</code>属性指向的就是父类的<code class="notranslate">__proto__</code>。 <code class="notranslate">Child.__proto__.__proto__ === Parent.__proto__</code></li>
</ol>
<h3>总结</h3>
<ol>
<li>在js中主要通过原型链实现继承。原型链的继承就是通过将一个类型的实例赋值给另一个构造函数的原型。这样，子类就可以访问超类中的属性和方法，与基于类继承相似。</li>
<li>原型链继承的问题是所有对象实例共享所有继承的属性和方法，因此不适于单独使用，而解决的方法就是借用构造函数。</li>
<li>借用构造函数，是通过在子类的构造函数中调用超类的构造函数。这样就可以做到，每一个实例有自己的属性和方法，但是也限制了子类的扩展，因为只能在构造函数内部声明其他属性和方法。</li>
<li>使用最多的继承模式是组合继承，集成了原型链继承和借用构造函数优势。通过原型链来扩展方法，通过借用构造函数来实现实例属性的继承，唯一缺点就是必须调用两次超类构造函数，造成效率缺失。</li>
<li>原型式继承，是针对于对象的一种继承模式，如非必要声明构造函数，可以使用该模式，其实质就是对源对象进行浅复制。</li>
<li>寄生式继承, 与原型式继承息息相关。基于源对象生成一个新对象，然后对这个新对象增强后返回。</li>
<li>寄生组合继承，为了解决组合继承会两次调用超类构造函数而造成效率低下的问题，将寄生式继承和组合式继承结合。通过寄生式继承对超类原型对象浅复制，然后对子类原型的构造函数修正，最后改写子类的原型对象。</li>
</ol>
<p><strong>寄生组合继承是基于类型继承最有效的方式。</strong></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[搬山计划]]></title>
            <link>https://wuh.site/post/30</link>
            <guid>30</guid>
            <pubDate>Fri, 07 May 2021 13:11:21 GMT</pubDate>
            <description><![CDATA[
![banshanjihua 001](https://user-images.githubusercontent.com/34117238/117454439-b7d41d00-af78-11eb-8b6f-7e4be67d9aa8.jpeg)

## 搬山计划

在过去的一年时间里，自己除了工作就是工作，现在是时候做出一点点改变了，去玩生活去。

每一个人的身上的优缺点都是他的]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/117454439-b7d41d00-af78-11eb-8b6f-7e4be67d9aa8.jpeg"><img src="https://user-images.githubusercontent.com/34117238/117454439-b7d41d00-af78-11eb-8b6f-7e4be67d9aa8.jpeg" alt="banshanjihua 001" style="max-width: 100%;"></a></p>
<h2>搬山计划</h2>
<p>在过去的一年时间里，自己除了工作就是工作，现在是时候做出一点点改变了，去玩生活去。</p>
<p>每一个人的身上的优缺点都是他的“闪光点“，而这些”闪光点“无时无刻不在反映着他自身。他永远也无法将这些闪光点抹除，不管它是积极的还是消极的。虽然无法消除消极的闪光点，但是可以隐藏，这一个过程给它命名一个名字——"搬山计划"。</p>
<p>整个人体，我把它当做一座山。你的优点和缺点全部集中在山顶之中，所以它们最显眼。而山脚处，则是普通地不能普通的个人因素。</p>
<blockquote>
<p>现在我加入一个思考，当你接触观察一个新朋友的时候，你首先是关注他的优点，还是缺点？或者说，彻底影响你对他的个人看法是什么因素？</p>
</blockquote>
<p>所以，我说：”自身修炼改造，犹如搬山。你永远也不能彻底改变沉疴旧疾，只能将山顶最引人注目的土往下搬。“</p>
<p>对于我而言，普普通通，平平凡凡，无人关注才是一种最佳的生活状态。</p>
<p>写字，读书，玩一些从未接触过的事物。</p>
<p>每一晚，我给自己安排了200字的控笔。</p>
<p>每一天，我给自己安排了2小时的阅读。</p>
<p>每一周，我给自己安排去逛一逛周边。</p>
<p>每一月，我给自己安排去见一见我在深圳的朋友。</p>
<p>现在，我对无人机很感兴趣，我似乎应该去买一个无人机玩一玩。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[浅尝一下UI设计]]></title>
            <link>https://wuh.site/post/28</link>
            <guid>28</guid>
            <pubDate>Sun, 18 Apr 2021 10:49:16 GMT</pubDate>
            <description><![CDATA[
## 浅尝一下UI设计
![ui_thumb](https://user-images.githubusercontent.com/34117238/115142719-cc0db400-a075-11eb-860b-9e08c8acecda.png)


博客的前端项目基础功能终于做的差不多了，现在就差设计一下UI了，奈何我不是专业的UI，只能从前端的角度和一些专业的设计文档，去实现]]></description>
            <content:encoded><![CDATA[<h2>浅尝一下UI设计</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/115142719-cc0db400-a075-11eb-860b-9e08c8acecda.png"><img src="https://user-images.githubusercontent.com/34117238/115142719-cc0db400-a075-11eb-860b-9e08c8acecda.png" alt="ui_thumb" style="max-width: 100%;"></a></p>
<p>博客的前端项目基础功能终于做的差不多了，现在就差设计一下UI了，奈何我不是专业的UI，只能从前端的角度和一些专业的设计文档，去实现一下。</p>
<h3>布局基础值</h3>
<p>在我们构建网站的布局时，前端会依据设计图，设计网页。在开始工作前，我们会确认一些基础值，比如：</p>
<ol>
<li>间距相关</li>
<li>色彩相关</li>
<li>动效相关</li>
<li>交互相关</li>
<li>布局相关</li>
</ol>
<p>我对设计的初级了解主要来自于<a href="https://ant.design/docs/spec/introduce-cn" rel="nofollow">Antd Design</a>的设计思想，它们的组件设计的真的很棒！现在先用原生css实现一次，以后再考虑改为less。如下:</p>
<div class="highlight highlight-source-css"><pre class="notranslate"><span class="pl-kos">:</span><span class="pl-c1">root</span> {
  <span class="pl-c">/** Base **/</span>
  <span class="pl-s1">--padding-base</span><span class="pl-kos">:</span> <span class="pl-c1">8<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--margin-base</span><span class="pl-kos">:</span> <span class="pl-c1">8<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--font-size-base</span><span class="pl-kos">:</span> <span class="pl-c1">14<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--border-radius-base</span><span class="pl-kos">:</span> <span class="pl-c1">3<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--line-height-base</span><span class="pl-kos">:</span> <span class="pl-c1">22<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--transition-base</span><span class="pl-kos">:</span> all <span class="pl-c1">.5<span class="pl-smi">s</span></span> ease;
}</pre></div>
<p>基础属性可以配置的有很多，我先定义一些比较常规的属性，然后根据这些基础属性，延伸出一些派生属性, 比如:</p>
<div class="highlight highlight-source-css"><pre class="notranslate"><span class="pl-kos">:</span><span class="pl-c1">root</span> {
  <span class="pl-c">/** Base **/</span>
  <span class="pl-s1">--padding-base</span><span class="pl-kos">:</span> <span class="pl-c1">8<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--margin-base</span><span class="pl-kos">:</span> <span class="pl-c1">8<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--font-size-base</span><span class="pl-kos">:</span> <span class="pl-c1">14<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--border-radius-base</span><span class="pl-kos">:</span> <span class="pl-c1">3<span class="pl-smi">px</span></span>;
  <span class="pl-s1">--line-height-base</span><span class="pl-kos">:</span> <span class="pl-c1">22<span class="pl-smi">px</span></span>
  <span class="pl-s1">--transition-base:</span> all <span class="pl-c1">.5<span class="pl-smi">s</span></span> ease;
  
  <span class="pl-c">/** Margin **/</span>
  <span class="pl-s1">--margin-base-2</span><span class="pl-kos">:</span> <span class="pl-en">calc</span>(<span class="pl-c1">2</span> <span class="pl-c1">*</span> <span class="pl-en">var</span>(<span class="pl-s1">--margin-base</span>));
  <span class="pl-s1">--margin-base-3</span><span class="pl-kos">:</span> <span class="pl-en">calc</span>(<span class="pl-c1">3</span> <span class="pl-c1">*</span> <span class="pl-en">var</span>(<span class="pl-s1">--margin-base</span>));
  
  <span class="pl-c">/** Border **/</span>
  <span class="pl-s1">--border-radius-2</span><span class="pl-kos">:</span> <span class="pl-en">calc</span>(<span class="pl-c1">2</span> <span class="pl-c1">*</span> <span class="pl-en">var</span>(<span class="pl-s1">--border-radius-base</span>));
  
  <span class="pl-c">/** Line Height **/</span>
  <span class="pl-s1">--line-height-default</span><span class="pl-kos">:</span> <span class="pl-en">calc</span>(<span class="pl-en">var</span>(<span class="pl-s1">--font-size-base</span>) <span class="pl-c1">+</span> <span class="pl-c1">10</span> <span class="pl-c1">-</span> <span class="pl-c1">2</span>);
}</pre></div>
<p>将这些派生属性的配置全部集中到一个样式文件当中，不要在组件中再次定义样式，以保证全局样式的整体一致性。</p>
<p>当然，派生属性的倍数设置，并不是简简单单的乘于整数倍这么简单，有一些相关的公式或者是规范，详情可以参考<a href="https://ant.design/docs/spec/introduce-cn" rel="nofollow">antd的设计文档</a>。例如:</p>
<ol>
<li>
<p><strong>字号</strong>: 对于字号与行高的定义就是：lineHeight = fontSize+10 - 2。在Antd中基础字号为14px，相对应的行高为 22px，字阶的选择在3-5中之间，保持克制原则。</p>
</li>
<li>
<p><strong>字重</strong>: 对于字重只建议使用3种，400、500和600。具体效果可以研究Antd的<strong>Typograph</strong>组件，赶紧按照标准实现一下自己的个人网站试一试。</p>
</li>
<li>
<p><strong>字体颜色</strong>：个人认为，色彩还是很考验一个设计师的，因为需要搭配，整体搭配的色彩需要<strong>和谐</strong>，所以对于色彩的把握才是整个体系的重中之重。对于不同的应用场景有不一样的实现，需要提前定义好网站的主，次，辅助和标题的色彩。<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/115142764-1a22b780-a076-11eb-9a65-a7a7cbf2b370.png"><img src="https://user-images.githubusercontent.com/34117238/115142764-1a22b780-a076-11eb-9a65-a7a7cbf2b370.png" alt="system-color" style="max-width: 100%;"></a></p>
</li>
<li>
<p><strong>暗黑模式</strong>: 给自己的网站准备一套暗黑模式是一个不错的功能，现在我们可以直接使用Antd的工具生成，站在巨人的肩膀上扩展，让我们的自定义开发快乐起来。</p>
</li>
</ol>
<p>现在先试着将我们的基础属性定义出来。就用Antd官网的工具生成一系列的色彩值，在此之前我们需要定义一个主题色彩。除此之外，需要定义字体色彩、border色彩和shadow阴影。</p>
<p>最为关键的是，我们需要设计一下页面的布局结构。从我个人的项目来分，可以分为：</p>
<ol>
<li>顶级标题</li>
<li>二级标题</li>
<li>三级标题</li>
<li>一级菜单</li>
<li>二级菜单</li>
<li>基础描述文案 -- Description</li>
<li>基本文案 -- Pages</li>
<li>背景色对比</li>
<li>Border外边框</li>
<li>Strong 增强类型文案</li>
<li>Small 渐弱类型文案</li>
<li>Shadow阴影</li>
<li>Hover类型色彩</li>
</ol>
<p>从「克制」方向来看，我做出了调整:</p>
<ol>
<li>页面上不需要太多的Heading标签，最多三级H1,H3,H6；</li>
<li>准备左侧菜单入口或者是顶部菜单入口，不需要太多的菜单，最多两级；</li>
<li>针对文章详情样式的调整，不用大的样式调整，需要多加一些细节调整；</li>
<li>页面内只准备三级字重，Strong等于600、Normal等于500以及Small等于400；</li>
<li>手势的交互增强，对比色彩、BorderRadius...</li>
<li>渐进动画，全部使用transition增强页面交互</li>
</ol>
<h3>确认基础设置值</h3>
<ol>
<li>Padding 和 Margin的基数定为 8px, 整数倍增加，为8的倍数；</li>
<li>BorderRadius的基数为 3px，增加不限制；</li>
<li>FontSize的基数为14px，增加不限制；</li>
<li>LineHeight的基数为22px，与FontSize成线性关系，LineHeight = Fontsize + 10 - 2；</li>
<li>定义主题色，中性色和主题色的反色；</li>
<li>定义背景色，可能需要好几组对应的背景色，以对应不同的使用场景；</li>
<li>定义Border边框色彩，不需要太多，可以直接使用主题色或者是中性色；</li>
<li>定义动画函数，常见的函数是ease，linear，可以自己定义贝塞尔曲线；</li>
<li>定义辅助色，辅助色彩丰富一点点</li>
</ol>
<h3>定义Heading类型主题</h3>
<p>首先给文案类配置主题，达到一种视觉上的层次感。可以通过主题色系的不同的色彩，然后在页面上使用。</p>
<p>在上图中，定义了8种类型，可以按照上面的顺序，将生成的色彩，一一对应。但是可能也会有特殊的位置需要额外定义。比如我们现在需要生成两套文字色，以对应light和dark模式下的展示。</p>
<div class="highlight highlight-source-css"><pre class="notranslate"><span class="pl-c">/** Light **/</span>
  <span class="pl-s1">--color-base</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>ebecec</span>;
  <span class="pl-s1">--color-base-10</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>0d0d0d</span>;
  <span class="pl-s1">--color-base-9</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>333333</span>;
  <span class="pl-s1">--color-base-8</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>595959</span>;
  <span class="pl-s1">--color-base-7</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>808080</span>;
  <span class="pl-s1">--color-base-6</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>a6a6a6</span>;
  <span class="pl-s1">--color-base-5</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>b3b3b3</span>;
  <span class="pl-s1">--color-base-4</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>bfbfbf</span>;
  <span class="pl-s1">--color-base-3</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>cccccc</span>;
  <span class="pl-s1">--color-base-2</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>d9d9d9</span>;
  <span class="pl-s1">--color-base-1</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>e6e6e6</span>;

<span class="pl-c">/** Dark **/</span>
  <span class="pl-s1">--color-base</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>141313</span>;
  <span class="pl-s1">--color-base-10</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>fafafa</span>;
  <span class="pl-s1">--color-base-9</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>f8f8f8</span>;
  <span class="pl-s1">--color-base-8</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>f3f3f3</span>;
  <span class="pl-s1">--color-base-7</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>e8e7e7</span>;
  <span class="pl-s1">--color-base-6</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>dcdcdc</span>;
  <span class="pl-s1">--color-base-5</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>adacac</span>;
  <span class="pl-s1">--color-base-4</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>7e7d7d</span>;
  <span class="pl-s1">--color-base-3</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>5b5a5a</span>;
  <span class="pl-s1">--color-base-2</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>454545</span>;
  <span class="pl-s1">--color-base-1</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>2c2b2b</span>;</pre></div>
<p>一共生成10种色彩，用于对应上图的8种类型，可用的色彩还是比较多的，先定义一套最普通的样式出来。</p>
<div class="highlight highlight-source-css"><pre class="notranslate"><span class="pl-s1">--title-normal-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-10</span>);
<span class="pl-s1">--title-less-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-9</span>);

<span class="pl-s1">--text-primary-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-8</span>);
<span class="pl-s1">--text-less-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-7</span>);

<span class="pl-s1">--text-second-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-6</span>);

<span class="pl-s1">--disabled-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-5</span>);

<span class="pl-s1">--border-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-4</span>);

<span class="pl-s1">--divider-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-3</span>);

<span class="pl-s1">--background-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-2</span>);

<span class="pl-s1">--table-head-color</span><span class="pl-kos">:</span> <span class="pl-en">var</span>(<span class="pl-s1">--color-base-1</span>);</pre></div>
<h3>中性色搭配</h3>
<p>偷个懒，直接用Antd的中性色，以color-7为基准，大于7的为Dark模式下的色彩，小于7的为Light模式下的色彩。</p>
<p>生成这些中性色有什么用呢？</p>
<p>我把它搭配使用在Card组件当中，中性色是以Gray色彩为基准生成的，灰色是百搭色彩，没有什么色彩能够比中性色更适合做背景色彩了。除非你需要自定义一些Alert或者的Message类型的样式，才会去给这些组件定义一些不同状态下的背景色彩。</p>
<h3>辅助色搭配</h3>
<p>在选择辅助色时，需要考虑到的是辅助色和背景色以及字色的搭配，需要好好准备一下色彩，最好是从选择的主题色出发，去选择相近的色系。</p>
<h3>Transition 与 Animate交互</h3>
<p>我们最少需要准备两套动画，即入场动画和出场动画。举一个例子，我们给一个标签做hover特效时，定义在hover类中的就是入场动画，比如使用ease-in，那么定义在当前标签类中的即为出场动画，比如使用ease-out，这个样子给用户的体验是不是有了一点点趣味呢。</p>
<p>如果需要将我们的页面细节做起来，我们可以给每一个属性都指定一个特有的出场和入场动画，那看起来就更美妙了，但是我觉得用两个动画就可以了。</p>
<h3>间距设置</h3>
<p>现在我们的基础都是基于8px，几何倍数的增加或者是减少，这样看起来的页面的间距值就全部统一起来啦，从结构上确实好看，具体去看Antd的组件。我是觉得好看的~</p>
<p>除了8n这一种写法，还可以使用em单位和rem单位，em相对于父级标签的字号，rem相对于根标签的字号，也是一种结构性的写法。但是使用场景上有差异，用em单位我们通过Fontsize属性轻松实现自适应的组件，比如在项目中的AudioContronl组件和Button组件组，就是通过Fontsize来控制Audio按钮组的样式。</p>
<h3>富结构化缺省页</h3>
<p>查询结果结构化是我在做google查询优化时接触到概念，我认为这个概念也可以用到我们的构建个人网站的查询结果中。</p>
<p>举个例子<strong>404页面</strong>，我个人认为：在类博客项目这种内容型项目中，我并不是想看一个枯燥的404提示，我更想看的是我查询的关键字在没有反馈的内容时，开发者给用户的交互是一种什么样的实现，才能吸引用户停留在我的网站中。</p>
<p>比如，我查询一个<strong>色彩</strong>关键字，我的网站上没有相关的博客内容，但是我不能给你一个简简单单的404，而是给用户一些推荐内容的快捷入口，引导用户点击进入博客内容页面，留住流量。</p>
<p>而资源类的404，可以给一些动画，或者是引入腾讯404服务的交互，让服务器端的错误或者是资源缺失，给用户一种丰富、有趣的体验。</p>
<p>在最近有一个主题卖疯了，就是华为商城的宇航人主题，它不就是靠着有趣才吸引了消费者吗，在短视频中火了后，不知道多少人为了一个主题去买了一块手表。可见，现在C端产品考虑<strong>趣味性</strong>的比重应该是比较大的。</p>
<h3>Empty 空状态</h3>
<p>为了弥补我们网站内容的缺失和资源缺失，给用户带来的不良体验，我们需要优化的点就是做一个有意思的Empty 空状态展示页。</p>
<p>在Empty中，我设计的结构是，一个简单的动画吸引用户视线，一组类bilibili中的火星文，一组引流快捷入口，如下图：<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/115142870-96b59600-a076-11eb-8a89-4213573efe69.png"><img src="https://user-images.githubusercontent.com/34117238/115142870-96b59600-a076-11eb-8a89-4213573efe69.png" alt="2021-04-18-092633" style="max-width: 100%;"></a></p>
<h3>定制型设计</h3>
<p>我们在写作时，工具会提示让我们选择是否启用<strong>专注模式</strong>，专注模式就是一种定制型设计。再类比一下，我们使用网易云App时有精简模式和普通模式，精简模式下，只有控制按钮组其他的什么都没有。</p>
<p>所以，一个网站能不能够吸引用户长时间停留，最为关键的点大概就是有意义的丰富内容和有意思的交互。让用户觉得好玩，让他自己去浏览、去玩。这样的网站才能够保证<strong>回访率</strong>。</p>
<h3>清新的结构和出彩的细节</h3>
<p>单从设计结构来看，开发者可以给用户提供两套布局模式，比如：菜单固定在左的模型和菜单固定在顶部的模型。给用户提供两套视觉模型，Light型和Dark型，然后我们可以根据系统时间，默认给用户切换主题色。</p>
<p>或者，定义精简模式，在阅读模式下，减少系统相关的交互和按钮入口，新增一些阅读类型的按钮，比如：自定义行高、字号，自定义阅读模式下网站字色和背景色，有耐心的话，还可以给出一些国际化方案，例如，中英文切换或者是简繁体切换。</p>
<p>总之，需要我们动用一些时间和心血去做一些不一样的细节出来，把网站打磨的漂漂亮亮的，就可以比较大方的拿出去拉外快项目啦。</p>
<p>一个开发者的个人网站大概就是他的一个比较有特色的个人名片啦。我们前端开发者还是占据了大量的优势的，我们可以自己做一些自己想要的效果出来，我们自己就是自己项目的产品经理。</p>
<h3>简洁而不简单，清新才是关键</h3>
<p>在Antd的设计文档中，始终在着重描述三个设计思想：自然、高效和克制。始终在表达<strong>一种简简单单才是美</strong>。</p>
<p>在理想状态下，我们不太需要关注更多的细节，比如那个经典的撕逼话题：”你这个1像素能不能细一点点， 我看着就不像1像素“。相反我们需要去做减法，但是此减法非彼减法。视觉上的细节少了但是给开发的工作却多了。单是色彩就至少准备40多个，其看不见的工作就给了视觉上的简单赋予了另外的一种不简单。</p>
<p>做好一份设计并不是我以上描述的这么简单，有很多内容我们都不知道，毕竟不是专业的设计师，我了解的相关知识全部来自于书本。但是我们现在是从前端角度去分析一下下怎么去做设计，让我们的项目做得更好一点，更快一点，更<strong>简单</strong>一点。</p>
<p>简洁而不简单，把背后的工作留给自己慢慢品，把清新留给用户。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2021年度总结]]></title>
            <link>https://wuh.site/post/27</link>
            <guid>27</guid>
            <pubDate>Thu, 08 Apr 2021 08:53:37 GMT</pubDate>
            <description><![CDATA[## 2021年度总结
![sss](https://user-images.githubusercontent.com/34117238/113997641-eaf89300-988a-11eb-90ad-4ad6f21ff00d.jpg)

转眼之间都快到2021年的年中了, 突然回味过来了, 想要写一写我的2020.

在2020年4月中旬，我终于回到了深圳，在一个星期后我入职了现]]></description>
            <content:encoded><![CDATA[<h2>2021年度总结</h2>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/34117238/113997641-eaf89300-988a-11eb-90ad-4ad6f21ff00d.jpg"><img src="https://user-images.githubusercontent.com/34117238/113997641-eaf89300-988a-11eb-90ad-4ad6f21ff00d.jpg" alt="sss" style="max-width: 100%;"></a></p>
<p>转眼之间都快到2021年的年中了, 突然回味过来了, 想要写一写我的2020.</p>
<p>在2020年4月中旬，我终于回到了深圳，在一个星期后我入职了现在就职的公司。从工作的时间维度看，现在的时间刚好一年，恰到好处。</p>
<h3>持续阅读，才是可持续发展</h3>
<p>正正经经读完的小说没有几本，好多的小说我没办法一直读下去，因为他们太耗费精力和时间。对于我而言，我可能需更多的时间去阅读和研究。比如说: 《时间简史》和《中国通史》。</p>
<p>以下是我整理的一份书单: <a href="https://weread.qq.com/misc/booklist/74791710_7kPtxUxu0" rel="nofollow">我的常读书</a>。</p>
<p>它们是:</p>
<ol>
<li>我们是同志了。 -- 《三体》</li>
<li>历史也可以写的很好看。 -- 《明朝那些事儿》</li>
<li>我叫阿良，善良的良。 -- 《剑来》</li>
<li>白鹿原上最好的先生死了。-- 《白鹿原》</li>
<li>安禄山起兵了，大唐完了。-- 《血腥的盛唐》</li>
<li>方木之后，再无方木，走好我的朋友。-- 《心理罪》</li>
<li>唯有知识让人高贵。 -- 《时间简史》</li>
<li>黑客与画家的共同点是为了艺术？？？ -- 《黑客与画家》</li>
<li>抬头看天空，低头看道路。 --《人间失格》</li>
<li>社会的变革逃不出历史的预定轨道。-- 《中国通史》</li>
<li>笑容也是一种武器，有空就应该笑一笑。 -- 《七种武器》</li>
<li>官吏之间的互相博弈也很有意思。 -- 《显微镜下的大明》</li>
<li>师生之间的权利传递和斗争艺术。 -- 《大明王朝1566》</li>
<li>气象？境界？不懂~ -- 《人间词话》</li>
<li>以人为主体，事件为载体，讲一些有温度的历史。 -- 《历史的温度》</li>
</ol>
<p>《时间简史》和《中国通史》似乎更加适合比较专业的读者、研究员去研究学习。我推荐去看在B站里的一部同名记录片《中国通史》。视频接受地速度更快，也许更加适合现在我们的生活节奏。</p>
<blockquote>
<p>《中国通史》里面有一个观点：”以今观古，可乎？“。</p>
</blockquote>
<p>所以我们去看历史类读物时，就别太认真了。做一个旁观者，看作者讲好一个故事，就可以啦！</p>
<p>与此同时，并不影响你有自己的猜想和判断。比如：如果王莽的运气好一点点，新朝继续发展，历史会怎样？杨广东征高句丽时，那个冬天如果没那么冷，现在又是什么样的世界格局？如果赤壁的那一把火点不起来？如果把李自成在某一个不知名的山头干掉？</p>
<p>不同的猜想，不同的发展，写一本短篇小说也没什么难事。比如写一写《穿越到XX朝做一个XXXX》。</p>
<hr>
<p>20年初，一本小说火爆全网，它就是《人间失格》。说是什么<strong>魔幻现实主义</strong>的又一代表。特点就是<strong>虚虚实实，真假难辨</strong>。其实，我真的看不出什么，可能是水平不够吧。</p>
<p>在年初，在B站上，看了一个栏目，李健主持的一个拉美地区的主题音乐会。里面提到了马尔克斯，热情桑巴，拉美音乐。他们提起了伦巴舞，动作极其热情，气氛很是旖旎。大家可以找一段伦巴看一下，验证一下。</p>
<p>我大胆地描绘一下场景：水手们上岸了，在这一个港口，他们看到了热情如吉普赛女郎的哥伦比亚少女，站在街边。随手拿了一杯啤酒，拉上了一个女郎，在道路的中心跳起了舞。那少女也舞动着身体，脸上布满了笑容。伴随着手鼓的节奏，肢体摆动的幅度越来越大，她的身体也越来越放松。慢慢地，跳舞的男女一对一对地加入进来，少女们如同提线木偶，听从摆动。音乐声混杂着笑声、吆喝声和叫骂声，在无尽的夜色中越传越远...</p>
<hr>
<p>我看《三体》大概有四五年了，每一年都会翻一翻，看一看。每一次翻感觉都不一样，今年看《三体》的起因是因为，我在B站刷完了一部动画《<a href="https://www.bilibili.com/bangumi/play/ep300998?from=search&amp;seid=14488103964051940387" rel="nofollow">我的三体之章北海传</a>》。</p>
<p>官僚游戏在明朝嘉靖时期迎来了一波高潮，嘉靖的一生就是斗争、斗争，再斗争。帝国权利高层的工作就是斗争、斗争，再斗争。但是基层的权利斗争也同样精彩; 《大明王朝1566》结合《显微镜下的大明王朝》一起看，最好再加上《那些事儿》。</p>
<p>举一个例子，海瑞在做县令时，除了要跟上司斗争还要和底下的小弟们斗争。做好一个官已经很困难了，更别说做一个有作为的清官了。</p>
<hr>
<p>《黑客与画家》是阮一峰老师的翻译作品，在前端范围内，应该无人不识阮老师。</p>
<p>互联网产品的生命周期极其短暂，在旧金山奋斗的打工人们，每一个月都会涌出各种各样的创意，新生力量在不断冲击着硅谷的各种行业，各种职业。从目前的局势看起来，在未来相当长的一段时间内，世界的中心仍然是旧金山，因为那里可以制造出源源不断的新鲜血液。</p>
<p>布局这一发展模式的奠基人大概就是本书的作者保罗了吧。“天使投资计划”给创业者基本的创业资金和技术支持，似乎是真正做到了前浪带动后浪。</p>
<p>我们在github读源码的时候经常会看到一些注释，是这个样子:</p>
<div class="highlight highlight-source-js"><pre class="notranslate"><span class="pl-c">/**</span>
<span class="pl-c">* Hack </span>
<span class="pl-c">* create somthing for build chore</span>
<span class="pl-c">*/</span></pre></div>
<p>书中对Hack的解释是，对某一个问题做出了一个优秀的解答。做出这个优秀解答的作者就是Hacker，音译过来就是”黑客“。</p>
<p>我自认为够不上<strong>优秀</strong>。</p>
<hr>
<p>大唐并不是全时期都是盛世，但是每一个盛世之前都有一段血腥的历史。我不知道这是不是书名的本意，我只知道大唐帝国的光辉，也曾照耀中亚的大地和东南亚的海湾，阴影中躺着无数的白骨和箭矢。</p>
<p>在落日的余晖中，唐明皇回想起自己的一生。如果当时少听一听音乐，多看一看奏本，提前宰了安禄山。现在是不是在太液池和自己心爱的杨贵妃一起跳那支霓裳羽衣舞。</p>
<p>大明宫中，久已不闻破阵乐。</p>
<hr>
<h3>以量取胜，还是质者为王</h3>
<p>似乎是为了弥补在家里待的三个月的时间，自四月开始，我就像上了发条的手表，想停下来都停不下来了。</p>
<p>生活轨迹如同机械表般的规律，上班下班，上班加班下班，后来就更过分了，开始熬夜加班了。现在正好反思一下，为什么加班？什么样的工作量积压才会像我们这样的加班？加班是否真的有效？</p>
<p>首先我们的系统功能很多，单独拿一个业务线出去，就是一个<strong>管理系统</strong>。</p>
<p>项目开始...</p>
<p>在我正式接手开发之后，我终于意识到，我进了一个深坑。试想一下，我给你一个大概的日期，你准备一下，到时候我找你要结果，安排项目上线。当时我就懵了。当我看到原型图上密密麻麻的功能之后，我发誓，我懵早了。</p>
<p>活着干，死了算，时间不够，加班干。两个月后，项目上线了！</p>
<p>当时的开发人力就两个人，一个前端，一个后台。在那一段时间里，面对前端的工作积压，加班消费接口的选择无疑是正确的。但是在项目实际上线运营的前夜，我们还在更改需求。在当时看来，这是一段备受折磨的日子，但是我绝对想象不到，在后期还有一个折磨之王。</p>
<p>三级复核的审核功能可以有多复杂？54个节点的审核功能见过吗，兄弟？</p>
<p>在这个功能开发过程中，我们的团队逐渐成型稳定，功能全部分出去了，我开始全力做这个复核功能。我的第一次熬夜加班献给了这个项目。到现在我终于明白，通宵加班只有0次和无数次。</p>
<p>我接了一个最不应该接的功能<strong>多页签</strong>。现在回想，我有好几种方式可以无侵入解决需求，但是覆水难收，终成困局。现在我只想说一句：”我干~“。</p>
<p>折磨之王上线了！</p>
<p>在我进组开发财务系统后，我完全没有意识到，这将会是一个什么样的折磨项目，一直到现在都是我极力逃避的项目。整个开发时间达到了惊人的2个月，功能通过率不过10%。在这个数据的背后，没有一个人是轻松的，每一个开发都是疲倦的，沧桑的，崩溃的。</p>
<p>”加班“是这个项目的主题词，在这两个月的时间里，我们能做的就是”加班，加班，再加班“。而造成这个局面的是一个”折磨之王“。长叹一口气后，就这样吧都过去了。</p>
<p>我们度过的一段最美好的时光就是现在，终于进入正轨了，迭代中的项目才是最美好的项目。因为我们控制住了功能，在规定时长内能够完成预定的工作，但是有人不开心了，是谁我不想说。</p>
<p>我常开玩笑地说，如果经常加班，那水平一定不咋样，牛逼的人是不加班的。但是我们认真工作在预期内完成的工作，却被认定为工作不饱和。进入迭代后，功能质量被牢牢地控制住了，难道非要让我们做一些超量的工作，但是质量却得不到保障的功能吗？</p>
<p>究竟是量者取胜，还是质者为王？</p>
<h3>有结构的笔画，方圆之中得道</h3>
<p>判定一个男人成熟的标准，是以生理维度为上，还是心智维度最佳？</p>
<p>我不得不承认：冲动的一面将在相当长的一段时间里陪伴着我，同时我将长期与他同行。能改变的是缺点，而改变不了的是弱点。性格缺陷的修补能力大概就是决定心智发育程度的短板。</p>
<p>一时兴起，来练字吧，我总得给自己找一个填补的入口。</p>
<p>不爱正楷爱行书，不爱唐诗爱宋词，找了一套宋词字帖就开始了！</p>
<p>我想，当我进行到离开了田字格，在一页空白的纸上，心静手稳地写出了行列对齐的汉字后，我大概就取得了阶段性的成功了吧！那时的我应该是极其内敛，水波不兴。</p>
<p>初初练字，手抖的极为厉害，可能是因为长时间不正经写字了。正经起来，重新去学写字表现的极为痛苦。第一，心有牵挂，难以平静；第二，长期形成的写字习惯也是重学的阻力；第三，临摹字帖的滋味不太好受。</p>
<p>我练字的最终目的，并不是为了写一手漂亮的汉字，其目的是为了<strong>控制</strong>，即为**“克己”**。一个汉字能否写的好看是控制它的结构，类推一下，是否成人是看能否控制自我心智，慢慢地我发现写好一个字还真不简单！正如做好一个人是那么的困难！</p>
<p>不用刻意地去计较时间，不用刻意地去计较字体，随心而动，随意而发，大概就是《人间词话》中的”气“了吧。</p>
<p>方寸之中，也有大道。</p>
<h3>海平面上的距离</h3>
<blockquote>
<p>关山难越, 谁悲失路之人。萍水相逢, 尽是他乡之客。</p>
</blockquote>
<p>来深圳一年多了，这里很大也很好。它离我家两千里。</p>
<p>那一天我特意早起去海边，朝霞平铺在海平面上，我看着旁边经过的路人和依稀的汽车，沉睡中的城市又开始躁动了。那一刻我强烈的希望回家。</p>]]></content:encoded>
        </item>
    </channel>
</rss>