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 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
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
Get free courses inspired by the best practices used in open source.
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
Learn the best practices used in open source.
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://www.npmjs.com/package/commander
- https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/add.ts#L22
Top comments (0)