CodeGenius 灵活组合的 CLI 工具

🎄Hi~ 大家好,我是小鑫同学,资深 IT 从业者,InfoQ 的签约作者,擅长前端开发并在这一领域有多年的经验,致力于分享我在技术方面的见解和心得

CodeGenius 是我最近开发的 CLI 工具, 它与你在社区看到的其它 CLI 工具的本质区别是可以 灵活组合 , 这样你既可以为不同的项目组合不同的 CLI 功能, 也可以通过插件开发来替换掉已经过时或不兼容的功能, 灵活组合 对于 CLI 功能较多或项目间应用规则不一致的情况是一个良好的解决方案.

认识 CodeGenius

通过框架图可以了解到, 在 CodeGenius 的核心部分提供了 CLI 命令行注册注册的功能, 还内置了常用的 commit, scrript, fix 命令, 并提供了配置文件的支持, 对于其他额外的功能全部放到插件里面去做, 通过配置文件来进行插件的组合, 形成符合某一个或某一系列项目的 CLI 工具.

CLI 基础功能搭建

这里使用 cac 来作为 CLI 基础功能的搭建, 所有的 CLI 功能全部通过 setup 函数进行注册.

typescript 复制代码
import cac from "cac";

import { handleError, setup } from "@/helper";
import { plugins } from "@/index";

import pkg from "../package.json";

const setupCli = async () => {
  const cli = cac("codeg");

  await setup(cli, plugins);

  cli.help();
  cli.version(pkg.version);

  cli.parse(process.argv, { run: false });

  await cli.runMatchedCommand();
};

setupCli().catch(handleError);

由于内置命令和外置命令在自定义配置时略有差别, 所以在 setup 函数中内置的命令需要在此执行并传入自定义配置, rootInstaller 作为特殊的内置命令, 承接着所所有命令通过选项式执行的兜底功能.

typescript 复制代码
export async function setup(cli: CAC, plugins: BuiltInPlugins) {
  const uconfig = await loadConfigModule();
  const commands: Array<CommandOptions> = [];
  
  const builtInPluginsIns = plugins.map((fn) => fn(uconfig?.commands));

  for (const pluginIns of builtInPluginsIns.concat(uconfig?.plugins || [])) {
    if (pluginIns.command && pluginIns.describe) {
      commands.push({
        display: pluginIns.name || pluginIns.command,
        command: pluginIns.command,
        description: pluginIns.describe,
      });
    }
    pluginIns.setup(cli);
  }
  // 特殊处理
  rootInstaller(commands.concat(defaultCommands)).setup(cli);
}

自定义配置

自定义配置需要用到的一个关键技术就是 模块动态加载 , 目前仅支持加载 codeg.config.js, codeg.config.mjs 文件且必须是 ESM 模块, 如果需要加载更多的模块类型, 还需要额外的兼容.

typescript 复制代码
export async function loadConfigModule(): Promise<
  CodeGeniusOptions | undefined
> {
  let resolvedPath: string | undefined;
  for (const filename of DEFAULT_CONFIG_FILES) {
    const filePath = path.resolve(process.cwd(), filename);
    if (!fs.existsSync(filePath)) continue;
    resolvedPath = filePath;
    break;
  }

  if (!resolvedPath) return;
  const moduleURL = pathToFileURL(resolvedPath).href;
  return (await import(moduleURL)).default;
}

同样的我也为自定义配置添加了 defineConfig 函数, 在配置时可以减少一些不必要的麻烦.

typescript 复制代码
export interface CodeGeniusOptions {
  commands?: CommandsOptions;
  plugins?: Plugins;
}

export const defineConfig = (config: CodeGeniusOptions): CodeGeniusOptions =>
  config;

script 命令

script 命令的主要功能是, 代理运行 package.scripts 脚本, 用于项目有大量 scripts 的情况, 可以生成单独的配置文件用来描述每个 script 的作用, 并通过询问模式来执行对应的 script.

typescript 复制代码
export default function scriptRunInstaller() {
  return {
    name: "script",
    describe: "代理运行 package.scripts 脚本",
    command: "script",
    setup: (cli: CAC) => {
      cli
        .command("script", "代理运行 package.scripts 脚本")
        .action(async () => {
          await generateScripts();
          await scriptRun();
        });
    },
  };
}

CodeGenius 插件开发

verify 命令是用来检查 GitCommit 时所编写的描述是否符合规范的功能, 现在我通过 verify 示例来演示 CodeGenius 的插件开发.

注册函数

gitCommitVerifyInstaller 函数返回的对象中, name, describe, command, 都是为 root 命令在提供数据, 在这 root 兜底功能中很有必要.

setup 函数中通过调用 cacAPI 来实现 verify 命令的注册, 并在 action 中调用功能函数.

typescript 复制代码
const gitCommitVerifyInstaller = () => {
  return {
    name: "verify",
    describe: "校验 COMMIT_EDITMSG 中的信息是否符合 Angualr 规范",
    command: "verify",
    setup: (cli: CAC) => {
      cli
        .command("verify", "校验 COMMIT_EDITMSG 中的信息是否符合 Angualr 规范")
        .action(async () => {
          await gitCommitVerify();
        });
    },
  };
};

功能函数

COMMIT_EDITMSG 是使用 git commit 命令时生成用于存储 git 提交信息的临时文件, 所以读取和校验就变得很简单了.

typescript 复制代码
const gitCommitVerify = async () => {
  const dogit = await execCommand("git", ["rev-parse", "--show-toplevel"]);
  const root = path.join(dogit || "", ".git", "COMMIT_EDITMSG");

  const content = readFileSync(root, { encoding: "utf-8" }).trim();

  const REG_EXP =
    /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
  if (!REG_EXP.test(content)) {
    printError(
      "Git 提交信息不符合 Angualr 规范, 建议运行 `npx code-genius commit` 生成规范信息",
    );
    process.exit(1);
  } else {
    printInfo("Git 提交信息校验通过");
  }
};

接着导出功能函数和注册函数, 以便插件注册和 API 方式调用.

typescript 复制代码
export { gitCommitVerify, gitCommitVerifyInstaller };

CodeGenius 插件使用

在你所需要的用到 verify 命令的项目中安装 code-geniu@codegenius/verify-plugin, 并在项目根目录增夹 codeg.config.mjs 文件, 下面是配置的具体内容.

typescript 复制代码
import { defineConfig } from "code-genius";
import { gitCommitVerifyInstaller } from "@codegenius/verify-plugin";

export default defineConfig({
  plugins: [
    gitCommitVerifyInstaller(),
  ],
});

配置完成后你就可以通过 codeg 来列出所有已注册命令的选项, 当然你也可以通过 codeg -h 来查看所有已注册的命令.

CodeGenius 已有插件

因目前仍集中在调教插件化的核心功能, 上面的插件仅作为参考使用, 更多细节可以在 github.com/FE-CodeGeni... 查看.

相关推荐
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫3 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦4 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子4 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享5 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
清灵xmf7 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨7 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL7 小时前
npm入门教程1:npm简介
前端·npm·node.js
小白白一枚1118 小时前
css实现div被图片撑开
前端·css