shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.10
Tags: opensource, shadcnui, nextjs, node
Published: 2024-07-10 21:06:46

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.9, we looked at getRegistryStyles function, fetchRegistry function and stylesSchema.

In this article, we will understand the below concepts:

1.  getRegistryBaseColors function
2.  prompts
3.  Creating components.json
4.  resolveConfigPaths

getRegistryBaseColors
---------------------

Unlike the getRegistryStyles function, getRegistryBaseColors does not use fetchRegistry function, it simply returns an array as shown below:

```js
 export async function getRegistryBaseColors() {
  return \[
    {
      name: "slate",
      label: "Slate",
    },
    {
      name: "gray",
      label: "Gray",
    },
    {
      name: "zinc",
      label: "Zinc",
    },
    {
      name: "neutral",
      label: "Neutral",
    },
    {
      name: "stone",
      label: "Stone",
    },
  \]
}
```

prompts
-------

promptForMinimalConfig calls [prompts](https://www.npmjs.com/package/prompts) with an array objects as in the below image.

![](https://media.licdn.com/dms/image/D4E12AQE2G6O8T9CXwA/article-inline_image-shrink_1500_2232/0/1720645130856?e=1726099200&v=beta&t=PvGEf5VdVxLYR5o5PYTq2JMI1EodWE_m6P9z1UGan7Q)

[Prompts is an npm package](https://www.npmjs.com/package/prompts) is an easy to use CLI prompts to enquire users for information. [Prompts docs](https://www.npmjs.com/package/prompts) has a [lot of examples](https://www.npmjs.com/package/prompts#-examples), do check them out.

Based on the response that you provide in your CLI, it sets the style, baseColor and cssVariables.

```js
const config = rawConfigSchema.parse({
    $schema: defaultConfig?.$schema,
    style,
    tailwind: {
      ...defaultConfig?.tailwind,
      baseColor,
      cssVariables,
    },
    rsc: defaultConfig?.rsc,
    tsx: defaultConfig?.tsx,
    aliases: defaultConfig?.aliases,
})
```

and these are used in setting the config.

Creating components.json
------------------------

After setting the config, promptsForMinimalConfig creates components.json using this config.

```js
// Write to file.
logger.info("")
const spinner = ora(\`Writing components.json...\`).start()
const targetPath = path.resolve(cwd, "components.json")
await fs.writeFile(targetPath, JSON.stringify(config, null, 2), "utf8")
spinner.succeed()
```

[fs.writeFile](https://nodejs.org/api/fs.html#filehandlewritefiledata-options) asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an [<AsyncIterable>](https://tc39.github.io/ecma262/#sec-asynciterable-interface), or an [<Iterable>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol) object. The promise is fulfilled with no arguments upon success.

### JSON.stringify(config, null, 2)

We all have seen JSON.stringify(<some variable>) but what are these additional params, null and 2?

Reading the [mdn docs for JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#examples), JSON.stringify has the below syntax:

```js
JSON.stringify(value)
JSON.stringify(value, replacer)
JSON.stringify(value, replacer, space)
```

This example below demonstrates perfectly

```js
function replacer(key, value) {
  // Filtering out properties
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}

const foo = {
  foundation: "Mozilla",
  model: "box",
  week: 45,
  transport: "car",
  month: 7,
};
JSON.stringify(foo, null, 2);
```

![](https://media.licdn.com/dms/image/D4E12AQH7iggUQLfjCw/article-inline_image-shrink_1500_2232/0/1720645130988?e=1726099200&v=beta&t=QifI9gBT3Sodgqeg9UgbfLc5mfy79f_KhKus10-GARo)

resolveConfigPaths
------------------

```js
export async function resolveConfigPaths(cwd: string, config: RawConfig) {
  // Read tsconfig.json.
  const tsConfig = await loadConfig(cwd)

  if (tsConfig.resultType === "failed") {
    throw new Error(
      \`Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${
        tsConfig.message ?? ""
      }\`.trim()
    )
  }

  return configSchema.parse({
    ...config,
    resolvedPaths: {
      tailwindConfig: path.resolve(cwd, config.tailwind.config),
      tailwindCss: path.resolve(cwd, config.tailwind.css),
      utils: await resolveImport(config.aliases\["utils"\], tsConfig),
      components: await resolveImport(config.aliases\["components"\], tsConfig),
      ui: config.aliases\["ui"\]
        ? await resolveImport(config.aliases\["ui"\], tsConfig)
        : await resolveImport(config.aliases\["components"\], tsConfig),
    },
  })
}
```

resolveConfigPaths has the resolvedPaths object with some keys resolved using using path.resolve. Keys like tailwindConfig, tailwindCss, utils, components, ui are set.

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

In this article, I discussed the following concepts:

1.  getRegistryBaseColors

Unlike the getRegistryStyles function, getRegistryBaseColors does not use fetchRegistry function, it simply returns an array

2\. prompts

[Prompts](https://www.npmjs.com/package/prompts) package lets you enquire users for information in the CLI. [Prompts docs](https://www.npmjs.com/package/prompts) has a [lot of examples](https://www.npmjs.com/package/prompts#-examples), do check them out.

3\. Creating components.json

promptsForMinimalConfig creates components.json using fs.writeFile

4\. JSON.stringify(config, null, 2)

We all have seen JSON.stringify(<some variable>) but what are these additional params, null and 2 used in shadcn-ui/ui CLI source code?

```js
 await fs.writeFile(targetPath, JSON.stringify(config, null, 2), "utf8")
```

[From the mdn docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#examples), JSON.stringify can have any of the following syntax:

```js
JSON.stringify(value)
JSON.stringify(value, replacer)
JSON.stringify(value, replacer, space)
```

> _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/commands/init.ts#L232](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L232)
2.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/registry/index.ts#L39](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/registry/index.ts#L39)
3.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L65](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L65)