shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 2
Tags: javascript, nextjs, shadcnui, opensource
Published: 2024-06-18 20:45:47

In this article, I discuss how [Blocks page](https://ui.shadcn.com/blocks) is built on [ui.shadcn.com](http://ui.shadcn.com). [Blocks page](https://github.com/shadcn-ui/ui/blob/main/apps/www/app/(app)/blocks/page.tsx) has a lot of utilities used, hence I broke down this Blocks page analysis into 5 parts.

1.  [shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 1](https://medium.com/@ramu.narasinga_61050/shadcn-ui-ui-codebase-analysis-how-is-blocks-page-built-part-1-ac4472388f0a)
2.  shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 2
3.  shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 3 (Coming soon)
4.  shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 4 (Coming soon)
5.  shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 5 (Coming soon)

[In part 1](https://medium.com/@ramu.narasinga_61050/shadcn-ui-ui-codebase-analysis-how-is-blocks-page-built-part-1-ac4472388f0a), we looked at two important modular functions named getAllBlockIds and \_getAllBlocks.

In part 2, we will look at the following:

1.  Where is BlockDisplay used?
2.  Where to find BlockDisplay component?
3.  BlockDisplay component explained
4.  getBlock function

Where is BlockDisplay used?
---------------------------

![](https://media.licdn.com/dms/image/D4E12AQEsNx5kAw8vCQ/article-inline_image-shrink_1500_2232/0/1718743004987?e=1724284800&v=beta&t=AFIyfAKBEXQCRPT_SXMjcdEdQ2mCkr-G3E7wQHwPkKQ)

BlockDisplay is used in [blocks/page.tsx](https://github.com/shadcn-ui/ui/blob/main/apps/www/app/(app)/blocks/page.tsx). In part 1, I explained the code behind fetching blocks; When you visit [blocks page](https://ui.shadcn.com/blocks) on [ui.shadcn.com](http://ui.shadcn.com), you will find a lot of blocks rendered, it is in fact from blocks array above. These blocks so far do not contain the code that translates to a components used in an individual block. BlockDisplay has it own logic to deal with rendering components for each block. Important concept here to remember is to pass the minimal information required.

Where to find BlockDisplay component?
-------------------------------------

You can find BlockDisplay component exported from [components/block-display.tsx](https://github.com/shadcn-ui/ui/blob/main/apps/www/components/block-display.tsx#L5).

![](https://media.licdn.com/dms/image/D4E12AQH034Pb-PuHqw/article-inline_image-shrink_1000_1488/0/1718743006429?e=1724284800&v=beta&t=vjfU1dk-0bjpI1L1Gaotx7whlNgLbWPi6e-2RQ5LFis)

Has about 29 lines of code.

BlockDisplay component explained
--------------------------------

Let’s try to understand the BlockDisplay code at a high level.

```js
import { getBlock } from "@/lib/blocks"
import { BlockPreview } from "@/components/block-preview"
import { styles } from "@/registry/styles"

export async function BlockDisplay({ name }: { name: string }) {
  const blocks = await Promise.all(
    styles.map(async (style) => {
      const block = await getBlock(name, style.name)
      const hasLiftMode = block?.chunks ? block?.chunks?.length > 0 : false

      // Cannot (and don't need to) pass to the client.
      delete block?.component
      delete block?.chunks

      return {
        ...block,
        hasLiftMode,
      }
    })
  )

  if (!blocks?.length) {
    return null
  }

  return blocks.map((block) => (
    <BlockPreview key={\`${block.style}-${block.name}\`} block={block} />
  ))
}
```

There is a blocks array that is populated after Promise.all resolves. Promise.all has an array of styles imported from registry/styles. These styles are mapped over and each style is further processed.

getBlock is a utility function that accepts two parameters, name and [style.name](http://style.name) and there is also a flag named hasLiftMode that is based on block.chunks.length. block.components and block.chunks are deleted as they are not required on the client side.

These blocks are then mapped over and each block is used in BlockPreview.

getBlock function
-----------------

getBlock function is imported [lib/blocks.ts](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L27) and contains the code below:

```js
export async function getBlock(
  name: string,
  style: Style\["name"\] = DEFAULT\_BLOCKS\_STYLE
) {
  const entry = Index\[style\]\[name\]

  const content = await \_getBlockContent(name, style)

  const chunks = await Promise.all(
    entry.chunks?.map(async (chunk: BlockChunk) => {
      const code = await readFile(chunk.file)

      const tempFile = await createTempSourceFile(\`${chunk.name}.tsx\`)
      const sourceFile = project.createSourceFile(tempFile, code, {
        scriptKind: ScriptKind.TSX,
      })

      sourceFile
        .getDescendantsOfKind(SyntaxKind.JsxOpeningElement)
        .filter((node) => {
          return node.getAttribute("x-chunk") !== undefined
        })
        ?.map((component) => {
          component
            .getAttribute("x-chunk")
            ?.asKind(SyntaxKind.JsxAttribute)
            ?.remove()
        })

      return {
        ...chunk,
        code: sourceFile
          .getText()
          .replaceAll(\`@/registry/${style}/\`, "@/components/"),
      }
    })
  )

  return blockSchema.parse({
    style,
    highlightedCode: content.code ? await highlightCode(content.code) : "",
    ...entry,
    ...content,
    chunks,
    type: "components:block",
  })
}
```

As you can see, there is a lot going on here. We will cover some part of this code in this article and the rest in the coming articles.

```js
const entry = Index\[style\]\[name\]
const content = await \_getBlockContent(name, style)
```

Index is imported from \_registry\_ and is autogenerated by [scripts/build-registry.ts](https://github.com/shadcn-ui/ui/blob/main/apps/www/scripts/build-registry.mts) (more on this later).

[_getBlockContent_](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L107) _returns an object that is assigned to content. The below code is picked from_ getBlockContent.

```js
async function \_getBlockContent(name: string, style: Style\["name"\]) {
  const raw = await \_getBlockCode(name, style)
```

as you can this, in turn, calls \_getBlockCode.

\_getBlockCode has the code

```js
async function \_getBlockCode(
  name: string,
  style: Style\["name"\] = DEFAULT\_BLOCKS\_STYLE
) {
  const entry = Index\[style\]\[name\]
  const block = registryEntrySchema.parse(entry)

  if (!block.source) {
    return ""
  }

  return await readFile(block.source)
}
```

I have talked about Index, registryEntrySchema and parse in great detail in [part 1](https://medium.com/@ramu.narasinga_61050/shadcn-ui-ui-codebase-analysis-how-is-blocks-page-built-part-1-ac4472388f0a). we did not understand the readFile function yet.

readFile
--------

readFile function is used to read file content from block.source

```js
async function readFile(source: string) {
  const filepath = path.join(process.cwd(), source)
  return await fs.readFile(filepath, "utf-8")
}
```

[Index](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/index.tsx) contains blocks that do not have source, but at the end, you will find some blocks with source as shown below

![](https://media.licdn.com/dms/image/D4E12AQE_O0rZ4ynOfg/article-inline_image-shrink_1000_1488/0/1718743007391?e=1724284800&v=beta&t=JUMm6dHLZb9r7tKUI8uBOkqG-UzsGviY5jiB9NKNGzA)

For example, for authentication-04, code is available at [_registry_](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx)[/new-york/block/authentication-04.tsx](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx).

![](https://media.licdn.com/dms/image/D4E12AQGZcT4pgfDrTQ/article-inline_image-shrink_1000_1488/0/1718743006768?e=1724284800&v=beta&t=RPPbPz6i2awzCkTnLO0hcYZVsuJmL4AXzjdAr3YNHGI)

What you see above as one of the blocks shown on blocks page on [ui.shadcn.com](http://ui.shadcn.com) is the code from [_registry_](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx)[/new-york/block/authentication-04.tsx](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx). Isn’t this awesome!?

Let’s take a step back now and get back on track with out function call stack. We got to readFile from \_getBlockCode. With this so far, we have understood the \_getBlockCode. We got to \_getBlockCode from \_\_getBlockContent and only covered the first line as shown below

### \_getBlockContent

```js
async function \_getBlockContent(name: string, style: Style\["name"\]) {
  const raw = await \_getBlockCode(name, style)

  const tempFile = await createTempSourceFile(\`${name}.tsx\`)
  const sourceFile = project.createSourceFile(tempFile, raw, {
    scriptKind: ScriptKind.TSX,
  })

  // Extract meta.
  const description = \_extractVariable(sourceFile, "description")
  const iframeHeight = \_extractVariable(sourceFile, "iframeHeight")
  const containerClassName = \_extractVariable(sourceFile, "containerClassName")

  // Format the code.
  let code = sourceFile.getText()
  code = code.replaceAll(\`@/registry/${style}/\`, "@/components/")
  code = code.replaceAll("export default", "export")

  return {
    description,
    code,
    container: {
      height: iframeHeight,
      className: containerClassName,
    },
  }
}
```

In part 3, I will explain how createTempSourceFile, createSourceFile and _extractVariable work in order to understand_ getBlockCode completely. Keep in mind, we still need to get back to getBlock since this is used in BlockDisplay . Did you notice the chain of function calls here? functions following single responsibility principle and self explanatory and modular.

Conclusion
----------

In part 2, I discuss the BlockDisplay component. This component has functions that are chained together so well that it respects the SRP and is quite module.

I will highlight the key function in this chain. It goes like this:

BlockDisplay => getBlock => \_getBlockContent => readFile

readFile is where you will find the code that reads the source code available at _registry_/ that loads the “blocks” and is rendered via an iframe. Jesus! I wasn’t expecting magic of this sort.

So far, this only completes _getBlockContent explanation, I still need to get back to_ getBlock _and BlockDisplay which has its own complex functions such as_ createTempSourceFile_,_ createSourceFile _and_ extractVariable. I have 0 clue as how they work, but I will make a good attempt to understand and explain them in an easy way in the next article.

> _Want to learn how to build shadcn-ui/ui from scratch? Check out_ [_build-from-scratch_](https://tthroo.com/)

About me:
---------

Website: [https://ramunarasinga.com/](https://ramunarasinga.com/)

Linkedin: [https://www.linkedin.com/in/ramu-narasinga-189361128/](https://www.linkedin.com/in/ramu-narasinga-189361128/)

Github: [https://github.com/Ramu-Narasinga](https://github.com/Ramu-Narasinga)

Email: [ramu.narasinga@gmail.com](mailto:ramu.narasinga@gmail.com)

References:
-----------

1.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/components/block-display.tsx#L5](https://github.com/shadcn-ui/ui/blob/main/apps/www/components/block-display.tsx#L5)
2.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L27](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L27)