shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 1.0
I wanted to find out how shadcn-ui CLI works. In this article, I discuss the code used to build the shadcn-ui/ui CLI. In part 1, we will look at a code snippet picked from packages/cli/src/index.ts.
// source: https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/index.ts
#!/usr/bin/env node
import { add } from "@/src/commands/add"
import { diff } from "@/src/commands/diff"
import { init } from "@/src/commands/init"
import { Command } from "commander"
import { getPackageInfo } from "./utils/get-package-info"
process.on("SIGINT", () => process.exit(0))
process.on("SIGTERM", () => process.exit(0))
async function main() {
const packageInfo = await getPackageInfo()
const program = new Command()
.name("shadcn-ui")
.description("add components and dependencies to your project")
.version(
packageInfo.version || "1.0.0",
"-v, --version",
"display the version number"
)
program.addCommand(init).addCommand(add).addCommand(diff)
program.parse()
}
main()
There’s about 29 lines of code in index.ts
Imports used
#!/usr/bin/env node
import { add } from "@/src/commands/add"
import { diff } from "@/src/commands/diff"
import { init } from "@/src/commands/init"
import { Command } from "commander"
import { getPackageInfo } from "./utils/get-package-info"
Shadcn CLI docs discuss three commands; add , diff , init
These commands are imported from a folder named commands in src folder.
Commander is an npm package used here to enable CLI interactions.
getPackageInfo
getPackageInfo is a small utility function found in utils/get-package-info.ts
import path from "path"
import fs from "fs-extra"
import { type PackageJson } from "type-fest"
export function getPackageInfo() {
const packageJsonPath = path.join("package.json")
return fs.readJSONSync(packageJsonPath) as PackageJson
}
Notice how there’s an enforced PackageJson type from type-fest. It is from the Legend, Sindre Sorhus. I see this guy’s name so often when I dig into open source.
fs.readJSONSync reads a JSON file and then parses it into an object. In this case, it is an object of type PackageJson.
process.on("SIGINT", () => process.exit(0))
process.on("SIGTERM", () => process.exit(0))
SIGINT: This is a signal that is typically sent to a process when a user types Ctrl+C in the terminal. It is often used to request that a process terminate gracefully. When a process receives a SIGINT signal, it can catch it and perform any necessary cleanup operations before terminating.
SIGTERM: This is a signal that is typically sent to a process by the operating system to request that the process terminate. It is often used as a graceful way to ask a process to terminate, allowing it to perform any necessary cleanup operations before exiting. Processes can catch this signal and perform cleanup operations before terminating. (Source)
Conclusion:
I have seen Commander.js being used in Next.js create-next-app package, I see it in use here again in shadcn-ui/ui. I will continue picking small code snippets from this CLI package and discuss the code. I liked the way package.json is read using a utility function getPackageInfo. This getPackageInfo uses fs.readJSONSync. There is Type assertion applied using PackageJson provided by type-fest on the Object returned by fs.readJSONSync.
Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch
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:
-
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/index.ts
-
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-package-info.ts#L5
-
https://dev.to/superiqbal7/graceful-shutdown-in-nodejs-handling-stranger-danger-29jo