shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.14

shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.14

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.11, we looked at runInit function and how shadcn-ui/ui ensures directories provided in resolvedPaths in config exist.

The following operations are performed in runInit function:

  1. Ensure all resolved paths directories exist.

  2. Write tailwind config.

  3. Write css file.

  4. Write cn file.

  5. Install dependencies.

#1, #2, #3 from the above are covered in part 2.12 and 2.13, let’s find out how “Write cn file” operation is done.

Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch

Write cn file

The below code snippet is picked from cli/src/commands/init.ts

// Write cn file.
  await fs.writeFile(
    `${config.resolvedPaths.utils}.${extension}`,
    extension === "ts" ? templates.UTILS : templates.UTILS_JS,
    "utf8"
  )

templates.UTILS contains the below code

export const UTILS = `import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
`

export const UTILS_JS = `import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}
`

cn utility is literally code returned as a string and written to lib/utils when you run shadcn init.

Conclusion:

templates.UTILS variable in packages/cli/src/commands/init.ts contains the cn utility function related code.

export const UTILS = `import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}
`

export const UTILS_JS = `import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}
`

Catch here is, this code is presented as a string into fs.writeFile that writes to a provided path as shown below

await fs.writeFile(
    `${config.resolvedPaths.utils}.${extension}`,
    extension === "ts" ? templates.UTILS : templates.UTILS_JS,
    "utf8"
  )

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:

  1. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L331C3-L356C4

  2. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/templates.ts#L1