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

ramunarasinga

Ramu Narasinga

Posted on July 3, 2024

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)
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

fb.glob

const files = await fg.glob("\*\*/\*", {
    cwd,
    deep: 3,
    ignore: PROJECT\_SHARED\_IGNORE,
})
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
Enter fullscreen mode Exit fullscreen mode

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.

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:

  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
💖 💪 🙅 🚩
ramunarasinga
Ramu Narasinga

Posted on July 3, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related