Refactoring the Design System for a Monorepo architecture

Henrique Ramos

Challenges of Current Architecture

  • Code duplication across projects
  • Difficulties in maintaining consistent design standards
  • Slow build times due to large codebase
  • Bloated dependencies on Web
  • TypeScript and Linting errors on Platform-specific codes

Examples

  • Multiple config files on root
  •         
    src/
      ---mobile
      ---shared
      ---tokens
      ---web
    jest.config.js
    jest.config.web.js
    jest.setup.js
    jest.setup.web.js
            
          
  • Convoluted build commands:
  •           
    "copy-assets": "cp -r src-ts/shared/assets src/shared/",
    "copy-styles": "find src-ts -name '*.css' -exec sh -c 'mkdir -p src/$(dirname |cut -c8-) && cp  src/$(dirname |cut -c8-)/' \\;",
    "build": "tsc --project tsconfig.json && npx tsc-alias -p tsconfig.json && mv src src-ts && mv dist src && npm run copy-assets && npm run copy-styles",
              
            

What is a Monorepo?

  • Multiple projects, a single Git repository
  • Simplified code sharing
  • Easier per-project tooling setup

Architecture

  • @jitb/design-core for platform-agnostic code and assets
  • @jitb/design-web for web and @jitb/design-mobile for mobile-specific code
  • @jitb/storybook for Storybook codeviews

Folder structure

      
design-system
  ├── package.json
  ├── tsconfig.base.json
  ├── storybook
  │   ├── .storybook
  │   ├── stories
  │   ├── storybook-static
  │   ├── CHANGELOG.md
  │   ├── env.d.ts
  │   ├── eslint.config.mjs
  │   └── tsconfig.json
  packages
    ├── core
    │    ├── assets
    │    ├── src
    │    ├── eslint.config.mjs
    │    ├── package.json
    │    ├── rollup.config.js
    │    ├── setupTests.ts
    │    ├── tsconfig.build.json
    │    ├── tsconfig.json
    │    └── vitest.config.mts
    ├── mobile
    │    ├── __mocks__
    │    ├── src
    │    ├── babel.config.cjs
    │    ├── eslint.config.mjs
    │    ├── jest.setup.js
    │    ├── package.json
    │    ├── rollup.config.js
    │    └── tsconfig.json
    └── web
        ├── src
        ├── eslint.config.mjs
        ├── package.json
        ├── rollup.config.js
        ├── setupTests.ts
        ├── tsconfig.json
        └── vitest.config.mts
        
      

Technologies used

  • TypeScript
  • PNPM Workspaces
  • Nx
  • Rollup

What changed?

  • Replace macos.m1.medium executor by docker.large, using 8x less credits/min 150 - 20
  • Reduced web bundle size from 3.78MB to 2.2MB
  • Script caching, reducing CI times by 30%
  • Improved DX with per-project setups
  • Script orchestration by NX
pnpm test:watch:ui
pnpm nx graph

Thank you :D