DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on • Edited on • Originally published at thinkthroo.com

1

Citty, an elegant CLI builder by Unjs

In this article, we will review the Citty, an elegant CLI builder. This library is built by Unjs.

Image description

I came across this package in cli.ts in unbuild. Let’s see this in action by running some experiments in codesandbox.

I copied the code below, provided in citty docs, in a codesandbox project.

import { defineCommand, runMain } from "citty";

const main = defineCommand({
  meta: {
    name: "hello",
    version: "1.0.0",
    description: "My Awesome CLI App",
  },
  args: {
    name: {
      type: "positional",
      description: "Your name",
      required: true,
    },
    friendly: {
      type: "boolean",
      description: "Use friendly greeting",
    },
  },
  run({ args }) {
    console.log(`${args.friendly ? "Hi" : "Greetings"} ${args.name}!`);
  },
});

runMain(main);
Enter fullscreen mode Exit fullscreen mode

and below image shows the outcome.

Link to codesandbox — https://codesandbox.io/p/devbox/vlmqqv

Pretty straightforward right? let’s now review how this is implemented in cli.ts in unbuild source code.

#!/usr/bin/env node
import { defineCommand, runMain } from "citty";
import consola from "consola";
import { resolve } from "pathe";
import { name, version, description } from "../package.json";
import { build } from "./build";

const main = defineCommand({
  meta: {
    name,
    version,
    description,
  },
  args: {
    dir: {
      type: "positional",
      description: "The directory to build",
      required: false,
    },
    config: {
      type: "string",
      description: [
        "The configuration file to use relative to the current working directory.",
        "                 Unbuild tries to read `build.config` from the build `DIR` by default.",
        "",
      ].join("\n"),
    },
    watch: {
      type: "boolean",
      description: "Watch the src dir and rebuild on change (experimental)",
    },
    stub: {
      type: "boolean",
      description: "Stub the package for JIT compilation",
    },
    minify: {
      type: "boolean",
      description: "Minify build",
    },
    sourcemap: {
      type: "boolean",
      description: "Generate sourcemaps (experimental)",
    },
    parallel: {
      type: "boolean",
      description:
        "Run different types of builds (untyped, mkdist, Rollup, copy) simultaneously.",
    },
  },
  async run({ args }) {
    const rootDir = resolve(process.cwd(), args.dir || ".");
    await build(rootDir, args.stub, {
      sourcemap: args.sourcemap,
      config: args.config ? resolve(args.config) : undefined,
      stub: args.stub,
      watch: args.watch,
      rollup: {
        esbuild: {
          minify: args.minify,
        },
      },
    }).catch((error) => {
      consola.error(`Error building ${rootDir}: ${error}`);
      throw error;
    });
  },
});

runMain(main);
Enter fullscreen mode Exit fullscreen mode

In the example provided in the documentation, there were two argument

  • friendly

  • name

But the cli.ts has arguments specific to unbuild:

  • dir — string

  • config — string

  • watch — boolean

  • stub — boolean

  • minify — boolean

  • sourcemap — boolean

  • parallel — boolean

run

async run({ args }) {
    const rootDir = resolve(process.cwd(), args.dir || ".");
    await build(rootDir, args.stub, {
      sourcemap: args.sourcemap,
      config: args.config ? resolve(args.config) : undefined,
      stub: args.stub,
      watch: args.watch,
      rollup: {
        esbuild: {
          minify: args.minify,
        },
      },
    }).catch((error) => {
      consola.error(`Error building ${rootDir}: ${error}`);
      throw error;
    });
  },
Enter fullscreen mode Exit fullscreen mode

All the options passed via CLI are used in build function as a parameter. build function is imported from ‘build.ts’ function.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com

My Github — https://github.com/ramu-narasinga

My website — https://ramunarasinga.com

My Youtube channel — https://www.youtube.com/@thinkthroo

Learning platform — https://thinkthroo.com

Codebase Architecture — https://app.thinkthroo.com/architecture

Best practices — https://app.thinkthroo.com/best-practices

Production-grade projects — https://app.thinkthroo.com/production-grade-projects

References:

  1. https://github.com/unjs/citty

  2. https://github.com/unjs/unbuild/blob/main/src/cli.ts#L2C41-L2C46

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay