shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 3.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 2.0 to 2.15, I discussed how npx shadcn-ui init works under the hood.
We will look at how npx shadcn-ui add <component> works in this part 3.x.
Since the packages/cli/src/commands/add.ts file is large, I will break this analysis down into parts and talk about code snippets and explain how stuff works.
In this article, we will look the concepts:
Add command.
Commander.js package
How add command is registered?
Argument and options
addOptionsSchema
Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch
add command
export const add = new Command()
.name("add")
.description("add a component to your project")
.argument("[components...]", "the components to add")
.option("-y, --yes", "skip confirmation prompt.", true)
.option("-o, --overwrite", "overwrite existing files.", false)
.option(
"-c, --cwd <cwd>",
"the working directory. defaults to the current directory.",
process.cwd()
)
.option("-a, --all", "add all available components", false)
.option("-p, --path <path>", "the path to add the component to.")
.action(async (components, opts) => {
try {
const options = addOptionsSchema.parse({
components,
...opts,
})
We will begin with how add command is added. The above code snippet is picked from packages/cli/src/commands/add.ts
Commander.js package:
Command is imported from commander.js, a complete solution for node.js command-line interfaces.
How add command is registered?
The way add command is registered is that, if you open this src/commands/index.ts in a new tab, you will find this code as shown below
Commands are created separately in the folder named commands for maintainability purposes. If you were to fork this shadcn-ui/ui repo and want to add your own command, this is one way to do it.
Argument and options
When you write something like npx shadcn-ui add Button, Button here is an argument.
.argument("[components...]", "the components to add")
The above code snippet is picked from here.
You also have options that go with your add command as shown below:
.option("-y, --yes", "skip confirmation prompt.", true)
.option("-o, --overwrite", "overwrite existing files.", false)
.option(
"-c, --cwd <cwd>",
"the working directory. defaults to the current directory.",
process.cwd()
)
.option("-a, --all", "add all available components", false)
.option("-p, --path <path>", "the path to add the component to.")
and then you have action
.action(async (components, opts) => {
addOptionsSchema
const options = addOptionsSchema.parse({
components,
...opts,
})
const cwd = path.resolve(options.cwd)
if (!existsSync(cwd)) {
logger.error(`The path ${cwd} does not exist. Please try again.`)
process.exit(1)
}
The above snippet is picked from add.ts
addOptionsSchema is declared just above the add function as shown below:
const addOptionsSchema = z.object({
components: z.array(z.string()).optional(),
yes: z.boolean(),
overwrite: z.boolean(),
cwd: z.string(),
all: z.boolean(),
path: z.string().optional(),
})
This schema basically ensures all the options and arguments are valid before processing them further.
Conclusion:
In Part 2.0 to 2.15, I discussed how npx shadcn-ui init works under the hood. It is time for a version bump to my articles. In 3.x articles, I will write about how npx shadcn-ui add works under the hood. Please note that semver is not applicable to my articles lol.
Command is imported from commander.js, a complete solution for node.js command-line interfaces. The way add command is registered with npx shadcn-ui CLI is that, if you open this src/commands/index.ts in a new tab, you will find this code as shown below:
program.addCommand(init).addCommand(add).addCommand(diff)
There’s an argument that accepts a single component name or an array of component names, that is why you would write something like npx shadcn-ui add Button
Buttonhere is an argument. add command also has few options such -y, -o, -c, -a, -p. Read more about these in the shadcn-ui CLI documentation.
addOptionsSchema ensures that arguments and the options passed to the add command are valid using zod
Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch
About me:
Website: https://ramunarasinga.com/
Linkedin: https://www.linkedin.com/in/ramu-narasinga-189361128/
Github: https://github.com/Ramu-Narasinga
Email: ramu.narasinga@gmail.com
Build shadcn-ui/ui from scratch
References
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/add.ts
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/add.ts#L31C1-L49C9
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/index.ts#L24
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/add.ts#L22
Subscribe to my newsletter
Read articles from Ramu Narasinga directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by