Logo

dev-resources.site

for different kinds of informations.

shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.12

Published at
7/12/2024
Categories
shadcnui
nextjs
opensource
javascript
Author
ramunarasinga
Author
13 person written this
ramunarasinga
open
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.12

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.11, we looked at runInit function and how shadcn-ui/ui ensures directories provided in resolvedPaths in config exist.

The following operations are performed in runInit function:

  1. Ensure all resolved paths directories exist.
  2. Write tailwind config.
  3. Write css file.
  4. Write cn file.
  5. Install dependencies.

Let’s understand how shadcn-ui/ui CLI writes to tailwind config in runInit function.

Write tailwind config

After checking the directories exist, there are few more operations performed before writing tailwind config as shown in the below code.

This code is picked from cli/src/commands/init.ts.

const extension = config.tsx ? "ts" : "js"

const tailwindConfigExtension = path.extname(
  config.resolvedPaths.tailwindConfig
)

let tailwindConfigTemplate: string
if (tailwindConfigExtension === ".ts") {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_TS\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG\_TS
} else {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG
}

// Write tailwind config.
await fs.writeFile(
  config.resolvedPaths.tailwindConfig,
  template(tailwindConfigTemplate)({
    extension,
    prefix: config.tailwind.prefix,
  }),
  "utf8"
)
Enter fullscreen mode Exit fullscreen mode

Let’s understand this code snippet

Extension

const extension = config.tsx ? "ts" : "js"
Enter fullscreen mode Exit fullscreen mode

This extension is used in later parts of code that deal with writing cn file.

tailwindConfigExtension

const tailwindConfigExtension = path.extname(
  config.resolvedPaths.tailwindConfig
)
Enter fullscreen mode Exit fullscreen mode

The path.extname() method returns the extension of the path, from the last occurrence of the . (period) character to end of string in the last portion of the path. If there is no . in the last portion of the path, or if there are no . characters other than the first character of the basename of path (see path.basename()) , an empty string is returned.

let tailwindConfigTemplate: string
if (tailwindConfigExtension === ".ts") {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_TS\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG\_TS
} else {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG
}
Enter fullscreen mode Exit fullscreen mode

Depending on the tailwindConfigExtension and config.tailwind.cssVariables, tailwindConfigTemplate is set to a value using templates. Templates is imported from utils/templates and contains some variables initialised with values related to tailwind config

Write to tailwind config file

await fs.writeFile(
  config.resolvedPaths.tailwindConfig,
  template(tailwindConfigTemplate)({
    extension,
    prefix: config.tailwind.prefix,
  }),
  "utf8"
)
Enter fullscreen mode Exit fullscreen mode

template used here in the above snippet is different from utils/templates. Different how? this template is imported from lodash.template

Read more about lodash.template

An example using lodash.template:

// Use the "interpolate" delimiter to create a compiled template.
var compiled = \_.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'
Enter fullscreen mode Exit fullscreen mode

This explains why there is %extension% in utils/templates.ts

It gets replaced with w/e is passed. Interesting…

Conclusion:

After checking the directories exist (explained in the part 2.11), there are few more operations performed before writing tailwind config as shown in the below code.

const extension = config.tsx ? "ts" : "js"

const tailwindConfigExtension = path.extname(
  config.resolvedPaths.tailwindConfig
)

let tailwindConfigTemplate: string
if (tailwindConfigExtension === ".ts") {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_TS\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG\_TS
} else {
  tailwindConfigTemplate = config.tailwind.cssVariables
    ? templates.TAILWIND\_CONFIG\_WITH\_VARIABLES
    : templates.TAILWIND\_CONFIG
}

// Write tailwind config.
await fs.writeFile(
  config.resolvedPaths.tailwindConfig,
  template(tailwindConfigTemplate)({
    extension,
    prefix: config.tailwind.prefix,
  }),
  "utf8"
)
Enter fullscreen mode Exit fullscreen mode

extension β€” This extension is used in later parts of code that deal with writing cn file.

tailwindConfigExtension β€” The path.extname() method returns the extension of the path, from the last occurrence of the . (period) character to end of string in the last portion of the path.

Depending on the tailwindConfigExtension and config.tailwind.cssVariables, tailwindConfigTemplate is set to a value using templates. Templates is imported from utils/templates and contains some variables initialised with values related to tailwind config

Write to tailwind config file β€” using fs.writeFile, tailwindConfig is updated but there is a catch. template from lodash.template is used to perform some replacements before writing to the file.

An example usage of lodash.template from the docs:

// Use the "interpolate" delimiter to create a compiled template.
var compiled = \_.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'
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: [email protected]

Learn the best practices used in open source.

References:

  1. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L331C3-L356C4
  2. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L53
  3. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L43
  4. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L20
  5. https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/templates.ts
  6. https://lodash.com/docs#template
shadcnui Article's
30 articles in total
Favicon
Color Highlighting for Tailwind CSS Variables in VS Code
Favicon
Shadcn UI Theme generator, with OKLCH colors and ancient sacred geometry.
Favicon
Next.js Starter Kit: Build Fast & Secure Apps with Auth, Payments & More!
Favicon
Comparing the copyToClipboard implementations in Shadcn-ui/ui and Codehike.
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 3.1
Favicon
Comparison of file and component structures among Shadcn-ui, Plane.so and Gitroom.
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 3.0
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.15
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.14
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.13
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.12
Favicon
Create File Upload UI in Next.js with Shadcn UI
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.11
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.10
Favicon
How to Use Icons in Shadcn UI with Next.js
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.9
Favicon
Next.js with Shadcn UI Progress Bar Example
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.7
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.5
Favicon
How to Use Scroll Area in Next.js with Shadcn UI
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.4
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.3
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.2
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.0
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 2.1
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 1.1
Favicon
shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? β€” Part 1.0
Favicon
shadcn-ui/ui codebase analysis: How is β€œBlocks” page built β€” Part 5
Favicon
Next.js Image File Upload and Preview with shadcn/ui
Favicon
shadcn-ui/ui codebase analysis: How is β€œBlocks” page built β€” Part 3

Featured ones: