2024July

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:

  1. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L80

  2. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L135

We use cookies
We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.

Learn more