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:
getRegistryBaseColors function
prompts
Creating components.json
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",
},
]
}
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,
})
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()
fs.writeFile asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an <AsyncIterable>, or an <Iterable> 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, JSON.stringify has the below syntax:
JSON.stringify(value)
JSON.stringify(value, replacer)
JSON.stringify(value, replacer, space)
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);
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),
},
})
}
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:
- 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(<some variable>) 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")
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)
Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch
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
Build shadcn-ui/ui from scratch