shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.4
Tags: javascript, opensource, nextjs, shadcnui
Published: 2024-07-02 20:59:35

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 parts 2.0 to 2.3, we looked at different functions involved to [check if there is an existing config.](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L74C3-L78C4)

Let’s move on to the next line of code

![](https://media.licdn.com/dms/image/D4E12AQH4Rof3EKJ5GQ/article-inline_image-shrink_1500_2232/0/1719953399104?e=1725494400&v=beta&t=OOPCscZ335HApaXOCOYMlCbCehDavg7XjMQtv-f03SQ)

After checking if there is an existing config, in the getProjectConfig function, the next step is to find out the project type.

This project type is your project’s type in which you are trying to install shadcn-ui components via init command.

```js
const projectType = await getProjectType(cwd)
```

[getProjectType](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L111) is imported from [ui/packages/cli/src/utils/get-project-info.ts](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L111) and this function has some checks to identify if your Next.js project uses app or pages router and if it has src folder.

```js
export async function getProjectType(cwd: string): Promise<ProjectType | null> {
  const files = await fg.glob("\*\*/\*", {
    cwd,
    deep: 3,
    ignore: PROJECT\_SHARED\_IGNORE,
  })

  const isNextProject = files.find((file) => file.startsWith("next.config."))
  if (!isNextProject) {
    return null
  }

  const isUsingSrcDir = await fs.pathExists(path.resolve(cwd, "src"))
  const isUsingAppDir = await fs.pathExists(
    path.resolve(cwd, \`${isUsingSrcDir ? "src/" : ""}app\`)
  )

  if (isUsingAppDir) {
    return isUsingSrcDir ? "next-app-src" : "next-app"
  }

  return isUsingSrcDir ? "next-pages-src" : "next-pages"
}
```

This code is pretty self-explanatory except for the fg.glob

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

Check out the fast-glob docs about the [deep property](https://www.npmjs.com/package/fast-glob#deep).

![](https://media.licdn.com/dms/image/D4E12AQHsMH8GlAId9Q/article-inline_image-shrink_1000_1488/0/1719953399595?e=1725494400&v=beta&t=xzys-SLtTCwmj9w-IP7kmXGkHUDaYI9PadCHafcpmqU)

You might be wondering what’s PROJECT\_SHARED\_IGNORE.

Well, PROJECT\_SHARED\_IGNORE is an [array initiated at the top of file](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L24).

![](https://media.licdn.com/dms/image/D4E12AQHzEbG6ieWTEQ/article-inline_image-shrink_1000_1488/0/1719953399007?e=1725494400&v=beta&t=eQQixxjkBp7q6sA5o7Fg57-GLrq9L88uEtDMkLD6-QQ)

Check out the docs for [ignore property.](https://www.npmjs.com/package/fast-glob#ignore)

![](https://media.licdn.com/dms/image/D4E12AQGwtP2pJVwFtA/article-inline_image-shrink_1500_2232/0/1719953399952?e=1725494400&v=beta&t=A0VaLAmR7HUALfXYGFX9Ga-Vhd5p-4FiKdLlUFG0WLg)

Conclusion:
-----------

As I moved on to the next line of code in getProjectConfig in shadcn-ui CLI source code, I found a function named getProjectType. This function’s purpose is to find out if your Next.js project uses app or pages router and whether it has src folder.

This code is pretty self explanatory:

```js
export async function getProjectType(cwd: string): Promise<ProjectType | null> {
  const files = await fg.glob("\*\*/\*", {
    cwd,
    deep: 3,
    ignore: PROJECT\_SHARED\_IGNORE,
  })

  const isNextProject = files.find((file) => file.startsWith("next.config."))
  if (!isNextProject) {
    return null
  }

  const isUsingSrcDir = await fs.pathExists(path.resolve(cwd, "src"))
  const isUsingAppDir = await fs.pathExists(
    path.resolve(cwd, \`${isUsingSrcDir ? "src/" : ""}app\`)
  )

  if (isUsingAppDir) {
    return isUsingSrcDir ? "next-app-src" : "next-app"
  }

  return isUsingSrcDir ? "next-pages-src" : "next-pages"
}
```

Except for the way files are accessed. fg.glob is set to depth level of 3 and ignores certain folders such as node\_modules, dist, build, public and .next.

From the code snippet above, there’s one of 5 values expected as a project type: null || “next-app-src” || “next-app” || “next-pages-src” || “next-pages”.

> _Want to learn how to build shadcn-ui/ui from scratch? Check out_ [_build-from-scratch_](https://tthroo.com/)

About me:
---------

Website: [https://ramunarasinga.com/](https://ramunarasinga.com/)

Linkedin: [https://www.linkedin.com/in/ramu-narasinga-189361128/](https://www.linkedin.com/in/ramu-narasinga-189361128/)

Github: [https://github.com/Ramu-Narasinga](https://github.com/Ramu-Narasinga)

Email: [ramu.narasinga@gmail.com](mailto:ramu.narasinga@gmail.com)

[Build shadcn-ui/ui from scratch](https://tthroo.com/)

References:
-----------

1.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L111](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L111)
2.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L24](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-project-info.ts#L24)