DEV Community

Cover image for shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.10
Ramu Narasinga
Ramu Narasinga

Posted on • Edited on

1

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

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:



 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",
    },
  \]
}


Enter fullscreen mode Exit fullscreen mode

prompts

promptForMinimalConfig calls prompts with an array objects as in the below image.

Prompts is an npm package is an easy to use CLI prompts to enquire users for information. Prompts docs has a lot of examples, do check them out.

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



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


Enter fullscreen mode Exit fullscreen mode

and these are used in setting the config.

Creating components.json

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



// 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()


Enter fullscreen mode Exit fullscreen mode

fs.writeFile asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an , or an object. The promise is fulfilled with no arguments upon success.

JSON.stringify(config, null, 2)

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

Reading the mdn docs for JSON.stringify, JSON.stringify has the below syntax:



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


Enter fullscreen mode Exit fullscreen mode

This example below demonstrates perfectly



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);


Enter fullscreen mode Exit fullscreen mode

resolveConfigPaths



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),
    },
  })
}


Enter fullscreen mode Exit fullscreen mode

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 package lets you enquire users for information in the CLI. Prompts docs has a lot of 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() but what are these additional params, null and 2 used in shadcn-ui/ui CLI source code?



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


Enter fullscreen mode Exit fullscreen mode

From the mdn docs, JSON.stringify can have any of the following syntax:



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


Enter fullscreen mode Exit fullscreen mode

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/commands/init.ts#L232
  2. 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

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more