In this article, I discuss how Blocks page is built on ui.shadcn.com. Blocks page has a lot of utilities used, hence I broke down this Blocks page analysis into 5 parts.
- shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 1
- shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 2 (Coming soon)
- shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 3 (Coming soon)
- shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 4 (Coming soon)
- shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 5 (Coming soon)
In part 1, we will look at the following:
- Where to find blocks page code in the shadcn-ui/ui repository?
- getAllBlockIds function
- _getAllBlocks function
These function further call other utility functions that will be explained in the other parts.
Where to find blocks page code in the shadcn-ui/ui repository?
blocks/page.tsx is where you will find Blocks page related code in the shadcn-ui/ui repository
Just because it has only 10 lines of code does not mean it is a simple page, there is a lot going on behind these lines, especially in the lib/blocks.ts, but don’t worry, we will understand the utility functions used in depth later in this article and other parts as well.
BlocksPage gets the blocks from a function named getAllBlockIds() which is imported from lib/blocks and these blocks are mapped with a BlockDisplay component that shows blocks on the Blocks page. Let’s find out what is in getAllBlockIds()
getAllBlockIds function
The below code snippet is picked from lib/blocks.ts
export async function getAllBlockIds(
style: Style\["name"\] = DEFAULT\_BLOCKS\_STYLE
) {
const blocks = await \_getAllBlocks(style)
return blocks.map((block) => block.name)
}
This code snippet is self explanatory, style parameter gets a default value DEFAULT_BLOCKS_STYLE because in the Blocks page, we call getAllBlockIds without any params as shown below:
const blocks = await getAllBlockIds()
But wait, what is the value in DEFAULT\_BLOCKS\_STYLE
?
At line 14 in lib/blocks, you will find this below code:
const DEFAULT\_BLOCKS\_STYLE = "default" satisfies Style\["name"\]
“default” satisfies Style[“name”], Style is from register/styles. I just admire the quality of Typescript written in this shadcn-ui/ui. So, _getAllBlocks gets called with a param named style that is initiated to “default”. So far, the code is straight forward. Let’s now understand what is in _getAllBlocks
_getAllBlocks function
The below code snippet is picked from lib/blocks.ts
async function \_getAllBlocks(style: Style\["name"\] = DEFAULT\_BLOCKS\_STYLE) {
const index = z.record(registryEntrySchema).parse(Index\[style\])
return Object.values(index).filter(
(block) => block.type === "components:block"
)
}
Even though, getAllBlockIds from above calls this function with a parameter, this function still has a default value set to the style parameter.
const index = z.record(registryEntrySchema).parse(Index\[style\])
Code above has the following:
z.record
Record schema in Zod are used to validate types such as Record. This is particularly useful for storing or caching items by ID.
registryEntrySchema
registryEntrySchema defines a schema for the blocks
export const registryEntrySchema = z.object({
name: z.string(),
description: z.string().optional(),
dependencies: z.array(z.string()).optional(),
devDependencies: z.array(z.string()).optional(),
registryDependencies: z.array(z.string()).optional(),
files: z.array(z.string()),
source: z.string().optional(),
type: z.enum(\[
"components:ui",
"components:component",
"components:example",
"components:block",
\]),
category: z.string().optional(),
subcategory: z.string().optional(),
chunks: z.array(blockChunkSchema).optional(),
})
parse(Index[style])
parse is a schema method to check data is valid. If it is, a value is returned with full type information! Otherwise, an error is thrown.
Example:
const stringSchema = z.string();
stringSchema.parse("fish"); // => returns "fish"
stringSchema.parse(12); // throws error
Index is imported from _registry_folder and contains all the components used in shadcn-ui/ui.
Looks like this file gets auto generated by scripts/build-registry.ts and this is also used in CLI package to add shadcn components into your project, more on this in the upcominhg articles.
Basically, we validate Index[“default”] against the registry schema to ensure the auto generated code is valid and is ready for further processing such as showing in blocks page.
_getAllBlocks filters the blocks based on the block type as shown below:
return Object.values(index).filter(
(block) => block.type === "components:block"
)
This is how you are able to see components that are specific to Blocks page.
Conclusion:
We looked at two important module functions named getAllBlockIds and _getAllBlocks. I find this code to be pretty self explanatory, I do admire the way zod’s Record schema validations are used on the auto generated registry index json.
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.
Top comments (0)