Skip to content

Bun实现一个命令行工具

Posted on:2025年2月8日 at 18:44

思考

在我们使用有些 npm 库(cli)时,我们可以使用某些指令(命令行接口)来使用该库。例如rolluprollup src/main.js -f cjs;或vitevite dev

那么他们时如何实现的?

关于node是实现该功能网上有很多文章,大家可自行查阅。

接下来我们使用bun来实现该功能。其实与 nodejs 实现原理一致。 我们来实现一个简单的输入输出命令printer;

创建项目

  1. 新建printer文件夹
  2. 使用bun init来初始化项目。

index.ts

#!/usr/bin/env node

import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import { readFileSync } from "node:fs";

// 获取当前文件的目录
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// 读取 package.json
const packageJson = JSON.parse(
  readFileSync(join(__dirname, "package.json"), "utf-8")
);
const version: string = packageJson.version;

function evaluateMathExpression(expr: string): number {
  try {
    return new Function(`return ${expr}`)();
  } catch (error) {
    console.error("无效的数学表达式");
    return NaN;
  }
}

function printHelp(): void {
  console.log(`
打印工具 v${version}

用法:
  printer <文本>          打印文本
  printer --version      显示版本号
  printer --help         显示帮助信息
  printer --math <表达式> 计算数学表达式

示例:
  printer hello world
  printer --math 1+1
  `);
}

type StrategyFunction = (args: string[]) => void;

const strategies: { [key: string]: StrategyFunction } = {
  "--version": (): void => {
    console.log(version);
  },

  "--help": printHelp,

  "--math": (args: string[]): void => {
    if (args.length < 2) {
      console.error("请提供数学表达式");
      return;
    }
    const expression = args.slice(1).join("");
    const result = evaluateMathExpression(expression);
    if (!isNaN(result)) {
      console.log(result);
    }
  },

  default: (args: string[]): void => {
    console.log(args.join(" "));
  },
};

function printArgs(): void {
  const args: string[] = process.argv.slice(2);

  if (args.length === 0) {
    printHelp();
    return;
  }

  const strategy: StrategyFunction = strategies[args[0]] || strategies.default;
  strategy(args);
}

printArgs();

修改 package.json

{
  "name": "printer",
  "module": "dist/index.js",
  "version": "1.0.0",
  "type": "module",
  "devDependencies": {
    "@types/bun": "latest"
  },
  "scripts": {
    "start": "bun index.ts",
    "build": "bun build index.ts --target node --outdir dist && cp package.json dist"
  },
  "bin": {
    "printer": "./dist/index.js"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  }
}

打包

bun run build

安装到当前项目

bun link

就可以使用啦

printer hello
hello

printer --math 1+1
2

全局使用

npm install -g .

也可发布到 npm 上面