<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>CosmoLau 的个人博客</title><description>我的奇思妙想</description><link>https://blog.cosmolau.top/</link><language>zh_CN</language><item><title>扩展插件的开发与维护</title><link>https://blog.cosmolau.top/posts/batch-builder/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/batch-builder/</guid><description>Cocos Creator 扩展插件的开发与维护，以及批量构建扩展介绍</description><pubDate>Mon, 18 May 2026 16:44:17 GMT</pubDate><content:encoded>&lt;h1&gt;Cocos Creator 扩展插件的开发与维护&lt;/h1&gt;
&lt;p&gt;本篇文章以我的开源扩展插件 &lt;a href=&quot;https://github.com/CosmoLau/batch-builder&quot;&gt;batch-builder&lt;/a&gt; 作为案例，讲述 Cocos Creator 扩展插件在开发时如何有效的进行版本管理，并搭建一个自动化流水线来用于扩展插件的打包发布与版本检查。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;说明&lt;/strong&gt;&lt;/em&gt;：本篇文章未使用 AI 参与撰写与润色，作为案例的开源插件采用 99.9% 古法编码制作而成，不是瞧不起 AI，而是 AI 太贵用不起，请给我的项目&lt;a href=&quot;https://github.com/CosmoLau/batch-builder&quot;&gt;点个 Star&lt;/a&gt;，或者在&lt;a href=&quot;https://www.ifdian.net/a/CosmoLau?utm_source=copylink&amp;amp;utm_medium=link&quot;&gt;爱发电主页&lt;/a&gt;以及 &lt;a href=&quot;https://ko-fi.com/Z8Z31TPDA1&quot;&gt;ko-fi&lt;/a&gt; 让我能摆脱古法时代！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;项目准备&lt;/h2&gt;
&lt;p&gt;为了降低扩展插件开发的门槛，这个项目使用 Cocos Creator 3.8.7 中提供的 &lt;code&gt;Vue-Element-UI 面板&lt;/code&gt; 作为扩展插件模板来进行开发。大体上来说，这个模板相当于是一个比较标准的 WEB 项目。&lt;/p&gt;
&lt;h2&gt;版本管理&lt;/h2&gt;
&lt;p&gt;在对扩展插件进行版本管理时，需要分两种情况来考虑。&lt;/p&gt;
&lt;h3&gt;独立仓库&lt;/h3&gt;
&lt;p&gt;如果扩展插件需要维护统一的版本，用于多个 Cocos 项目中，那么将创建好的扩展插件项目整个初始化为 Git 项目，此时 &lt;code&gt;.gitignore&lt;/code&gt; 中需要&lt;strong&gt;添加&lt;/strong&gt;以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# npm
node_modules
# 构建产物
/dist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后推荐将扩展插件项目转移到其他路径下，&lt;strong&gt;不要放在 Cocos 项目下&lt;/strong&gt;，依次来将扩展差将与项目分开，需要进行开发时，在 Cocos Creator 编辑器中 &lt;code&gt;扩展管理器&lt;/code&gt; 里 &lt;code&gt;导入扩展文件(.zip)&lt;/code&gt; 旁&lt;strong&gt;下拉菜单&lt;/strong&gt;，通过 &lt;code&gt;开发者导入&lt;/code&gt; 来将整个扩展插件项目进行导入，这会在原本 Cocos 项目下的 &lt;code&gt;extensions&lt;/code&gt; 目录中创建一个软链接用来在开发时使用。&lt;/p&gt;
&lt;h3&gt;Cocos 项目仓库&lt;/h3&gt;
&lt;p&gt;如果扩展插件就专门为这一个 Cocos 项目而开发的，那完全可以一并提交到 Cocos 的 Git 仓库中，这时就需要确认 Cocos 项目的 &lt;code&gt;.gitignore&lt;/code&gt; 忽略文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# npm 必须忽略，否则会增加仓库体积
node_modules
# 可选，推荐忽略构建产物
# 第一次拉取仓库时 build 一遍即可
/extensions/${扩展插件名}/dist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;注意&lt;/strong&gt;&lt;/em&gt;：这里的 dist 忽略需要精确到扩展插件，避免把其他从扩展商店下载的插件给忽略了。&lt;/p&gt;
&lt;h2&gt;自动化流水线&lt;/h2&gt;
&lt;p&gt;自动化流水线主要是用于扩展插件作为独立仓库时，用来自动化构建打包与发布。&lt;/p&gt;
&lt;p&gt;如果提交到 Cocos 项目的仓库中，一般来说只需要拉取代码后，执行一遍 build 命令即可，或者编写一个 &lt;code&gt;git hooks&lt;/code&gt;，用来在拉取代码时，如果有扩展插件中的文件变动，自动执行一遍 build 命令，本篇文章不涉及这个内容，就不详细说明，可以直接让 AI 写一个钩子脚本。&lt;/p&gt;
&lt;p&gt;当作为独立仓库提交时，如果提交的远端 Git 仓库支持 CI/CD，就可以编写一套自动化流水线来构建并发布扩展插件包，这里我们以 GitHub Actions 作为例子，参考 &lt;a href=&quot;https://github.com/CosmoLau/batch-builder/blob/main/.github/workflows/release.yml&quot;&gt;release.yml&lt;/a&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Release

permissions:
  contents: write

# 推送 v 开头的标签时触发这个 Action
on:
  push:
    tags:
      - &apos;v*&apos;

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # 检出仓库
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          # 这里 fetch-depth 设置为 0，是下面 changelog 需要
          fetch-depth: 0

      # 设置 node 环境
      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          registry-url: https://registry.npmjs.org/
          # 可以更换为开发环境中使用的 node 版本
          node-version: lts/*
          cache: &apos;npm&apos;

      # 安装依赖
      - name: Install dependencies
        run: npm install

      # 构建项目
      - name: Build project
        run: npm run build

      # 这里读取 package.json 中的 name 来命名压缩包
      - name: Read package name and package files
        id: meta
        run: |
          PKG_NAME=$(node -p &quot;require(&apos;./package.json&apos;).name&quot;)
          echo &quot;pkg_name=${PKG_NAME}&quot; &amp;gt;&amp;gt; &quot;$GITHUB_OUTPUT&quot;

      # 压缩打包
      # 其中 dist、i18n、package.json 是必须的
      # 其他内容是否打包，需要根据项目情况而定
      - name: Create zip archive
        run: |
          ZIP_NAME=&quot;${{ steps.meta.outputs.pkg_name }}.zip&quot;
          zip -r &quot;${ZIP_NAME}&quot; \
            dist \
            i18n \
            logo.png \
            README* \
            package.json
          echo &quot;Created archive: ${ZIP_NAME}&quot;

      # 发布打包后的压缩包
      - name: Upload release asset
        uses: softprops/action-gh-release@v2
        with:
          files: ${{ steps.meta.outputs.pkg_name }}.zip

      # 自动化生成 changelog
      - name: Write changelog
        run: npx changelogithub # or changelogithub@0.12 to ensure a stable result
        env:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在压缩打包阶段，其实核心的只有 &lt;code&gt;dist&lt;/code&gt; 和 &lt;code&gt;package.json&lt;/code&gt; 两个内容，其他的都可以不要，但爱看官方文档的小伙伴就会问了，在&lt;a href=&quot;https://docs.cocos.com/creator/3.8/manual/zh/editor/extension/install.html#%E6%89%93%E5%8C%85%E6%89%A9%E5%B1%95&quot;&gt;打包扩展&lt;/a&gt;里说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;dist&lt;/code&gt;、&lt;code&gt;i18n&lt;/code&gt;、&lt;code&gt;node_module&lt;/code&gt;、&lt;code&gt;package.json&lt;/code&gt;、&lt;code&gt;static&lt;/code&gt; 这几个文件（夹）为必选，缺一不可&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们这里详细盘一下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文件（夹）&lt;/th&gt;
&lt;th&gt;必选&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dist&lt;/td&gt;
&lt;td&gt;√&lt;/td&gt;
&lt;td&gt;扩展插件产物&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;如果不涉及 i18n，这是可选的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node_modules&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;vite 在构建时，会进行 tree shaking，需要的 npm 包实际上已经在 dist 中了&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;package.json&lt;/td&gt;
&lt;td&gt;√&lt;/td&gt;
&lt;td&gt;Cocos Creator 的扩展管理器会根据这个来运行扩展&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;static&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;这个看项目需要，如果没有用到，可以不用打包&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;那么代码里的 &lt;code&gt;logo.png&lt;/code&gt; 和 &lt;code&gt;README*&lt;/code&gt; 又是干嘛的呢？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./batch-builder_explain.png&quot; alt=&quot;扩展管理器说明&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;logo.png&lt;/code&gt;&lt;/strong&gt;：在扩展管理器中显示的&lt;strong&gt;扩展插件图标&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;README.zh.md&lt;/code&gt;&lt;/strong&gt;：在扩展管理器中显示的&lt;strong&gt;资源介绍&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里吐槽一下，既然编辑器不开源，这些奇奇怪怪的规则至少也该写在文档里吧，&lt;code&gt;平台支持&lt;/code&gt; 这一字段连官方扩展都从来没用过，不会官方自己都忘了这是怎么用的吧？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外，流水线的最后一步是自动化编写发布时的 ChangeLog，这个需要在编写 git commit 时遵循&lt;a href=&quot;https://www.conventionalcommits.org/zh-hans/v1.0.0/&quot;&gt;约定式提交&lt;/a&gt;规范。&lt;/p&gt;
&lt;h3&gt;版本检测&lt;/h3&gt;
&lt;p&gt;如果需要做版本检测，可以使用 &lt;a href=&quot;https://docs.github.com/zh/rest?apiVersion=2026-03-10&quot;&gt;GitHub API&lt;/a&gt; 来获取 Release 中最新发布的版本号，&lt;a href=&quot;https://github.com/CosmoLau/batch-builder/blob/main/src/panels/scripts/checkUpdate.ts&quot;&gt;示例插件中的版本检测&lt;/a&gt;就使用了这个方法来判断是否有新版本，然后通过 &lt;a href=&quot;https://github.com/CosmoLau/batch-builder/releases/latest&quot;&gt;https://github.com/CosmoLau/batch-builder/releases/latest&lt;/a&gt; 来跳转最新发布页，&lt;/p&gt;
&lt;h2&gt;踩坑经验&lt;/h2&gt;
&lt;h3&gt;依赖包版本&lt;/h3&gt;
&lt;p&gt;在这个扩展插件模板中，除了 &lt;code&gt;vite&lt;/code&gt; 以外，大部分的依赖包都可以放心升级到最新版本，使用 &lt;code&gt;npm install xxx@latest&lt;/code&gt; 升级即可。&lt;/p&gt;
&lt;p&gt;那么为什么 &lt;code&gt;vite&lt;/code&gt; 依赖不行呢？因为模板中使用了一个官方编写的 &lt;code&gt;@cocos-fe/vite-plugin-cocos-panel&lt;/code&gt; vite 插件来处理打包构建的流程，但是这个 vite 插件并没有开源，而插件本身没有对 vite 新版本进行兼容性处理，所以唯独 &lt;code&gt;vite&lt;/code&gt; 依赖不要进行升级。&lt;/p&gt;
&lt;h3&gt;node 版本&lt;/h3&gt;
&lt;p&gt;在示例项目中，会发现有个 &lt;a href=&quot;https://github.com/CosmoLau/batch-builder/blob/main/.node-version&quot;&gt;.node-version&lt;/a&gt;，与 &lt;code&gt;package.json&lt;/code&gt; 中的 &lt;code&gt;engines.node&lt;/code&gt; 字段相同，都设置为了 &lt;code&gt;20.15.1&lt;/code&gt; 这个 node 版本号。&lt;/p&gt;
&lt;p&gt;这么做的目的是告诉开发者，当这个插件在 Cocos Creator 编辑器中运行时，打印 &lt;code&gt;process.version&lt;/code&gt; 显示的版本号，也就是说 Cocos Creator 的 node 运行环境为 &lt;code&gt;20.15.1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;发现这个问题是在示例项目中使用 node 内置的 &lt;code&gt;fs.glob&lt;/code&gt; 时，发现编辑器中并不支持，这种情况就老老实实用 &lt;code&gt;glob&lt;/code&gt; npm 包就行了。&lt;/p&gt;
&lt;h3&gt;Element-plus 的根 DOM&lt;/h3&gt;
&lt;p&gt;如果是用 &lt;code&gt;Vue-Element-UI 面板&lt;/code&gt; 这个模板创建扩展插件项目的话，示例代码中已经提供了依赖注入，在 &lt;code&gt;App.vue&lt;/code&gt; 中有如下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
import { inject } from &apos;vue&apos;;
import { ElMessage } from &apos;element-plus&apos;;
import { keyAppRoot, keyMessage } from &apos;./provide-inject&apos;;

const appRootDom = inject(keyAppRoot);
const message = inject(keyMessage)!;

const open = () =&amp;gt; {
    ElMessage({
        message: &apos;show message&apos;,
        appendTo: appRootDom,
    });
};

function open2() {
    message({ message: &apos;show inject message&apos; });
}

&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style scoped&amp;gt;
/* ... */
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 Element-plus 中的很多弹窗类组件，需要挂载到根 DOM 下才能正常显示，也就是代码中的 &lt;code&gt;appRootDom&lt;/code&gt;，一般来说，这种类型的组件都会提供一个 &lt;code&gt;append-to&lt;/code&gt; 属性，这个属性就是在这里使用的，例如在 &lt;code&gt;el-tooltip&lt;/code&gt; 中使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;el-tooltip
    content=&quot;打开构建面板，导出构建配置&quot; 
    :append-to=&quot;appRootDom&quot; 
    effect=&quot;light&quot;
    placement=&quot;bottom&quot;&amp;gt;
&amp;lt;/el-tooltip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;外部链接&lt;/h3&gt;
&lt;p&gt;如果在扩展插件中使用 &lt;code&gt;windows.open&lt;/code&gt; 方法来打开外部链接，会打开一个新的 Electron 窗口来打开。&lt;/p&gt;
&lt;p&gt;想要解决这个方法，要么使用官方的 &lt;code&gt;&amp;lt;ui-link&amp;gt;&lt;/code&gt; 标签，要么使用 &lt;code&gt;&amp;lt;el-link&amp;gt;&lt;/code&gt; 标签，示例插件中用来触发 Element-plus 标签事件的方法来进行了 hack 操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function linkToRelease() {
    if (!canUpdate.value) return;
    // 使用 window.open 会打开一个 Electron 窗口
    // 所以这里模拟 el-link 点击来打开链接
    (githubLink.value.$el as HTMLElement).click();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;连续构建&lt;/h3&gt;
&lt;p&gt;在扩展插件开发时，遇到过好几次构建后脚本缺失的情况，参见&lt;a href=&quot;https://github.com/cocos/cocos-engine/issues/19024&quot;&gt;3.8.7 命令行连续构建，会有几次出现脚本丢失的情况&lt;/a&gt;这个 issue。&lt;/p&gt;
&lt;p&gt;由于中途跟换过开发设备，感觉这个问题在低配置的机器上出现概率比较大，如果各位开发者在开发中仍然遇到这个问题，可以参考示例扩展插件中的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过 &lt;code&gt;is missing or invalid&lt;/code&gt; 类似的日志内容来判断是否再构建时有丢失脚本。&lt;/li&gt;
&lt;li&gt;在丢失脚本的情况下，对构建进行重试。&lt;/li&gt;
&lt;li&gt;构建之前检查资源数据库是否准备好（&lt;code&gt;query-ready&lt;/code&gt; 消息），这个其实也没法保证构建不会丢失脚本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;示例扩展插件简介&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;本篇文章的示例扩展插件已开源，详细说明可以到 &lt;a href=&quot;https://github.com/CosmoLau/batch-builder&quot;&gt;batch-builder 仓库&lt;/a&gt;和&lt;a href=&quot;https://github.com/CosmoLau/batch-builder/blob/main/README.zh.md&quot;&gt;插件资源介绍&lt;/a&gt;中查看，这里只做简单介绍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;batch-builder 是一个批量构建项目的插件，由于项目需求，Cocos Creator 中的每个 &lt;code&gt;.scene&lt;/code&gt; 场景文件都作为一个单独的项目进行打包构建，其数量在几十个左右，未来可能会更多。在这种情况下，如果要使用 Cocos 的构建面板，每个项目都需要单独勾选场景和 bundle，在场景文件数量非常多时，这是非常低效且容易犯错的重复工作，所以本扩展插件应运而生。&lt;/p&gt;
&lt;p&gt;为了减小项目体积，每个场景文件专属的资源会放在同名的 bundle 包下，而整个项目共用的资源会放在 &lt;code&gt;resources&lt;/code&gt; 目录下，做好这个约定后，才能统一构建流程。&lt;/p&gt;
&lt;p&gt;这个扩展插件的构建方式是基于&lt;strong&gt;命令行&lt;/strong&gt;的，这样才能对构建配置进行高度自定义，所以这里有个可以优化的点，在使用这个扩展插件时，需要先在 &lt;code&gt;构建面板&lt;/code&gt; 中对任意一个项目进行一次正常构建，构建成功后将构建配置文件进行导出，以供扩展插件使用。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;扩展&lt;/code&gt; -&amp;gt; &lt;code&gt;批量构建工具 🛠️&lt;/code&gt; 打开扩展的面板后，填入所需内容，就可以在 &lt;code&gt;项目列表&lt;/code&gt; 里多选需要批量构建的场景文件，然后点击构建即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./batch-builder.png&quot; alt=&quot;batch-builder&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;这篇文章和这个插件如果再不发布，等 &lt;code&gt;PinK&lt;/code&gt; IDE 和 &lt;code&gt;Cocos-cli&lt;/code&gt; 正式上线，就要过时了:cry:。为了证明在 Creator 时期待过，以此为纪念。&lt;/p&gt;
&lt;p&gt;我相信 AI 应该能轻松复刻这个扩展插件，但是 Cocos 在 Creator 时期，文档别说是 AI 不友好了，甚至是“人类不友好”，希望 Cocos 能在 SUD 接手下，有个体面的&lt;s&gt;结局&lt;/s&gt;未来。&lt;/p&gt;
</content:encoded></item><item><title>2025 年终总结</title><link>https://blog.cosmolau.top/posts/summary_2025/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/summary_2025/</guid><description>又一年结束了，这一年我到底干了些什么？</description><pubDate>Fri, 19 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;2025 年终总结&lt;/h1&gt;
&lt;p&gt;从今年开始，如果没什么大变故的话，打算坚持每年年底写一个年终总结，记录一下今年的生活、发现的有趣项目、学到的新知识，亦或是谈谈自己的想法之类的，内容可能会比较庞杂混乱，所以主要还是作为记录留档。&lt;/p&gt;
&lt;h2&gt;站点建设&lt;/h2&gt;
&lt;p&gt;目前呈现本篇内容的站点是一个博客站点，我将其解析到了 &lt;code&gt;blog.cosmolau.top&lt;/code&gt; 这个三级域名下，并将其存储在 GitHub 仓库中，通过 GitHub Pages 进行部署。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;CosmoLau/blog&quot;}&lt;/p&gt;
&lt;p&gt;但其实现在 &lt;code&gt;www.cosmolau.top&lt;/code&gt; 站点也是一个博客站点，这个站点是我一开始部署站点，后面我将其迁移到 &lt;code&gt;blog.cosmolau.top&lt;/code&gt; 这个三级域名下，并做了些许的个性化更改。&lt;/p&gt;
&lt;p&gt;&amp;lt;www.cosmolau.top&amp;gt; 站点的内容是存储在 &lt;a href=&quot;https://github.com/CosmoLau/site&quot;&gt;https://github.com/CosmoLau/site&lt;/a&gt; 仓库里，他是用 &lt;code&gt;Hexo&lt;/code&gt; 搭建的博客，使用的 &lt;code&gt;Vivid&lt;/code&gt; 作为博客主题。因为 &lt;code&gt;Vivid&lt;/code&gt; 的作者不再维护这个 &lt;code&gt;Hexo&lt;/code&gt; 的主题，转投到了基于 &lt;code&gt;Astro&lt;/code&gt; 的 &lt;code&gt;Fuwari&lt;/code&gt; 项目上，所以我也跟着对博客进行了迁移（就是本篇内容呈现的样子）。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;CosmoLau/site&quot;}&lt;/p&gt;
&lt;p&gt;当时在考虑迁移博客的时候，我进行了一个简单的规划，我认为 &lt;code&gt;www.cosmolau.top&lt;/code&gt; 或者说 &lt;code&gt;cosmolau.top&lt;/code&gt; 这个域名不应该用来展示我的博客内容，而应该作为我个人的作品集展示页面，这样才能更好的 showcase，不过羞于至今为止都没有什么拿得出手的项目，所以到现在也没能对作品集页面进行装修。&lt;/p&gt;
&lt;p&gt;基于以上想法，对作品集页面的装修工作将作为我 2026 年的目标之一，我希望这个作品集页面不光作为一个自我介绍的页面，也能见证我在技术上的成长，让我的目标更加清晰。&lt;/p&gt;
&lt;h2&gt;生活与工作&lt;/h2&gt;
&lt;p&gt;基于各种原因，我从 2023 年 10 月就开始在家啃老，一直到 2025 年 8 月才总算找到了工作，不论如何，也算是重新走上了正轨吧。&lt;/p&gt;
&lt;p&gt;在家里呆着的这 2 年，其实整个人也是非常煎熬的，每天没有事情干，程序也不想写，只能颓废地打游戏。对于一个普通人来说，梦想真的是奢望，没有经济也没有坚定的信念，就只是空谈，一场幻想罢了。&lt;/p&gt;
&lt;p&gt;作为一个从小喜欢玩游戏的重度玩家，到初入职场进入游戏开发行业，我仍然想要做出一款自己的游戏，但至今一事无成。信念啊，金钱啊，时间啊，都是我的借口，一直都只是在逃避，没有真正迈出这一步。但是今年借助 AI 的辅助，真让我成功开发了两个总算看得过去的 DEMO，我认为这是个好兆头，也许我之前连一个 DEMO 都做不出来的原因，就是缺一个全能型的开发搭子。我让 AI 帮我写测试用的数值，帮我分析策划案，真的能让我事半功倍，也比以往更有兴致，觉得至少我想的玩法有个明确的开发方向了。&lt;/p&gt;
&lt;p&gt;2026 年，希望能把现在的工作稳住，然后在 AI 的加持下，完成一款能达到上架水准的完整游戏。&lt;/p&gt;
&lt;h2&gt;年度新物&lt;/h2&gt;
&lt;p&gt;今年开始，我会记录一些新发现的、不错的、甚至已经替换进我的工作流中的应用、网站、软件、硬件或者其他什么的。&lt;/p&gt;
&lt;h3&gt;笔记✍🏻&lt;/h3&gt;
&lt;p&gt;在笔记这方面，我因为在第一份工作结束时，忘记备份笔记，所以在这方面非常懊悔。从那时起，我在 GitHub 上建了一个名为 &lt;code&gt;MyNote&lt;/code&gt; 的仓库来管理我所有的笔记。因为我现在都是用 VSCode 作为编辑器来写 Markdown，所以这一套流程还算是比较方便，甚至在今年折腾的过程中，发现可以在 &lt;a href=&quot;https://vscode.dev/&quot;&gt;vscode.dev&lt;/a&gt; 上非常丝滑的拉取 GitHub 仓库并修改推送，满足了跨平台笔记编写的需求，唯一的缺点就是在手机上访问 vscode.dev，会显得非常的局促，不过用来应急完全是够用的。&lt;/p&gt;
&lt;p&gt;当然，我也在寻找一些其他的笔记方案，目前让我比较满意的一个方案就是 &lt;a href=&quot;https://www.notion.com/&quot;&gt;Notion&lt;/a&gt;。Notion 可以说是功能非常强大的一个笔记应用了，也支持几乎所有平台（包括在 web 上直接访问），我想不出有什么很致命的缺点，可能国内访问不太稳定算一个缺点吧，还有在我的小米平板7S Pro 上识别键盘有点问题，不过这个已经修复了，虽然不知道是软件的原因还是硬件的原因导致的。&lt;/p&gt;
&lt;p&gt;&amp;lt;svg role=&quot;img&quot; width=&quot;100&quot; viewBox=&quot;0 0 24 24&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&amp;gt;&amp;lt;title&amp;gt;Notion&amp;lt;/title&amp;gt;&amp;lt;path d=&quot;M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z&quot;/&amp;gt;&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h3&gt;Git 客户端&lt;/h3&gt;
&lt;p&gt;我在大学时没怎么使用 Git，当开始工作时，Git 成为了必要工具，而我一开始接触到的就是带有图形化界面的 Git 客户端 &lt;a href=&quot;https://www.sourcetreeapp.com/&quot;&gt;SourceTree&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;说实话，SourceTree 让我又爱又恨，它几乎是陪伴我至今的 Git 客户端，但其在 Windows 上的性能很差劲。直到我在 V2EX 上看到一篇&lt;a href=&quot;https://www.v2ex.com/t/1177732&quot;&gt;讨论 Git 客户端的贴子&lt;/a&gt;，评论区有人推荐了国人开发的开源 Git 客户端 &lt;a href=&quot;https://github.com/sourcegit-scm/sourcegit&quot;&gt;SourceGit&lt;/a&gt;，才让我彻底抛弃陪伴已久的 SourceTree。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;sourcegit-scm/sourcegit&quot;}&lt;/p&gt;
&lt;p&gt;当然，这篇贴子中提到的几款 Git 客户端产品我也有用过，但我体验下来后的感觉是：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Git 客户端&lt;/th&gt;
&lt;th&gt;感受&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ugit&lt;/td&gt;
&lt;td&gt;腾讯系，内置一大堆我用不到的功能，太臃肿&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fork&lt;/td&gt;
&lt;td&gt;非常好，但是不支持多语言，我有多语言强迫症&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitKraken&lt;/td&gt;
&lt;td&gt;收费，不考虑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tortoise git&lt;/td&gt;
&lt;td&gt;疯狂原始龟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;github desktop&lt;/td&gt;
&lt;td&gt;也是不支持多语言&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;所以基于体验后的感受，最后选择了 SourceGit，应该至少会长期使用一段时间，不过在最近的使用中，已经发现一个 BUG，问题倒不是很严重，就是当文件只读时，无法提交，已经在相关 issue 中回复了，希望 BUG 都能今早修复吧。&lt;/p&gt;
&lt;p&gt;当然，没有使用 Git 客户端的习惯的话，直接使用 IDE 自带的 Git 也能满足基本需求。&lt;/p&gt;
&lt;h3&gt;数码产品&lt;/h3&gt;
&lt;p&gt;今年终于找到工作了，有收入来源了，终于可以消费了，还是列个表格来讲自己至今的感受，表格按照购入顺序排序：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;产品&lt;/th&gt;
&lt;th&gt;感受&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;小米平板7S Pro&lt;/td&gt;
&lt;td&gt;小米自研玄戒O1 CPU，感觉性能还是差了点，很多游戏甚至跑不到 60 帧，还是说平板都这样？不过看视频是真爽&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iPhone17&lt;/td&gt;
&lt;td&gt;有史以来最值得升级的一代，立刻换下我的 iPhone 11，高刷快充（？）无需多言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;机械革命 星耀14&lt;/td&gt;
&lt;td&gt;1.05KG 轻薄本，目前我已经找好笔记本电脑的定位，一定要轻，打游戏就应该在台式机上去享受大屏幕，而不是笔记本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AirPodsPro 3&lt;/td&gt;
&lt;td&gt;我的第一个无线耳机，延迟挺高不适合游戏使用，其他场景基本没啥问题，也说不上好坏吧，毕竟我也没用过别的无线耳机&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;家里有一台 2016 年上大学时买的 i5 6300hq + GTX960M 的笔记本电脑，现在运行 Windows 10 都有点费劲，最近有看到不少人开始使用 Linux Desktop，我也萌生了这样的想法，有时间给这台老笔记本电脑装个 Linux，看能不能焕发第二春。&lt;/p&gt;
&lt;h3&gt;AI&lt;/h3&gt;
&lt;p&gt;今年应该说 AI 非常火热，各种神仙打架，但是我基于不想折腾网络的原因，所以在 AI 使用方面比较保守，代码编辑器用的字节家的 &lt;code&gt;Trae&lt;/code&gt;，信息检查还是用的 &lt;code&gt;DeepSeek&lt;/code&gt;，感觉要让我走上 AI 付费的道路，还得看我经济积累得如何，目前感觉能用就行。&lt;/p&gt;
&lt;h2&gt;技术栈&lt;/h2&gt;
&lt;p&gt;我之前有想过做一个记录自己技术掌握程度的应用，但是在做成之前，&lt;a href=&quot;https://roadmap.sh/&quot;&gt;roadmap.sh&lt;/a&gt; 是我觉得很不错的一个替代产品，我目前时不时都会在上面更新一下我的掌握情况。&lt;/p&gt;
&lt;p&gt;由于今年重新开始参加工作的原因，我算是强行把一些以前想学习的技术栈落实了下来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vue：业务需求要做 &lt;code&gt;uniapp&lt;/code&gt;，要用到 Vue2，做 Cocos Creator 的扩展开发会用到 Vue3，以前认为 Vue 用着没什么难点，直到那个奇怪的响应式对象引用搞的我有点头大，这就是一部分人说 Vue 是黑魔法的原因吗？&lt;/li&gt;
&lt;li&gt;React：React 也有想吐槽的地方，返回的 HTML 代码块如果需要处理逻辑判断，会显得非常的乱，这点可能没 Vue 的代码和样式分离来的清晰，但是在 JS/TS 代码编写这块，感觉还是更本源一点，暂时没有遇到 Vue 中类似的一些坑。&lt;/li&gt;
&lt;li&gt;Elysia.js：我现在基本上都是使用 &lt;code&gt;bun&lt;/code&gt; 作为包管理器，也借此了解到 &lt;code&gt;Elysia.js&lt;/code&gt; 这个后端框架，之前用过 &lt;code&gt;express&lt;/code&gt;、&lt;code&gt;koa&lt;/code&gt; 之类的，我感觉使用起来也都没啥差别吧，既然 Elysia.js 说自己性能强，那我就索性一步到位了。然后不出意外的话，就出意外了，他的静态插件不知道是什么原因，打开静态目录下的文件超过一定数量就会有缺失了，后面还是把这一块的工作交给了 Vite 来完成。&lt;/li&gt;
&lt;li&gt;uniapp：如上面所说，业务需要，然后用了之后硬生生给我干成工伤。如果没有跨平台小程序需求，我觉得我应该永远不会使用 uniapp 来开发程序，强绑 HBuilderX 太让人难受了，我现在都是开发用 VSCode 来做，预览打包才在 HBuilder 上进行，甚至预览也不如浏览器上直接预览，DCloud 别抱着你那 HBuilderX 了，拥抱 VSCode 生态不好吗？现在的 AI 编辑器也都是用 VSCode 改的了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然还有我最爱的本职技术栈 Cocos，在我觉得他马上要死的时候，他被 SUD 以 5 亿人民币收购了，近期也是规划了 &lt;code&gt;PinK AI 编辑器&lt;/code&gt; 和 &lt;code&gt;Cocos Creator 4.x&lt;/code&gt;，那我还能说什么呢，能不能拳打 LayaBox、Godot，脚踢 Unity、Unreal，Make Cocos Great Again！&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;总之，2025 年马上要过去了，后面日子希望我真的能踏上正轨，我还有很多想做的事没做，想学的东西没学，不求大富大贵，但求个稳定吧。&lt;/p&gt;
&lt;p&gt;也在此督促一下自己，明年记得也要写一篇年终总结。&lt;/p&gt;
</content:encoded></item><item><title>在安卓平板上编写代码</title><link>https://blog.cosmolau.top/posts/coding_on_android/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/coding_on_android/</guid><description>安装平板真的有生产力吗？</description><pubDate>Wed, 27 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;在安卓平板上编写代码&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;生产力？伪命题？平板电脑真能敲代码吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;时隔两年总算找到份自己觉得合适的工作，不过出门工作，就得和家里亲手 DIY 的台式机告别了，虽然还有一台笔记本电脑可以凑合，但是它 2016 年的性能已经被我唾弃了。于是乎在考虑入手下一台笔记本电脑之前，我准备先买一个平板电脑过度，这也让 5 年没接触过安卓设备的我重新认识一下现在的安卓，就这样入手了一部&lt;strong&gt;小米平板7S Pro&lt;/strong&gt;作为我现在少有“生产力工具”。&lt;/p&gt;
&lt;p&gt;都说平板电脑拿来当“生产力工具”是伪命题，那么当你看到本篇文章被发布时，至少说明了平板电脑在写代码这一块，还是有那么一丢丢的生产力的。&lt;/p&gt;
&lt;h2&gt;准备工作&lt;/h2&gt;
&lt;p&gt;首先需要说明一下，我本职工作是游戏开发，但是一般的游戏开发都会使用到游戏引擎，而大部分游戏引擎应该只有 Windows 和 MacOS 应用，而且开发过程比较复杂，所以游戏开发其实并不是本篇文章的目的。&lt;/p&gt;
&lt;p&gt;而我另一个兴趣，就是 TypeScript 全栈开发，对于 Web APP 的跨平台性而言，应该在任何设备上进行都不在话下。在此之前，需要确认一下我们的需求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手上有一个平板电脑，且最好配备蓝牙鼠键（至少也得有个键盘）&lt;/li&gt;
&lt;li&gt;有前后端的开发需求&lt;/li&gt;
&lt;li&gt;使用 VScode 作为主力编辑器&lt;/li&gt;
&lt;li&gt;使用 GitHub 作为主力存储仓库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果满足以上需求，那么接下来的内容应该非常适合你。&lt;/p&gt;
&lt;h2&gt;vscode.dev——代餐&lt;/h2&gt;
&lt;p&gt;如果你的需求相比上面的更简单，仅仅只是想编辑一下 GitHub 仓库里的代码，那么使用 &amp;lt;vscode.dev&amp;gt; 这个网页版的 VScode 其实就能满足需求了，而且它能登录微软账户，同步你的 VScode 配置，保证你的插件生态体验，&lt;/p&gt;
&lt;p&gt;但是网页版 VScode 唯一的缺点就是没有终端，不过想来也是，微软也不会白白送一个开发环境。&lt;/p&gt;
&lt;p&gt;但是即使如此，你如果有一个配置好 CI/CD 的博客仓库，需要更新博客文章，那么 &amp;lt;vscode.dev&amp;gt; 几乎是完美的代餐。&lt;/p&gt;
&lt;h2&gt;Termux——Android Subsystem for Linux&lt;/h2&gt;
&lt;p&gt;提到安卓设备上编写代码，那么肯定绕不快 Linux 环境的搭建，只要上网一搜，Termux 肯定是首选方案，甚至没有之一。&lt;/p&gt;
&lt;p&gt;推荐在 &lt;code&gt;F-Droid&lt;/code&gt; 商店下载 Termux 最新版。&lt;/p&gt;
&lt;p&gt;下载好 Termux 后，当然就是搭建一个完整的 Linux 环境。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 更新 Termux 的包管理器
pkg update
pkg upgrade
# 如果无法下载，可能需要更换源
termux-change-repo
# 如果要访问存储，需要申请权限
termux-setup-storage
# 安装 proot
pkg install proot-distro
# 查看可安装的 Linux 系统
proot-distro list
# 安装自己熟悉的 Linux 系统，我这里使用 ubuntu
proot-distro install ubuntu
# 登录 ubuntu
proot-distro login ubuntu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据以上步骤，环境就算是搭建完成了，可能还需要在设置里打开开发者模式（连点系统版本号），然后在设置里搜索 &lt;code&gt;停止限制子进程&lt;/code&gt; 并打开此选项。&lt;/p&gt;
&lt;h2&gt;code-server——启动&lt;/h2&gt;
&lt;p&gt;Termux 安装好 Linux 环境后，就是搭建开发环境了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 确保使用 proot-distro login ubuntu 进入 Linux 系统

# 安装 code-server
curl -fsSL https://code-server.dev/install.sh | sh
# 查看 code-server 版本号，确认是否安装成功
code-server --version
# 查看并复制 code-server 密码
cat /root/.config/code-server/config.yml
# 其中 password 就是我们等会需要使用的密码
# 启动 code-server 服务
code-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完成以上操作后，就可以打开浏览器，访问 &lt;code&gt;127.0.0.1:8080&lt;/code&gt; 使用 VScode 了。&lt;/p&gt;
&lt;p&gt;这个 VScode 是有终端可以使用的，但是不能同步微软账号，插件系统中的插件也不一定能运行（可能是缺少环境）。&lt;/p&gt;
&lt;h2&gt;编码环境&lt;/h2&gt;
&lt;p&gt;因为我是做 TypeScript 全栈开发，那么 Node 环境是必备的，我习惯起手安装 &lt;code&gt;nvm&lt;/code&gt;，到 &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm 官方仓库&lt;/a&gt; 找到安装脚本运行即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里需要注意一下，安装完成后可能需要重启 linux，我们使用 &lt;code&gt;exit&lt;/code&gt; 命令退出到 Termux 后重新登录即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 退出 linux
exit
# 重新登录
proot-distro login ubuntu
# 然后就可以使用 nvm 了
nvm -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装好 Node 环境后，在安装一个 Bun 来运行 Elysiajs 后端框架&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 安装 Bun
curl -fsSL https://bun.sh/install | bash
# 安装完成后同样用重启 linux
exit
proot-distro login ubuntu
# 创建一个文件夹用来存放工程
mkdir workspace
cd workspace
# 生成一个 Elysiajs 项目
bun create elysia app
cd app
bun run dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完成后在浏览器中新建标签页，访问 &lt;code&gt;localhost:3000&lt;/code&gt; 即可看到 &lt;code&gt;Hello Elysia&lt;/code&gt; 啦。&lt;/p&gt;
&lt;h2&gt;其他说明&lt;/h2&gt;
&lt;p&gt;如果按照以上步骤跟下来，使用 &lt;code&gt;bun create astro app&lt;/code&gt; 或者 &lt;code&gt;bun create vue app&lt;/code&gt; 之类的命令来初始化框架可能会遇到报错，这些大概率都是缺少其他环境导致的，只需要把报错扔给 AI，让 AI 帮你解决即可。&lt;/p&gt;
&lt;h2&gt;后记&lt;/h2&gt;
&lt;p&gt;至此，本篇文章结束，如果对你有帮助的话，世界上也会少一个沦为泡面压的平板电脑，如果当你看到这篇文章出现在博客，那么我可以很高兴的告诉你，本篇文章的更新来自我的 &lt;code&gt;小米平板7S Pro&lt;/code&gt;。&lt;/p&gt;
</content:encoded></item><item><title>Windows 11 安装相关备忘录</title><link>https://blog.cosmolau.top/posts/windows/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/windows/</guid><description>感觉最近总是遇到一些系统问题，导致需要重装 Windows 11，所以做个备忘以备不时之需</description><pubDate>Tue, 12 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;安装系统应该算是一个不太频繁，但又很必要的操作，恰恰就是其频率不高，导致每次遇到的时候总会忘记一些之前踩过的坑，所以便有了本章作为一个踩坑备忘录。&lt;/p&gt;
&lt;h1&gt;情景&lt;/h1&gt;
&lt;p&gt;试想一下，一般需要安装 &lt;strong&gt;Windows 11&lt;/strong&gt; 系统是在哪些情况下？就我个人而言，应该有以下几种情况：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mindmap
    root(安装 Windows 11)
        购入新电脑
        电脑故障
        入职新公司
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其实主要就是 &lt;code&gt;新装系统&lt;/code&gt; 和 &lt;code&gt;重装系统&lt;/code&gt; 两种情况，两者的区别不大，但是 &lt;code&gt;重装系统&lt;/code&gt; 可能多一些坑，我在下文会提到。&lt;/p&gt;
&lt;h1&gt;备忘&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这部分我会按照先后顺序来记录。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;事前准备&lt;/h2&gt;
&lt;p&gt;如果是 &lt;code&gt;购入新电脑&lt;/code&gt; 的情况，对于 &lt;code&gt;笔记本电脑&lt;/code&gt; 来说，一般来说不太需要什么准备，电脑生产厂商应该会给你预装 Windows 11 系统。唯一需要注意的就是从开箱到开机的全程录屏，需要确保是首次激活，以免遇到 &lt;code&gt;“二手电脑”&lt;/code&gt;。如何判断是不是首次激活，可以善用搜索引擎或者到各大视频平台搜索相关视频。&lt;/p&gt;
&lt;p&gt;如果是 &lt;code&gt;入职新公司&lt;/code&gt;，那情况就各种各样了，有可能老板给你配了个新电脑，也有可能给你上个离职员工用过的设备，如果是新购置的笔记本电脑，同上。如果是上个员工用过的电脑，你可能需要重装，这种情况最简单的办法就是去微软官网下载一个 &lt;code&gt;ISO&lt;/code&gt; 系统镜像来安装，或者直接在 Windows 设置里重置电脑，简单快捷，无需多言。&lt;/p&gt;
&lt;p&gt;那么，当你遇到 &lt;code&gt;电脑故障&lt;/code&gt; 或者 &lt;code&gt;新买的台式机&lt;/code&gt;，那你可能需要先做一个 PE 系统盘来辅助安装，我一般使用 &lt;a href=&quot;https://www.wepe.com.cn/&quot;&gt;WEPE&lt;/a&gt; 来制作 PE 系统盘，这需要先准备一个 U 盘，然后找个能用的电脑来制作，PE 系统盘是让你在没有安装系统时，通过 U 盘来启动一个非常小的系统，方便来安装新的 Windows 系统，也就是说，这个 U 盘制作完成后，同样也需要一份 &lt;code&gt;ISO&lt;/code&gt; 系统镜像放入 U 盘里才能安装。&lt;/p&gt;
&lt;p&gt;:::tip
如果你像我一样很久以前就有一个 PE 系统盘，那么你可能需要重新制作一个新的 PE 系统，因为以前的 PE 系统不一定能打开 Windows 11 安装镜像。
:::&lt;/p&gt;
&lt;h2&gt;安装引导&lt;/h2&gt;
&lt;p&gt;到成功安装系统，或是在启动新购入的笔记本电脑时，会进入到 Windows 11 的安装引导中，如果在联网情况下，引导应该会让你登录微软账号来作为 Windows 用户，但可能对一部分人来说，微软账号的昵称是中文的（可能用的真实姓名，比如我），这会导致用户文件夹也是中文，对某些软件来说，中文文件夹会导致无法读取（大概是软件使用的编码格式导致的）。所以，要么断网使用本地用户，要么就进入系统之后重新创建一个用户。&lt;/p&gt;
&lt;h2&gt;修改用户名&lt;/h2&gt;
&lt;p&gt;如果你没法在安装引导使用本地用户登录，那么我这里有一个方便快捷的修改用户名方法，不需要修改注册表。&lt;/p&gt;
&lt;p&gt;首先在 &lt;code&gt;设置&lt;/code&gt; -&amp;gt; &lt;code&gt;账户&lt;/code&gt; -&amp;gt; &lt;code&gt;添加账户&lt;/code&gt; 中新增一个账户，在弹窗中选择 &lt;code&gt;我没有这个人的登录信息&lt;/code&gt;，后面再选择 &lt;code&gt;添加一个没有 Microsoft 帐户的用户&lt;/code&gt;，这样就能创建一个本地用户了。添加完成后，记得给本地用户设置为管理员。&lt;/p&gt;
&lt;p&gt;然后在 &lt;code&gt;账户&lt;/code&gt; -&amp;gt; &lt;code&gt;你的信息&lt;/code&gt; 中找到 &lt;code&gt;Microsoft 账号&lt;/code&gt;，点击 &lt;code&gt;改用本地账户登录&lt;/code&gt;，这样就成功将当前账户的微软账号退出了。&lt;/p&gt;
&lt;p&gt;接着注销，切换到刚才新建的用户，此时这个新建的用户的用户文件夹就不是中文了，只需要在账户中找到那个中文的用户删除掉就行，如果不在上一步退出微软账号，这一步就没法删除中文用户了。&lt;/p&gt;
&lt;h2&gt;无密码登录&lt;/h2&gt;
&lt;p&gt;可能有部分家用台式的人有这个需求，就是不想要设置密码，除了在上个步骤中新增本地用户时不设置账号外，还需要一个操作，使用 &amp;lt;kbd&amp;gt;Win&amp;lt;/kbd&amp;gt; + &amp;lt;kbd&amp;gt;R&amp;lt;/kbd&amp;gt; 快捷键打开运行窗口，输入以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;netplwiz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确定后打开窗口，在窗口中将 &lt;code&gt;要使用本计算机，用户必须输入用户名和密码&lt;/code&gt; 取消勾选，这样才能在每次开机时不再输入密码。取消勾选时会让你确认密码，其实就是每次自动给你登录了。取消勾选后记得 &lt;code&gt;应用&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;本地 Git 仓库&lt;/h2&gt;
&lt;p&gt;如果你是 &lt;code&gt;重装电脑&lt;/code&gt;，本地有一些 Git 仓库，那么可能会无法使用这些仓库，需要在 &lt;code&gt;git bash&lt;/code&gt; 中输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global --add safe.directory &quot;*&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用这个配置来解决无法使用本地 Git 仓库的问题。&lt;/p&gt;
&lt;h2&gt;驱动相关&lt;/h2&gt;
&lt;p&gt;下载 AMD 驱动时，千万别下载 &lt;code&gt;StoreMI&lt;/code&gt; 这个驱动，这个确定已经停止维护，他会导致硬盘盘符相互替换，然后开机无限蓝屏。&lt;/p&gt;
&lt;p&gt;如果手贱不小心下载了这个驱动，那么就用 PE 系统中的 &lt;code&gt;DISM++&lt;/code&gt; 里找到驱动管理，然后找到 &lt;code&gt;存储控制器&lt;/code&gt;，把 &lt;code&gt;Advanced Micro Devices, Inc&lt;/code&gt; 整个勾选上然后删除，盘符使用分区工具重新指派即可。&lt;/p&gt;
&lt;h2&gt;BIOS 相关&lt;/h2&gt;
&lt;p&gt;承接上文，我就是那个手贱下载 &lt;code&gt;StoreMI&lt;/code&gt; 的，以为 CPU 炸了导致的蓝屏 &lt;code&gt;BAD_POOL_CALLER&lt;/code&gt;，外加我电脑平时也经常蓝屏，以为是 CPU 电压的问题，结果在 BIOS 中改了 CPU 电压和内存条电压，这个电脑直接没法点亮了。&lt;/p&gt;
&lt;p&gt;如果是这种情况，一般主板都有重置的方法，以我的微星 B450m Mortal Max 迫击炮为例，在主板左下角的音频针脚上方有两个 &lt;code&gt;JBAT1&lt;/code&gt; 针脚（具体查看主板说明书），将其短接 5 - 10 秒即可重置 BIOS 设置，不同主板的方法肯定不同，不过应该都能在说明书上找到。&lt;/p&gt;
</content:encoded></item><item><title>站点记录</title><link>https://blog.cosmolau.top/posts/site-records/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/site-records/</guid><description>本站点的重要时间点记录</description><pubDate>Fri, 01 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;timeline
    title 站点重要时间线
    2022.10.18 : 部署 Hexo 博客站点
    2024.4.1 : 使用 vivia 主题
    2024.10.31 : 使用 Fuwari 主题
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2024.10.31&lt;/h1&gt;
&lt;p&gt;我刚用上 vivia 作为主题不久，作者就停止了维护，转而投入到 Fuwari 的开发。由于 Fuwari 是基于 Astro 的，我又不太想换一个不熟悉的框架，而且 Fuwari 还有些问题不符合我的预期，所以迟迟没迁移。&lt;/p&gt;
&lt;p&gt;直到这天，Fuwari 已经基本符合我的预期，我也对站点进行了一次小小的规划，将其部署到了 &lt;code&gt;blog.cosmolau.top&lt;/code&gt; 这个域名上。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;saicaca/fuwari&quot;}&lt;/p&gt;
&lt;h1&gt;2024.5.20&lt;/h1&gt;
&lt;p&gt;这天我翻译的 &lt;a href=&quot;https://typicode.github.io/husky/zh/&quot;&gt;Husky 文档&lt;/a&gt; 终于被&lt;a href=&quot;https://github.com/typicode/husky/pull/1413&quot;&gt;合并&lt;/a&gt;了，起因是我想把我的 husky 分叉仓库部署到自己的域名上，结果在添加了 &lt;code&gt;CNAME&lt;/code&gt; 文件后，发现 PR 也被同步修改了，此时我才发现，原来提交 PR 的流程我还是没搞懂。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;CosmoLau/husky&quot;}&lt;/p&gt;
&lt;p&gt;我将构建后的文档部署到了 &lt;a href=&quot;https://www.cosmolau.top/husky/zh/&quot;&gt;www.cosmolau.top/husky/zh/&lt;/a&gt;，不过现在我还是建议你去看官方文档。（顺便说一下，官方文档的多语言支持也是我做的）&lt;/p&gt;
&lt;h1&gt;2024.4.16&lt;/h1&gt;
&lt;p&gt;将 oclif 文档翻译成了中文，并添加了多语言的支持，不过提交的 PR 并没有被采纳。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;CosmoLau/oclif.github.io&quot;}&lt;/p&gt;
&lt;p&gt;既然官方没法合并 PR，那我就只能自己部署在 &lt;a href=&quot;https://www.cosmolau.top/docs/oclif/zh/&quot;&gt;www.cosmolau.top/docs/oclif/zh/&lt;/a&gt; 了。&lt;/p&gt;
&lt;h1&gt;2024.4.1&lt;/h1&gt;
&lt;p&gt;博客长期没有维护，我觉得可能是我选的主题不符合我的审美，所以到 &lt;a href=&quot;https://hexo.io/themes/&quot;&gt;Hexo 官方收录的主题页&lt;/a&gt; 寻找自己对的上眼的主题，最终选择了 &lt;a href=&quot;https://github.com/saicaca/hexo-theme-vivia&quot;&gt;vivia&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;saicaca/hexo-theme-vivia&quot;}&lt;/p&gt;
&lt;p&gt;作为新博客的第一天，我把我发布在 Cocos 论坛的文章做为了本博客的第一篇文章，&lt;a href=&quot;../cocos-extension/&quot;&gt;《【从零开始的插件开发】使用 CC3.x + UI组件 + Vue3 开发一个插件》&lt;/a&gt;发布了。&lt;/p&gt;
&lt;h1&gt;2022.10.18&lt;/h1&gt;
&lt;p&gt;因为看见别人的 Demo 域名为 &lt;code&gt;github.io&lt;/code&gt; 后缀，所以知道了 &lt;strong&gt;GitHub Pages&lt;/strong&gt; 的存在，然后在一众静态博客框架中选择了 &lt;code&gt;Hexo&lt;/code&gt;，其原因是 &lt;code&gt;Hexo&lt;/code&gt; 是 JavaScript 写的。&lt;/p&gt;
&lt;p&gt;我正好有个域名，索性就把 GitHub Pages 修改成了自定义域名 &lt;code&gt;www.cosmolau.top&lt;/code&gt;。&lt;/p&gt;
</content:encoded></item><item><title>使用 Docker 快速搭建《我的世界》（Minecraft）服务器</title><link>https://blog.cosmolau.top/posts/docker-minecraft-server/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/docker-minecraft-server/</guid><description>搭建《我的世界》服务器是一个折磨的过程，但用上 Docker，就能省去很多麻烦</description><pubDate>Wed, 15 May 2024 13:29:50 GMT</pubDate><content:encoded>&lt;p&gt;本篇是一个使用 Docker 进行游戏服务器快速搭建的教程，需要先自行安装 &lt;a href=&quot;https://docs.docker.com/engine/install/&quot;&gt;Docker&lt;/a&gt;，以做好前置准备。&lt;/p&gt;
&lt;p&gt;本教程基于 &lt;a href=&quot;https://github.com/itzg/docker-minecraft-server&quot;&gt;docker-minecraft-server&lt;/a&gt; 项目进行部署，详情请参阅 &lt;a href=&quot;https://docker-minecraft-server.readthedocs.io/en/latest/&quot;&gt;docker-minecraft-server 文档&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;快速部署&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -it --name mc -p 25565:25565 -e EULA=TRUE -v /home/minecraft/data:/data itzg/minecraft-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--name mc&lt;/code&gt;：设置容器名，此处设置为 &lt;code&gt;mc&lt;/code&gt;，方便下文使用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-v /home/minecraft/data:/data&lt;/code&gt;：将容器数据卷挂载到 &lt;code&gt;/home/minecraft/data&lt;/code&gt; 路径下，可自行修改，此处方便下文使用。&lt;/p&gt;
&lt;p&gt;执行以上命令后，等待 docker 部署完成，最基础的 Minecraft 服务器就已经搭建成功了，此时已经可以尝试通过 Minecraft 的 &lt;code&gt;多人游戏&lt;/code&gt; 连接到服务器公网 IP 了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;注意&lt;/em&gt;：如果使用家庭网络搭建服务器，一般是没有 IPv4 的公网 IP 的，可以尝试使用 IPv6 来连接。
部分云服务商还需要手动开启对应的端口访问，比如我使用的阿里云服务器，需要到&lt;code&gt;安全组&lt;/code&gt;中放行上面命令行用到的 &lt;code&gt;25565&lt;/code&gt; 端口即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;修改服务器参数&lt;/h2&gt;
&lt;p&gt;服务器搭建完成后，如果需要修改参数，就要找到 Minecraft 服务器对应的 Docker 数据卷（volume）挂载的路径。如果使用了上文的快速部署命令，路径应该为 &lt;code&gt;/home/minecraft/data&lt;/code&gt;，切换到改路径下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /home/minecraft/data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到路径下的 &lt;code&gt;server.properties&lt;/code&gt; 文件，内容大致如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#Minecraft server properties
#Wed May 15 05:00:42 UTC 2024
accepts-transfers=false
allow-flight=false
allow-nether=true
broadcast-console-to-ops=true
broadcast-rcon-to-ops=true
difficulty=easy
enable-command-block=false
enable-jmx-monitoring=false
enable-query=false
enable-rcon=false
enable-status=true
enforce-secure-profile=true
enforce-whitelist=false
entity-broadcast-range-percentage=100
force-gamemode=false
function-permission-level=2
gamemode=survival
generate-structures=true
generator-settings={}
hardcore=false
hide-online-players=false
initial-disabled-packs=
initial-enabled-packs=vanilla
level-name=world
level-seed=
level-type=minecraft\:normal
log-ips=true
max-chained-neighbor-updates=1000000
max-players=20
max-tick-time=60000
max-world-size=29999984
motd=A Minecraft Server
network-compression-threshold=256
online-mode=true
op-permission-level=4
player-idle-timeout=0
prevent-proxy-connections=false
pvp=true
query.port=25565
rate-limit=0
rcon.password=
rcon.port=25575
region-file-compression=deflate
require-resource-pack=false
resource-pack=
resource-pack-id=
resource-pack-prompt=
resource-pack-sha1=
server-ip=
server-port=25565
simulation-distance=10
spawn-animals=true
spawn-monsters=true
spawn-npcs=true
spawn-protection=16
sync-chunk-writes=true
text-filtering-config=
use-native-transport=true
view-distance=10
white-list=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参数对应的功能可以在 &lt;a href=&quot;https://zh.minecraft.wiki/w/Server.properties&quot;&gt;Minecraft WIKI&lt;/a&gt; 中查看，按需修改对应的参数即可。&lt;/p&gt;
&lt;p&gt;修改完成后，需要重启一下 Docker 容器，参考下文 &lt;code&gt;Docker 常用命令&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;常用参数&lt;/h2&gt;
&lt;p&gt;如果不想一个一个查看参数对应的内容，我这里会给出一些常用的参数配置说明，以便快速修改。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 游戏难度
# peaceful - 和平
# easy - 简单
# normal - 普通
# hard - 困难
difficulty=easy

# 游戏模式
# survival - 生存模式
# creative - 创造模式
# adventure - 冒险模式
# spectator - 旁观模式
gamemode=survival

# 最大玩家数
max-players=20

# 队友伤害
# true - 玩家可以互相伤害。
# false - 玩家无法互相造成伤害（也称作玩家对战环境（PvE））。
pvp=true

# 启用白名单
# false - 不使用白名单。
# true - 从 whitelist.json 文件加载白名单，需要在 whitelist.json 中添加玩家的用户名，对应的玩家才能加入服务器。
white-list=false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Docker 常用命令&lt;/h2&gt;
&lt;p&gt;查看所有 docker 容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps -a
# 输出内容如下
CONTAINER ID   IMAGE                        COMMAND                   CREATED        STATUS                       PORTS                                           NAMES
19bb186f2584   itzg/minecraft-server        &quot;/start&quot;                  16 hours ago   Up About an hour (healthy)   0.0.0.0:25565-&amp;gt;25565/tcp, :::25565-&amp;gt;25565/tcp   mc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启 Docker 容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 使用容器名来重启，例如容器名为 mc
docker restart mc
# 如果容器名太长，也可以使用容器 ID（CONTAINER ID），输入 ID 前几位即可
docker restart 19bb1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;暂停 Docker 容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stop mc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动 Docker 容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker start mc
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;踩坑分享&lt;/h2&gt;
&lt;p&gt;设置了一次白名单之后，如果重启一次容器，可能导致白名单的用户无法进入服务器，具体原因未知，所以我直接关闭了白名单，这种情况请注意保护好自己的&lt;strong&gt;公网 IP 不要泄露&lt;/strong&gt;，否则可能有其他人捣乱。&lt;/p&gt;
&lt;p&gt;如果遇到 &lt;code&gt;暂时无法连接到登录验证服务器，请稍后再试&lt;/code&gt;，检查一下是否修改过本机的 &lt;code&gt;hosts&lt;/code&gt;，如果有修改，清理一遍重进就行。&lt;/p&gt;
&lt;p&gt;服务器建议 4G 内存起步，2G 很容易炸掉，不推荐用来部署 Minecraft 服务器。&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/&quot;&gt;Docker&lt;/a&gt;
&lt;a href=&quot;https://github.com/itzg/docker-minecraft-server&quot;&gt;docker-minecraft-server&lt;/a&gt;
&lt;a href=&quot;https://docker-minecraft-server.readthedocs.io/en/latest/&quot;&gt;docker-minecraft-server 文档&lt;/a&gt;
&lt;a href=&quot;https://zh.minecraft.wiki/w/Server.properties&quot;&gt;Minecraft WIKI&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>使用 VitePress 移植 Cocos 文档</title><link>https://blog.cosmolau.top/posts/cocos-docs-vitepress/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/cocos-docs-vitepress/</guid><description>将基于 GitBook 搭建的 Cocos 文档使用 VitePress 重新搭建</description><pubDate>Thu, 04 Apr 2024 15:04:23 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;原文链接：https://forum.cocos.org/t/topic/150946 &amp;lt;br&amp;gt;
&lt;em&gt;&lt;strong&gt;注&lt;/strong&gt;&lt;/em&gt;：官方文档已移植为 VitePress 版本，参阅&lt;a href=&quot;https://docs.cocos.com/creator/3.8/manual/zh/&quot;&gt;Cocos Creator 用户手册&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;众所周知，Cocos 文档是使用 GitBook 发布的，如今已经有了更多成熟的静态网站生成器来构建个性化的开发文档，那么 Cocos 文档是不是也能换件新衣服呢？&lt;/p&gt;
&lt;p&gt;正巧最近在学 Vue3 的时候，发现 Vue3 是由 &lt;a href=&quot;https://github.com/vuejs/vitepress&quot;&gt;VitePress&lt;/a&gt; 构建的，作为出名的前端技术团队维护的静态站点生成器，想必有其特别之处，跑去看了下 &lt;a href=&quot;https://vitepress.dev&quot;&gt;VitePress 开发文档&lt;/a&gt;，没想到上手如此的简单快捷，就萌生了移植 Cocos 文档的想法。&lt;/p&gt;
&lt;p&gt;先上效果图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E4%B8%BB%E9%A1%B5.png&quot; alt=&quot;主页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%89%8B%E5%86%8C.png&quot; alt=&quot;手册&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E5%A4%9C%E9%97%B4%E6%A8%A1%E5%BC%8F.png&quot; alt=&quot;夜间模式&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E7%89%88%E6%9C%AC.png&quot; alt=&quot;版本&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果觉得效果还不错，可以到 https://www.cosmolau.top/docs/cocos/ 在线体验一下，由于移植的工作量主要在于侧边栏的移植，目前 500 多篇文章只有 100 多篇显示在了侧边栏，这还只是中文文档（英文文档也是 500 篇），所以在线版的并不完整。感兴趣的话可以到 &lt;a href=&quot;https://github.com/CosmoLau/cocos-docs-vitepress&quot;&gt;GitHub 仓库&lt;/a&gt; 来参与移植，或者 fork 下来自己把玩也行。&lt;/p&gt;
&lt;h2&gt;自动化移植&lt;/h2&gt;
&lt;p&gt;手动移植是最笨的方法，而且非常消磨精力，所以就得考虑下自动化移植。&lt;/p&gt;
&lt;p&gt;移植主要的内容是侧边栏，GitBook 的侧边栏目录写在一个 Markdown 文件中，想要自动化移植，可以使用 &lt;code&gt;mdast-util-from-markdown&lt;/code&gt; Nodejs 库来读取 &lt;code&gt;Markdown&lt;/code&gt; 的抽象语法树，然后再生成一份对应的 JSON 格式目录配置，粘贴到 VitePress 项目的 &lt;code&gt;config.ts&lt;/code&gt; 中就行了。&lt;/p&gt;
&lt;p&gt;限于我本人能力太菜，精力有限，这个课题就交给感兴趣的同学去研究吧。&lt;/p&gt;
&lt;h2&gt;VitePress 移植踩坑&lt;/h2&gt;
&lt;p&gt;如果你想了解更多，下面我会分享我在移植过程中遇到的各种坑。&lt;/p&gt;
&lt;h2&gt;img 标签路径错误&lt;/h2&gt;
&lt;p&gt;在 Cocos 官方文档中，相当部分的图片使用了 &lt;code&gt;img&lt;/code&gt; 标签来引入，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 使用 JSB 手动绑定

...

&amp;lt;a href=&quot;jsb/infrastructure.png&quot;&amp;gt;&amp;lt;img src=&quot;jsb/infrastructure.png&quot; alt=&quot; &quot;&amp;gt;&amp;lt;/a&amp;gt;

&amp;lt;div style=&quot;text-align:center&quot;&amp;gt;&amp;lt;p&amp;gt;新版 ABCmouse 的应用架构：基于 callStaticMethod 与 evalString 进行通信&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个 &lt;code&gt;Markdown&lt;/code&gt; 文件在开发时不会报错，但是在构建时就会报如下的错误：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;build error:

Error: [vite]: Rollup failed to resolve import &quot;jsb/infrastructure.png&quot; from &quot;E:/myWorkSpace/docs/docs/zh/manual/advanced-topics/jsb-manual-binding.md&quot;.

This is most likely unintended because it can break your application at runtime.

If you do want to externalize this module explicitly add it to

build.rollupOptions.external
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个报错困扰了我很久，在 VitePress 的 GitHub 仓库的 issue 中也没能找到解决方案。最终发现是因为引用的路径有误，正确的路径应该加上 “./”，做法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a href=&quot;./jsb/infrastructure.png&quot;&amp;gt;&amp;lt;img src=&quot;./jsb/infrastructure.png&quot; alt=&quot; &quot;&amp;gt;&amp;lt;/a&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;巧用 VSCode 的搜索功能来批量替换。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;丢失终止标签&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Element is missing end tag
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有些标签是需要成对的，会有一个形如 &lt;code&gt;&amp;lt;/&amp;gt;&lt;/code&gt; 的终止标签，如果遇到这个报错，就得看看是不是哪个标签少了个 &lt;code&gt;/&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;错误的扩展名&lt;/h2&gt;
&lt;p&gt;cocos-docs 中部分图片使用的大写字母 &lt;code&gt;.PNG&lt;/code&gt; 结尾，这也会使 VitePress 在构建时报错，修改成小写 &lt;code&gt;.png&lt;/code&gt; 即可，图片的扩展名也需要改成小写 &lt;code&gt;.png&lt;/code&gt;。（这个问题不是 BUG，具体参考这个 &lt;a href=&quot;https://github.com/vuejs/vitepress/issues/3748&quot;&gt;issue&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;还有几个报错，相对这几个都是小问题，可以去 &lt;code&gt;VitePress&lt;/code&gt; 上搜相关的 &lt;code&gt;issue&lt;/code&gt;，不过还是吐槽一句，终归还是部分 &lt;code&gt;Markdown&lt;/code&gt; 文档不够规范。&lt;/p&gt;
&lt;h2&gt;结尾&lt;/h2&gt;
&lt;p&gt;最近看到 Dashboard 马上要翻新了，手册文档是不是也该翻新一下，新瓶装旧酒。文档虽然还有进步空间，但看着舒服也算能赢一半吧（狗头）。&lt;/p&gt;
&lt;h3&gt;相关链接&lt;/h3&gt;
&lt;p&gt;VitePress 开发文档：https://vitepress.dev/&lt;/p&gt;
&lt;p&gt;VitePress 仓库：https://github.com/vuejs/vitepress&lt;/p&gt;
&lt;p&gt;Cocos 文档官方仓库：https://github.com/cocos/cocos-docs&lt;/p&gt;
&lt;p&gt;VitePress 版 Cocos 文档体验地址：https://www.cosmolau.top/docs/cocos/&lt;/p&gt;
&lt;p&gt;VitePress 版 Cocos 文档仓库：https://github.com/CosmoLau/cocos-docs-vitepress&lt;/p&gt;
</content:encoded></item><item><title>【从零开始的插件开发】使用 CC3.x + UI组件 + Vue3 开发一个插件</title><link>https://blog.cosmolau.top/posts/cocos-extension/</link><guid isPermaLink="true">https://blog.cosmolau.top/posts/cocos-extension/</guid><description>Cocos Creator 插件能提高开发效率，本文将带你了解如何从零开发一个插件</description><pubDate>Mon, 01 Apr 2024 18:40:44 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;视频教程
&amp;lt;iframe src=&quot;//player.bilibili.com/player.html?aid=357514260&amp;amp;bvid=BV1VX4y1t7tH&amp;amp;cid=1170026892&amp;amp;p=1&quot; scrolling=&quot;no&quot; border=&quot;0&quot; frameborder=&quot;no&quot; framespacing=&quot;0&quot; allowfullscreen=&quot;true&quot; width=&quot;100%&quot; height=&quot;400px&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;近期发布了一个 Cocos Creator 2.4.x 的自动化插件，想移植到 3.x 版本，但 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/readme.html&quot;&gt;扩展编辑器 官方文档&lt;/a&gt; 的教程让我这种小白一言难尽，尽管我刚开发完一款 2.x 的插件，3.x 也让我折腾了很久。&lt;/p&gt;
&lt;p&gt;首先得吐槽一下插件开发的官方文档，感觉不如 2.x 的文档，特别是 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/ui.html&quot;&gt;UI 组件&lt;/a&gt; 文档，感觉像是随便写的，虽然可以直接在 &lt;strong&gt;UI 组件面板&lt;/strong&gt; 中看到代码，但示例代码也有很多坑。而 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/extension-change-name.html&quot;&gt;扩展改名&lt;/a&gt; 这篇文档更是重量级，真的会有人需要用到这篇文档吗？不过还是叠个甲，希望只是官方没有太多精力去维护插件开发的文档。&lt;/p&gt;
&lt;p&gt;那么废话就到此为止，本篇文章算是个技术总结，毕竟我也算是从零开始开发的插件，踩了许多坑，虽然没啥技术力，但入门应该是够了。下面将一步一步教大家通过 CC3.x + UI组件 + Vue3 的形式开发一个简单的可视化插件。&lt;/p&gt;
&lt;h2&gt;为何选择 Vue3 模板开发？&lt;/h2&gt;
&lt;p&gt;Cocos Creator 3.x 支持创建 &lt;code&gt;HTML 面板&lt;/code&gt;、&lt;code&gt;Vue2.x 面板&lt;/code&gt;、&lt;code&gt;Vue3.x 面板&lt;/code&gt;，对于有对应技术栈的开发者来说，选择对口的模板是最好的选择。但如果是一位平时只使用 Cocos Creator，不太接触其他框架的小白来说（比如我），不妨选择最新的技术栈，这样能通过学习插件开发的同时，了解下 Vue3 的基础概念（&lt;s&gt;如果以后不做 Cocos 了，方便快速转行&lt;/s&gt;）。&lt;/p&gt;
&lt;p&gt;当然，我也是一个 Vue3 入门的新手，对 Vue3 理解不够透彻，文章中会大量引用 &lt;a href=&quot;https://cn.vuejs.org/&quot;&gt;Vue3 官方文档&lt;/a&gt; 的内容来进行解释，同时也引用了大量的 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/readme.html&quot;&gt;扩展编辑器 官方文档&lt;/a&gt; 来解释，本篇文章只能算是官方文档的补充说明。（&lt;s&gt;并不是真的教官方写文档&lt;/s&gt;）&lt;/p&gt;
&lt;h2&gt;创建扩展&lt;/h2&gt;
&lt;p&gt;首先我们通过 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/create-extension.html&quot;&gt;扩展模板与编译构建&lt;/a&gt; 文档中的方法来创建一个 &lt;strong&gt;Vue3.x 面板&lt;/strong&gt; 扩展，我们将 &lt;code&gt;扩展名&lt;/code&gt; 改为 &lt;code&gt;extension-vue&lt;/code&gt;，方便后面讲解。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;extension_name.png&quot; alt=&quot;创建扩展面板&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建完成后，在项目工程的 &lt;code&gt;extensions&lt;/code&gt; 文件夹中会生成这么一个目录结构：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84.png&quot; alt=&quot;扩展目录结构&quot; /&gt;&lt;/p&gt;
&lt;p&gt;目录结构的详细解释，在 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/first.html#%E6%89%A9%E5%B1%95%E7%9B%AE%E5%BD%95&quot;&gt;目录结构&lt;/a&gt; 中有记载，包括 &lt;code&gt;package.json&lt;/code&gt; 的字段含义，也在同一篇文档中。&lt;/p&gt;
&lt;p&gt;此时已经创建好了一个扩展模板，需要按照 &lt;code&gt;README.zh-CN.md&lt;/code&gt; 中的方法来安装 &lt;strong&gt;npm 依赖&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;注意&lt;/em&gt;：使用 npm 需要安装 &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Nodejs&lt;/a&gt; 环境，如果你还没有安装，推荐 Windows 开发者安装 &lt;a href=&quot;https://github.com/coreybutler/nvm-windows&quot;&gt;NVM for Windows&lt;/a&gt; 方便进行 Nodejs 的版本管理。（&lt;s&gt;总有一天会需要用到切换版本的功能&lt;/s&gt;）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;安装 &lt;strong&gt;npm 依赖&lt;/strong&gt; 需要打开终端来执行命令，如果你对终端的用法不了解，可以在 VSCode 中使用快捷键 &amp;lt;kbd&amp;gt;Ctrl&amp;lt;/kbd&amp;gt; + &amp;lt;kbd&amp;gt;Shift&amp;lt;/kbd&amp;gt; + &amp;lt;kbd&amp;gt;`&amp;lt;/kbd&amp;gt; 来打开，然后以此执行以下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 切换到扩展目录下
cd .\extensions\extension-vue\
# 安装 npm 依赖
npm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们回到 Cocos Creator 编辑器，在 &lt;code&gt;扩展&lt;/code&gt; -&amp;gt; &lt;code&gt;扩展管理器&lt;/code&gt; -&amp;gt; &lt;code&gt;已安装扩展&lt;/code&gt; 中启用创建好的扩展。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;提示&lt;/em&gt;：在开发插件的过程中如果遇到数据没刷新之类的问题，可以使用此方法来重新关闭开启插件，以重新加载插件。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;%E5%90%AF%E7%94%A8%E6%8F%92%E4%BB%B6.png&quot; alt=&quot;启用插件&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接着就能通过 &lt;code&gt;面板&lt;/code&gt; -&amp;gt; &lt;code&gt;extension-vue&lt;/code&gt; -&amp;gt; &lt;code&gt;默认面板&lt;/code&gt; 打开扩展模板面板，此时已经完成了扩展的创建。&lt;/p&gt;
&lt;h2&gt;使用 UI 组件布局&lt;/h2&gt;
&lt;p&gt;面板布局主要在 &lt;code&gt;extension-vue/static/template/default/index.html&lt;/code&gt; 中进行修改，下面统一用 &lt;strong&gt;index.html&lt;/strong&gt; 来代指。&lt;/p&gt;
&lt;p&gt;如果需要添加 CSS 样式，可以在 &lt;code&gt;extension-vue/static/style/default/index.css&lt;/code&gt; 中进行添加，下面统一用 &lt;strong&gt;index.css&lt;/strong&gt; 来代指。&lt;/p&gt;
&lt;p&gt;我们根据 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/ui.html&quot;&gt;UI 组件&lt;/a&gt; 文档的步骤，通过 &lt;code&gt;开发者&lt;/code&gt; -&amp;gt; &lt;code&gt;UI 组件&lt;/code&gt; 来打开 &lt;strong&gt;UI 组件面板&lt;/strong&gt;，这个面板里的参考代码很重要（也有很多坑），我们整个开发过程中都会用到，可以一直开着这个面板。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;UI%E7%BB%84%E4%BB%B6%E9%9D%A2%E6%9D%BF.png&quot; alt=&quot;UI组件面板&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我们回到 &lt;strong&gt;index.html&lt;/strong&gt; 中，我们先将 &lt;code&gt;&amp;lt;my-counter&amp;gt;&amp;lt;/my-counter&amp;gt;&lt;/code&gt; 和 &lt;code&gt;&amp;lt;h1 id=&quot;text&quot;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/code&gt; 注释掉，接下来要添加的所有 UI 组件标签都需要写在 &lt;code&gt;&amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; 标签内。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%B3%A8%E9%87%8A%E6%8E%89%E6%A0%87%E7%AD%BE.png&quot; alt=&quot;注释掉标签&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来我们尝试用 UI 组件拼出一个界面来。&lt;/p&gt;
&lt;h3&gt;使用 ui-prop 组件&lt;/h3&gt;
&lt;p&gt;ui-prop 组件能让可视化界面有一个整洁的排版，是很适合用来设置布局的组件。&lt;/p&gt;
&lt;p&gt;我们先来看一下 UI 组件面板中的 &lt;code&gt;layout&lt;/code&gt; -&amp;gt; &lt;code&gt;ui-prop&lt;/code&gt; 组件示例：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;ui-prop%E7%A4%BA%E4%BE%8B.png&quot; alt=&quot;ui-prop示例&quot; /&gt;&lt;/p&gt;
&lt;p&gt;先将第一个示例添加到 &lt;strong&gt;index.html&lt;/strong&gt; 的 app 标签中，并且添加一个 &lt;code&gt;&amp;lt;h1&amp;gt;&amp;lt;/h1&amp;gt;&lt;/code&gt; 标签来作为面板的标题。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    &amp;lt;div id=&quot;app&quot;&amp;gt;
        &amp;lt;!-- 所有 UI 组件写在 &amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt; 标签内 --&amp;gt;

        &amp;lt;h1&amp;gt;Extension Vue&amp;lt;/h1&amp;gt;

        &amp;lt;ui-prop&amp;gt;
            &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Checkbox&amp;lt;/ui-label&amp;gt;
            &amp;lt;ui-checkbox slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
        &amp;lt;/ui-prop&amp;gt;
        
        &amp;lt;ui-prop&amp;gt;
            &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Name&amp;lt;/ui-label&amp;gt;
            &amp;lt;ui-input slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-input&amp;gt;
        &amp;lt;/ui-prop&amp;gt;
        
        &amp;lt;ui-prop&amp;gt;
            &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Color&amp;lt;/ui-label&amp;gt;
            &amp;lt;ui-color slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-color&amp;gt;
        &amp;lt;/ui-prop&amp;gt;
        
        &amp;lt;ui-prop&amp;gt;
            &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Select&amp;lt;/ui-label&amp;gt;
            &amp;lt;ui-select slot=&quot;content&quot;&amp;gt;
                &amp;lt;option value=&quot;1&quot;&amp;gt;Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit, sint.&amp;lt;/option&amp;gt;
                &amp;lt;option value=&quot;2&quot;&amp;gt;Sapiente ratione esse voluptatibus repudiandae illo numquam quas nulla id.&amp;lt;/option&amp;gt;
            &amp;lt;/ui-select&amp;gt;
        &amp;lt;/ui-prop&amp;gt;

    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们通过 &lt;code&gt;面板&lt;/code&gt; -&amp;gt; &lt;code&gt;extension-vue&lt;/code&gt; -&amp;gt; &lt;code&gt;默认面板&lt;/code&gt; 来查看面板效果：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;ui-prop%E6%95%88%E6%9E%9C.png&quot; alt=&quot;ui-prop效果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这样看起来不太美观，标题可以居中显示，而且 &lt;code&gt;ui-prop&lt;/code&gt; 之间得加点间距。&lt;/p&gt;
&lt;p&gt;3.x 版本的 UI 组件没有 2.x 的 &lt;code&gt;ui-box-container&lt;/code&gt; 组件来框柱 &lt;code&gt;ui-prop&lt;/code&gt;，看起来也不太好看，来看看 2.x 的效果：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;ui-box-container.png&quot; alt=&quot;2.x ui-box-container&quot; /&gt;&lt;/p&gt;
&lt;p&gt;既然 3.x 没有，那我们就用 CSS 来实现一个，在 &lt;strong&gt;index.css&lt;/strong&gt; 中添加以下样式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* index.css */
h1 {
    /* 文本居中 */
    text-align: center;
}
.box {
    /* 外边距 10px */
    margin: 10px;
    /* 内边距 5px */
    padding: 5px;
    /* 虚线边框 */
    border-style: dashed;
    /* 边框宽度 1px */
    border-width: 1px;
    /* 边框颜色为灰色 */
    border-color: gray;
}
ui-prop {
    /* 添加上边距 5px */
    margin-top: 5px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们将所有 &lt;code&gt;ui-prop&lt;/code&gt; 组件添加到一对 &lt;code&gt;&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; 标签中，并为 div 添加 css 中定义的 box 样式。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;div id=&quot;app&quot;&amp;gt;

        &amp;lt;!-- 所有 UI 组件写在 &amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt; 标签内 --&amp;gt;

        &amp;lt;h1&amp;gt;Extension Vue&amp;lt;/h1&amp;gt;

        &amp;lt;div class=&quot;box&quot;&amp;gt;
            &amp;lt;ui-prop&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Checkbox&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-checkbox slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
            &amp;lt;/ui-prop&amp;gt;
            
            &amp;lt;ui-prop&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Name&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-input slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-input&amp;gt;
            &amp;lt;/ui-prop&amp;gt;
            
            &amp;lt;ui-prop&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Color&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-color slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-color&amp;gt;
            &amp;lt;/ui-prop&amp;gt;
            
            &amp;lt;ui-prop&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Select&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-select slot=&quot;content&quot;&amp;gt;
                    &amp;lt;option value=&quot;1&quot;&amp;gt;Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sit, sint.&amp;lt;/option&amp;gt;
                    &amp;lt;option value=&quot;2&quot;&amp;gt;Sapiente ratione esse voluptatibus repudiandae illo numquam quas nulla id.&amp;lt;/option&amp;gt;
                &amp;lt;/ui-select&amp;gt;
            &amp;lt;/ui-prop&amp;gt;
        &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，我们的面板就变得整洁了起来：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;add_box_style.png&quot; alt=&quot;add_box_style&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;注意&lt;/em&gt;：编写好 html 后，需要关闭面板重新打开才能看到修改后的内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用 &lt;code&gt;ui-prop&lt;/code&gt; 时需要注意 slot 的用法，&lt;code&gt;slot=&quot;label&quot;&lt;/code&gt; 的组件会放到 &lt;code&gt;ui-prop&lt;/code&gt; 左边的显示区域，&lt;code&gt;slot=&quot;content&quot;&lt;/code&gt; 则是显示在右边的显示区域，如果在 &lt;code&gt;ui-prop&lt;/code&gt; 标签对中添加元素而不使用 &lt;code&gt;slot&lt;/code&gt; 属性的话，就会被另起一行显示。&lt;/p&gt;
&lt;p&gt;如果我们想在 Checkbox 的 &lt;code&gt;ui-prop&lt;/code&gt; 中再添加一个 &lt;code&gt;ui-checkbox&lt;/code&gt; 元素，且不添加 &lt;code&gt;slot&lt;/code&gt; 属性的话，就会变成如下的效果：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
...
&amp;lt;ui-prop&amp;gt;
    &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Checkbox&amp;lt;/ui-label&amp;gt;
    &amp;lt;ui-checkbox slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
    &amp;lt;ui-checkbox&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
&amp;lt;/ui-prop&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;add_checkbox_noslot.png&quot; alt=&quot;add_checkbox_noSlot&quot; /&gt;&lt;/p&gt;
&lt;p&gt;所以正确的做法应该是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
...
&amp;lt;ui-prop&amp;gt;
    &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;Checkbox&amp;lt;/ui-label&amp;gt;
    &amp;lt;ui-checkbox slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
    &amp;lt;ui-checkbox slot=&quot;content&quot;&amp;gt;&amp;lt;/ui-checkbox&amp;gt;
&amp;lt;/ui-prop&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;add_checkbox_slot.png&quot; alt=&quot;add_checkbox_noSlot&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;吐槽&lt;/em&gt;：UI 组件面板中的示例代码很好，但是详细解释太少了，要么就应该像 2.x 一样在官方文档中详细写出每个属性的用法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;至此，我们已经尝试使用 UI 组件、HTML 原生标签、CSS 样式来完成基本的面板布局，接下来就可以靠搭积木的方式打造自己的扩展面板了。&lt;/p&gt;
&lt;p&gt;如果对 HTML 和 CSS 不熟悉，或者已经忘得差不多了，可以到 &lt;a href=&quot;https://www.w3school.com.cn/&quot;&gt;W3school 官网&lt;/a&gt; 找你想要的内容。&lt;/p&gt;
&lt;h2&gt;使用 Vue3 的特性&lt;/h2&gt;
&lt;p&gt;我们来做一个根据扩展名来统计文件数量的扩展。&lt;/p&gt;
&lt;h3&gt;编写逻辑代码&lt;/h3&gt;
&lt;p&gt;先打开 &lt;code&gt;extension-vue/src/panels/default/index.ts&lt;/code&gt;，这是面板的入口文件。&lt;/p&gt;
&lt;p&gt;在模板代码中，我们主要修改 &lt;code&gt;ready&lt;/code&gt; 函数中的内容，&lt;code&gt;ready&lt;/code&gt; 函数是面板启动后触发的钩子函数。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;ready&lt;/code&gt; 函数体中，有如下的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { createApp } from &apos;vue&apos;;
// ...
module.exports = Editor.Panel.define({
    $: {
        app: &apos;#app&apos;,
    },
    ready() {
        const app = createApp({});
        app.mount(this.$.app);
    }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码的意思就是创建一个 &lt;strong&gt;Vue App&lt;/strong&gt; 挂载到 &lt;code&gt;#app&lt;/code&gt; 标签上，就是为什么我们在 &lt;code&gt;index.html&lt;/code&gt; 中需要把布局写到 &lt;code&gt;&amp;lt;div id=&quot;app&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; 标签对中的原因。&lt;/p&gt;
&lt;p&gt;在这篇演示中，我们的逻辑代码主要写在 &lt;code&gt;createApp({})&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;首先我们定义两个数据，用于存放每个扩展名对应的文件数量和文件的总数量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;createApp({
    data() {
        return {
            /** 扩展名对应的文件数量 */
            fileCount: {},
            /** 文件总数量 */
            fileNum: 0
        }
    }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着我们来写主要的逻辑，将写在 &lt;code&gt;methods: {}&lt;/code&gt; 中，&lt;code&gt;data&lt;/code&gt; 中定义的数据我们可以通过 &lt;code&gt;this.xxx&lt;/code&gt; 取到。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { readdirSync, readFileSync, statSync } from &apos;fs-extra&apos;;
import { extname, join } from &apos;path&apos;;
// ...
createApp({
    data() {
        return {
            /** 扩展名对应的文件数量 */
            fileCount: {},
            /** 文件总数量 */
            fileNum: 0
        }
    },
    methods: {
        checkAssets() {
            // 定义两个数据的临时变量
            let fileCount: {[key: string]: number} = {};
            let fileNum = 0;
            // 获取 assets 文件夹的路径
            let assetsPath = join(Editor.Project.path, &quot;assets&quot;);
            let checkDir = (dirPath: string) =&amp;gt; {
                // 获取文件夹下所有的文件名
                let files = readdirSync(dirPath);
                // 遍历文件名
                files.forEach((fileName) =&amp;gt; {
                    // 当前文件的路径
                    let subPath = join(dirPath, fileName);
                    // 文件的信息
                    let stat = statSync(subPath);

                    if (stat.isDirectory()) {
                        // 如果文件是个目录，递归查找
                        checkDir(subPath);
                    }
                    else if (stat.isFile()) {
                        // 获取文件的扩展名
                        let extName = extname(fileName);
                        if (extName != &quot;&quot; &amp;amp;&amp;amp; !fileCount[extName]) {
                            fileCount[extName] = 1;
                        }
                        else if (extName != &quot;&quot; &amp;amp;&amp;amp; fileCount[extName]) {
                            fileCount[extName] += 1;
                        }
                        else {
                            if (fileCount[&quot;other&quot;]) {
                                fileCount[&quot;other&quot;] += 1;
                            }
                            else {
                                fileCount[&quot;other&quot;] = 1;
                            }
                        }
                        fileNum++;
                    }
                })
            }

            checkDir(assetsPath);
            // 将临时变量赋值给 data 中定义的变量
            this.fileCount = fileCount;
            this.fileNum = fileNum;
        }
    }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码中我们用到了 &lt;code&gt;Editor.Project.path&lt;/code&gt; 接口，用来获取项目目录路径，可以查看 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/editor-api.html&quot;&gt;Editor API 说明&lt;/a&gt; 文档来查询需要的功能。&lt;/p&gt;
&lt;p&gt;我们这段逻辑需要在面板打开时就执行，所以我们需要用到 &lt;a href=&quot;https://cn.vuejs.org/guide/essentials/lifecycle.html&quot;&gt;生命周期钩子&lt;/a&gt; 中的 &lt;code&gt;beforeMount&lt;/code&gt; 生命周期：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ...
createApp({
    data() {
        return {
            /** 扩展名对应的文件数量 */
            fileCount: {},
            /** 文件总数量 */
            fileNum: 0
        }
    },
    methods: {
        checkAssets() {
            // ...
        }
    },
    // 挂载应用之前
    beforeMount() {
        this.checkAssets();
    }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，我们的逻辑代码就写好了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;重要&lt;/em&gt;：TS 代码需要通过 tsc 命令编译成 JS 代码才能在扩展中生效，可以在终端中执行命令 &lt;code&gt;npm run build&lt;/code&gt;，来编译 TS 脚本，或者执行 &lt;code&gt;npm run watch&lt;/code&gt; 来监听 TS 脚本的变化，自动编译。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;使用 Vue3 来布局&lt;/h3&gt;
&lt;p&gt;我们要对 &lt;code&gt;index.html&lt;/code&gt; 进行重新布局，先删除掉之前的 UI 组件示例代码，我们重新编写一套：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;div id=&quot;app&quot;&amp;gt;

        &amp;lt;h1&amp;gt;Extension Vue&amp;lt;/h1&amp;gt;

        &amp;lt;div class=&quot;box&quot;&amp;gt;

            &amp;lt;ui-prop v-for=&quot;(value, key) in fileCount&quot;&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;{{ key }}&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-input 
                    slot=&quot;content&quot; 
                    readonly
                    :value=&quot;value&quot;
                &amp;gt;
                    &amp;lt;span slot=&quot;suffix&quot;&amp;gt;个文件&amp;lt;/span&amp;gt;
                &amp;lt;/ui-input&amp;gt;
            &amp;lt;/ui-prop&amp;gt;

            &amp;lt;ui-prop&amp;gt;
                &amp;lt;ui-label slot=&quot;label&quot;&amp;gt;总计&amp;lt;/ui-label&amp;gt;
                &amp;lt;ui-input 
                    slot=&quot;content&quot; 
                    readonly
                    :value=&quot;fileNum&quot;
                &amp;gt;
                    &amp;lt;span slot=&quot;suffix&quot;&amp;gt;个文件&amp;lt;/span&amp;gt;
                &amp;lt;/ui-input&amp;gt;
            &amp;lt;/ui-prop&amp;gt;

        &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们用到了 &lt;a href=&quot;https://cn.vuejs.org/guide/essentials/list.html&quot;&gt;列表渲染&lt;/a&gt; 中的 &lt;code&gt;v-for&lt;/code&gt; 来显示出所有扩展名对应的文件数量。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:value&lt;/code&gt; 是 &lt;code&gt;v-bind:value&lt;/code&gt; 的简写，详情可参考 &lt;a href=&quot;https://cn.vuejs.org/guide/essentials/template-syntax.html#attribute-bindings&quot;&gt;Attribute 绑定&lt;/a&gt;，通过这个方法，我们将 &lt;code&gt;data&lt;/code&gt; 中定义的两个值绑定到 &lt;code&gt;ui-input&lt;/code&gt; 标签的 &lt;code&gt;value&lt;/code&gt; 属性上。&lt;/p&gt;
&lt;p&gt;这样，我们基本算是完成了这个插件的主要功能，让我们通过 &lt;code&gt;面板&lt;/code&gt; -&amp;gt; &lt;code&gt;extension-vue&lt;/code&gt; -&amp;gt; &lt;code&gt;默认面板&lt;/code&gt; 打开面板看看效果吧：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%89%A9%E5%B1%95%E6%95%88%E6%9E%9C01.png&quot; alt=&quot;扩展效果01&quot; /&gt;&lt;/p&gt;
&lt;p&gt;看来 Cocos Creator 3.7.3 的 Hello World 模板项目的 Assets 文件夹下有 58 个文件。&lt;/p&gt;
&lt;h3&gt;来点交互&lt;/h3&gt;
&lt;p&gt;我们这个扩展有个问题，他只能在打开面板的时候统计文件数量，如果我们在不关闭面板的情况下增删 Assets 目录中的文件，面板上的数据就不会刷新，我们为面板加一个按钮来手动刷新数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;div id=&quot;app&quot;&amp;gt;

        &amp;lt;h1&amp;gt;Extension Vue&amp;lt;/h1&amp;gt;

        &amp;lt;div class=&quot;box&quot;&amp;gt;
            &amp;lt;!-- ... --&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div style=&quot;text-align: center;&quot;&amp;gt;
            &amp;lt;ui-button type=&quot;primary&quot; @confirm=&quot;checkAssets&quot;&amp;gt;
                &amp;lt;ui-icon value=&quot;refresh&quot;&amp;gt;&amp;lt;/ui-icon&amp;gt;
                刷新
            &amp;lt;/ui-button&amp;gt;
        &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们用到了 &lt;a href=&quot;https://cn.vuejs.org/guide/essentials/event-handling.html&quot;&gt;事件处理&lt;/a&gt;，使用 &lt;code&gt;@confirm&lt;/code&gt; 绑定了 &lt;code&gt;checkAssets&lt;/code&gt; 函数，UI 组件支持的事件我们可以在 &lt;strong&gt;UI 组件面板&lt;/strong&gt; 中查看：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;UI%20%E7%BB%84%E4%BB%B6%E9%9D%A2%E6%9D%BF%E6%9F%A5%E7%9C%8B%E4%BA%8B%E4%BB%B6.png&quot; alt=&quot;UI 组件面板查看事件&quot; /&gt;&lt;/p&gt;
&lt;p&gt;其中 &lt;strong&gt;Events&lt;/strong&gt; 就是该组件支持的事件名，示例代码也给出了 Vue 的写法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;吐槽&lt;/em&gt;：Vue 示例代码中应该是用 &lt;code&gt;methods: {}&lt;/code&gt;，不要将 Vue 示例代码原封不动的 Copy 到脚本里，会变得不幸。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这段代码中，我们将 &lt;code&gt;ui-button&lt;/code&gt; 也装进了一个 div 中，我们可以直接在标签中添加 &lt;code&gt;style&lt;/code&gt; 属性更改标签的样式，但如果 &lt;code&gt;style&lt;/code&gt; 内容较多，建议还是写在 &lt;code&gt;index.css&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;我们关闭面板，重新打开看看效果：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%89%A9%E5%B1%95%E6%95%88%E6%9E%9C02.png&quot; alt=&quot;扩展效果02&quot; /&gt;&lt;/p&gt;
&lt;p&gt;仍然是 58 个文件。（&lt;s&gt;废话&lt;/s&gt;）&lt;/p&gt;
&lt;p&gt;不要关闭面板，我们在编辑器的资源管理器中添加一个名为 &lt;code&gt;script&lt;/code&gt; 的文件夹，并创建一个 TypeScript 脚本文件，叫 &lt;strong&gt;HelloWorld&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E8%B5%84%E6%BA%90%E7%AE%A1%E7%90%86%E5%99%A8.png&quot; alt=&quot;资源管理器&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这时，我们点击 &lt;code&gt;extension-vue&lt;/code&gt; 面板中的 &lt;strong&gt;刷新&lt;/strong&gt; 按钮。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%89%A9%E5%B1%95%E6%95%88%E6%9E%9C03.png&quot; alt=&quot;扩展效果03&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我们发现多了一个 .ts 类型文件，但是总计比之前多了 3 个，另外两个文件分别是 &lt;code&gt;script.meta&lt;/code&gt; 和 &lt;code&gt;HelloWorld.ts.meta&lt;/code&gt; 文件，这是编辑器自动生成的文件。&lt;/p&gt;
&lt;p&gt;至此，你已经尝试了 &lt;code&gt;HTML&lt;/code&gt;、&lt;code&gt;CSS&lt;/code&gt;、&lt;code&gt;UI 组件&lt;/code&gt;、&lt;code&gt;Vue3 列表渲染&lt;/code&gt;、&lt;code&gt;Vue3 事件处理&lt;/code&gt;、&lt;code&gt;Vue3 生命周期&lt;/code&gt;、&lt;code&gt;Editor 接口调用&lt;/code&gt; 等内容，相信你对 Cocos 扩展已经有了初步的了解。如果仍有疑问，请积极回帖探讨，我是个插件开发的萌新，本篇文章只是个人的经验总结，如果能让你入门插件开发，那是我的荣幸。&lt;/p&gt;
&lt;p&gt;插件开发时，请灵活运用相关的文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/readme.html&quot;&gt;扩展编辑器&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cn.vuejs.org/&quot;&gt;Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3school.com.cn/&quot;&gt;W3school&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;吐槽&lt;/em&gt;：官方文档里是有 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/i18n.html&quot;&gt;多语言系统（i18n）&lt;/a&gt; 文档的，但是这篇文档的入口被隐藏在了 &lt;a href=&quot;https://docs.cocos.com/creator/manual/zh/editor/extension/basic.html&quot;&gt;基础功能&lt;/a&gt; 页面中，侧边栏找不到这个 i18n 文档的入口，而且 &lt;strong&gt;基础功能&lt;/strong&gt; 文档，在侧边栏是叫 &lt;strong&gt;扩展功能详解&lt;/strong&gt;，真的迷惑……&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;i18n%E5%85%A5%E5%8F%A3.png&quot; alt=&quot;i18n文档入口&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;彩蛋&lt;/h3&gt;
&lt;p&gt;在扩展根目录中放入一个 PNG 格式的图片资源，命名为 &lt;code&gt;logo.png&lt;/code&gt;，就能在扩展管理器中显示 LOGO 啦。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;logo%E5%B1%95%E7%A4%BA.png&quot; alt=&quot;logo展示&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;插件开发的意义在于实现自动化，可以解放部分重复的工作，降低重复工作导致的人工犯错几率，作为程序员，就应该使用程序来帮助自己提高效率（&lt;s&gt;这样才能更好的摸鱼&lt;/s&gt;）。&lt;/p&gt;
&lt;p&gt;官方在插件开发的文档方面，从 2.x 开始一直都不太完善，感觉都是徒有文档，入门还是得自己摸索，希望有朝一日能有更完善的插件开发文档。&lt;/p&gt;
&lt;p&gt;本篇内容中编写好的插件已经开源到 &lt;a href=&quot;https://github.com/CosmoLau/extension-vue&quot;&gt;GitHub 仓库&lt;/a&gt;，需要的话请移步仓库查看。&lt;/p&gt;
&lt;p&gt;另外，如果本篇文章并不能让你入门插件开发，论坛中也有其他大佬写的开发指南，可以参考他们的帖子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forum.cocos.org/t/topic/144174&quot;&gt;[muzzik 教程]：3.x 插件开发指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forum.cocos.org/t/muzzik/99553&quot;&gt;【muzzik教程】：插件开发之道&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forum.cocos.org/t/topic/122964&quot;&gt;手把手教你如何使用 rollup + vue单文件 工作流开发 3.x 插件&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forum.cocos.org/t/topic/149927&quot;&gt;【插件开发】升级Vue2.x+Element-ui+组件式开发Creator2.x&lt;/a&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>