In this article, we will review the Citty, an elegant CLI builder. This library is built by Unjs.
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);
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);
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;
});
},
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
Top comments (0)