shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 3
Tags: javascript, nextjs, shadcnui, opensource
Published: 2024-06-19 20:41:49

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](https://medium.com/@ramu.narasinga_61050/shadcn-ui-ui-codebase-analysis-how-is-blocks-page-built-part-2-7714c8f36a43)
3.  shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 3
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)

![](https://media.licdn.com/dms/image/D4E12AQF7hvMnhLwXSQ/article-inline_image-shrink_1000_1488/0/1718829266346?e=1724284800&v=beta&t=0QHFMU_CJj-DiixaEx_hQqhJNA36M-1ZufsZEAsWCLw)

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 .

\_getBlockCode function code:
-----------------------------
```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 2, we looked at \_getBlockCode in great detail. Let’s understand createTempSourceFile.

createTempSourceFile
--------------------

[createTempSourceFile function](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L102) creates a [unique temporary directory](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L102).

```js
async function createTempSourceFile(filename: string) {
  const dir = await fs.mkdtemp(path.join(tmpdir(), "codex-"))
  return path.join(dir, filename)
}
```

tempdir is imported from “os”, since shadcn-ui/ui uses Next.js, all this code is executed on server, hence it has access to “os” node.js package. [lib/blocks.ts has “use server”](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L1) at the top of file.

Basically, what this code means is that a temporary file with block file name is temporarily placed in a temporary folder.

createSourceFile
----------------

[createSourceFile](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L102) is a function called using project object

```js
const sourceFile = project.createSourceFile(tempFile, raw, {
    scriptKind: ScriptKind.TSX,
})
```

Hang on a minute, what is project object?

```js
const project = new Project({
  compilerOptions: {},
})
```

At the top of the file, this project variable is initiated with a Project instance. Now what is Project? Project is imported from ts-morph? What is ts-morph? Let’s find out.

### ts-morph

[ts-morph](https://ts-morph.com/) is a library that wraps the TypeScript compiler API to simplify setup, navigation and manipulation of the Typescript AST. [This article](https://www.jameslmilner.com/posts/ts-ast-and-ts-morph-intro/) has a good explanation what Typescript AST means.

When the TypeScript compiler compiles your code, it creates an [Abstract Syntax Tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of it. Essentially, an AST can be thought of as a tree representation of the syntax of your source code, with each node being a data structure representing a construct in the relating source code. The tree is complete with nodes of all the elements of the source code.

I definitely need to more research on this ts-morph concept and provide some examples in the [best practices module](https://tthroo.com/) and also talk about this a bit more in part 4.

```js
const sourceFile = project.createSourceFile(tempFile, raw, {
    scriptKind: ScriptKind.TSX,
})
```

[ts-morph.com](http://ts-morph.com) [documentation](https://ts-morph.com/manipulation/performance#performance-tip-work-with-structures-instead) provides an example that uses [project.createSourceFile](https://ts-morph.com/manipulation/performance#performance-tip-work-with-structures-instead), just like how shadcn-ui/ui does it.

We know how tempFile is created, raw is variable containing the file code returning by _getBlockCode, for example, code sitting at_ [_https://github.com/shadcn-ui/ui/blob/main/apps/www/_](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx)[\_registry\_\_/new-york/block/authentication-04.tsx](https://github.com/shadcn-ui/ui/blob/main/apps/www/__registry__/new-york/block/authentication-04.tsx)

I will provide an example project that uses ts-morph and performs the similar operations that shadcn-ui/ui does to understand createSourceFile and extractVariable. getBlock also uses these similar functions in part 4.

Conclusion:
-----------

shadcn-ui/ui performs some additional operations using ts-morph after reading the code from _registry_ folder’s blocks file. Why not just read the file directly? this is an interesing question. I will find out why there is a need to use ts-morph to extract the code further from the read file in part 4.

This is the beauty of reading/studying OSS code, you are exposed to a lot of new technical concepts. I do not know what ts-morph is yet… but I will find out soon and provide an example project after running some experiments. I will keep this example limited to the similar operations used in shadcn-ui/ui.

This part 3 does provide insights into creating a temporary folder using “os” package since lib/block.ts has “use server” at the top of this file.

> _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/lib/blocks.ts#L107](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L107)
2.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L102](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L102)
3.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L16](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L16)
4.  [https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L135](https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L135)