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.2, I followed along the call stack when the function getProjectConfig is called and discussed functions named getConfig, getRawConfig. A detailed explanation is provided about getRawConfig that is called from getConfig. In this article, we will analyse few more lines of code from getConfig function.
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),
},
})
}
Let’s break this function down.
loadConfig
// Read tsconfig.json.
const tsConfig = await loadConfig(cwd)
loadConfig is imported from [tsconfig-paths](https://www.npmjs.com/package/tsconfig-paths).
This function loads the tsconfig.json or jsconfig.json. It will start searching from the specified cwd directory.
if (tsConfig.resultType === "failed") {
throw new Error(
\`Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${
tsConfig.message ?? ""
}\`.trim()
)
}
This is an error check that throws an error when tsConfig or jsConfig fails to load.
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),
},
})
configSchema is returned by the resolveConfigPaths. This code snippet uses path.resolve and resolveImport.
resolveImport
import { createMatchPath, type ConfigLoaderSuccessResult } from "tsconfig-paths"
export async function resolveImport(
importPath: string,
config: Pick<ConfigLoaderSuccessResult, "absoluteBaseUrl" | "paths">
) {
return createMatchPath(config.absoluteBaseUrl, config.paths)(
importPath,
undefined,
() => true,
\[".ts", ".tsx"\]
)
}
You can read more about createMatchPath.
Conclusion:
I updated the commanderjs-usage-in-shadcnui with shadcn-ui CLI package code to understand the getConfig call in getProjectConfig. Turns out, this little detour to understand the series of function calls following getConfig are to check if there is existing component config.
// Check for existing component config.
const existingConfig = await getConfig(cwd)
if (existingConfig) {
return existingConfig
}
Just to recap, the call stack is like this: getConfig calls getRawConfig, getRawConfig uses explorer.search (from cosmicconfig) and then if there is an existing component config, resolveConfigPaths is returned that uses some helpers function such as createMatchPath provided by tsconfig-paths package. All this trouble just to check if there’s an existingConfig. Why tho?
The answer lies in the different schema that you get when there’s an existing component config available. (configSchema and rawConfigSchema). There’s something unique about the way these functions are organised!
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:
- https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L55
- https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L4
- https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/get-config.ts#L2
- https://www.npmjs.com/package/tsconfig-paths
- https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/resolve-import.ts#L3
- https://www.npmjs.com/package/tsconfig-paths#creatematchpath
Top comments (0)