shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.5
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.4, we looked at function getProjectType that returns the type of next project you are trying to install shadcn-ui via init command.
Let’s move on to the next line of code.
After finding out the projectType, the next step is to get the tailwindCssFile.
const tailwindCssFile = await getTailwindCssFile(cwd)
getTailwindCssFile is imported from ui/packages/cli/src/utils/get-project-info.ts and this function returns the main css file. Let’s find out how.
export async function getTailwindCssFile(cwd: string) {
const files = await fg.glob("**/*.css", {
cwd,
deep: 3,
ignore: PROJECT_SHARED_IGNORE,
})
if (!files.length) {
return null
}
for (const file of files) {
const contents = await fs.readFile(path.resolve(cwd, file), "utf8")
// Assume that if the file contains `@tailwind base` it's the main css file.
if (contents.includes("@tailwind base")) {
return file
}
}
return null
}
fb.glob
const files = await fg.glob("**/*", {
cwd,
deep: 3,
ignore: PROJECT_SHARED_IGNORE,
})
Check out the fast-glob docs about the deep property.
You might be wondering what’s PROJECT_SHARED_IGNORE.
Well, PROJECT_SHARED_IGNORE is an array initiated at the top of file.
Check out the docs for ignore property.
How is main css file returned?
for (const file of files) {
const contents = await fs.readFile(path.resolve(cwd, file), "utf8")
// Assume that if the file contains `@tailwind base` it's the main css file.
if (contents.includes("@tailwind base")) {
return file
}
}
There is a check contents.includes(“@tailwind base”) which is based on an assumption described in a comment.
Conclusion:
Finding the main css file with tailwind base classes based on an assumption that the content of file includes @tailwind base is clever.
Again, this getTailwindFile also uses fg.glob to get all the files in a given cwd to find the file that contains @tailwind base
I don’t know if I will ever use such an implementation but for now I know that such a thing is possible with fast-glob. Comes handy when you are building a CLI like package.
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/utils/get-project-info.ts#L80
-
https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L135