Optimizing React Component Library Build Time
Tags: react, webdev, javascript, githubactions
Published: 2024-06-25 06:14:03

In modern software development, CI/CD (Continuous Integration/Continuous Deployment) pipelines and building reusable components are crucial for maintaining high productivity and rapid deployment cycles. Adopting monorepos has become increasingly popular because they allow for better organization and management of code, particularly in large projects. By housing multiple packages within a single repository, teams can share code more efficiently and maintain consistency across different projects.

However, as monorepos grow, so does the build time. In some cases, build times can become relatively long. This is exactly what happened in our company. We created a monorepo to hold most of our React components and various utility functions. Unfortunately, the build time for this monorepo took about 12 minutes. This long build time hampered productivity and increased costs, especially when builds failed or defects needed fixing, requiring additional time for corrections.


![12 minutes build time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bw7rlmijgov5i51wrg5x.png)




**Caching the Build Using Turbo Repo**

To address this issue, we implemented Turbo Repo. Turbo Repo works by caching previous builds and only rebuilding the parts of the codebase that have changed. This looked promising, as our build time was significantly reduced. By using Turbo Repo, we could optimize our build process and make it more efficient.

**Company Rules and Regulations**

Using Turbo Repo worked well locally, but we faced challenges when integrating it into our CI/CD pipeline using GitHub Actions. According to Turbo Repo's documentation, a repository needs to be connected to Vercel for caching to work properly. However, this posed a problem because connecting to Vercel could potentially expose our code to a third party, which goes against our company's privacy regulations.

To comply with company policies, we found an alternative method: uploading the cache created by Turbo Repo to GitHub Artifact. This way, we could still use the benefits of Turbo Repo without exposing our code.

**How It Works**

Here's how we implemented this method:

- **Pipeline Trigger**: Every time a pipeline is triggered, it uploads the current cache created by Turbo Repo to GitHub Artifact.
- **Downloading Previous Cache**: When a new pipeline is triggered, it downloads the previous cache from GitHub Artifact.
- **Cache Utilization**: Turbo Repo uses the downloaded cache to determine which parts of the codebase need rebuilding, significantly reducing build times.
This method not only ensured that we complied with company regulations but also reduced our build time from 12 minutes to just 3 minutes.

```
name: CI

on:
  pull_request:
    branches:
      - main
      - feature/*
      - feat/*

jobs:
  ci:
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    strategy:
      matrix:
        # run both checks in parallel to speed up the CI
        run: ['pnpm run check-all', 'pnpm run build']

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - uses: pnpm/action-setup@v2
        name: Install pnpm
        id: pnpm-install
        with:
          version: 8
          run_install: false

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm install
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Download Existing Artifact from Target
        uses: dawidd6/action-download-artifact@v2
        continue-on-error: true
        with:
          workflow: prerelease.yml
          branch: ${{github.event.pull_request.base.ref}}
          if_no_artifact_found: ignore

      - name: Check Turbo cache existence
        id: turbo_cache
        uses: andstor/file-existence-action@v2
        with:
          files: ".turbo"

      - name: Download Existing Artifact from last workflow
        if: steps.turbo_cache.outputs.files_exists != 'true'
        uses: dawidd6/action-download-artifact@v2
        continue-on-error: true
        with:
          workflow: prerelease.yml
          if_no_artifact_found: ignore

      - name: ${{ matrix.run }}
        run: ${{ matrix.run }}
        continue-on-error: true

      - name: Upload .turbo
        uses: actions/upload-artifact@v2
        with:
          name: .turbo
          path: .turbo
```

**Conclusion**

By optimizing our build process using Turbo Repo and leveraging GitHub Artifact for caching, we achieved a significant reduction in build times while adhering to company policies. This improvement not only speeds up our development cycle but also boosts overall productivity and efficiency within the team. Developers can now iterate and test changes much faster, leading to quicker deployment of new features and enhancements.


![reduced build time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8xamgc7xdw2j9tw6xa1.png)