Welcome to the second chapter of my 10-Part Series — Building a Design System Agnostic UI Library 🚀.
In this chapter, we’ll dive into the architectural choices, tools, and challenges that shaped Cloak UI’s foundation.
Chapter 2 - Topics
- Why Architecture Matters 🏗️
- Different Frontend Architectures 🔎
- Multi-Repo vs Monorepo ⚖️
- Why Turborepo 🚀
- The Challenges I Faced 🛠️
- What’s Next 🔮
1. Why Architecture Matters 🏗️
When building Cloak UI, the challenge wasn’t just creating abstraction layers for buttons, inputs, or modals — it was designing a foundation that could actually support multiple design systems without turning into a tangled mess of code. 🧩
Architecture matters because it decides:
Flexibility 🔄 → can developers switch from one design system (like shad/cn) to another (like Radix or Hero UI) without rewriting everything?
Scalability 📈 → will adding new adapters or features break existing ones, or can the system grow naturally?
Collaboration 🤝 → can contributors easily understand the structure and extend it, or will they get lost in spaghetti code? 🍝
👉 For Cloak UI, the architecture isn’t just a behind-the-scenes decision — it’s the reason the project can actually deliver on its promise: helping teams escape UI vendor lock-in 🔓 while keeping their codebase clean ✨ and future-proof 🚀.
2. Different Frontend Architectures 🔎
Before settling on Cloak UI’s structure, I explored the common frontend architectures to see what really fits a design-system-agnostic UI library:
Monolithic Architecture 🏰 → Everything in one giant codebase. Great for quick MVPs, but scaling an open-source library this way is a maintenance nightmare.
Modular Architecture 🧩 → Breaks the project into smaller modules. Better than monoliths, but still doesn’t provide the separation needed when you’re supporting multiple adapters and utilities.
Component-Based Architecture ⚛️ → The DNA of modern frontend (React, Vue, etc.). Since Cloak UI’s entire premise is wrapping and adapting components, this naturally fits.
Microfrontends 🏗️ → Awesome for enterprise-scale apps with independent teams, but overkill for an open-source UI library.
👉 My takeaway: Cloak UI needed a component-first architecture ⚛️, but not in isolation — it had to be modular enough 🧩 so that tokens, utilities, adapters, and components could all evolve independently, without stepping on each other. This balance ⚖️ between component-driven design and modular organization became the foundation for Cloak UI. 🚀
3. Multi-Repo vs Monorepo ⚖️
One of the first architectural calls I had to make was where Cloak UI should live — should each package have its own repo, or should everything sit under a single roof? 🤔
Multi-Repo Approach 📦 → At first, it sounds clean:
cloak-core
,cloak-tokens
,cloak-components
, each in its own repo. But in practice, it’s chaos 😵. Shared configs have to be copy-pasted, tests don’t run across repos, and versioning becomes a constant headache. Maintaining five separate repos quickly feels like maintaining five separate projects. 🧨Monorepo Approach 🏠 → Instead, everything lives in one repo. Tooling, configs, and types are shared. Contributors get the full picture in one place 👀, and CI/CD pipelines become simpler. ⚡
👉 For Cloak UI, the monorepo choice was obvious ✅. This isn’t just about convenience — it’s about creating a single source of truth 📖 where contributors, maintainers, and even future adapters can work together without friction. 🤝
4. Why Turborepo 🚀
After choosing a monorepo, the next step was figuring out how to manage it. There are a few popular options ⚙️:
npm/yarn workspaces 📦 → Great for small setups. But Cloak UI needed more than just package linking — features like build caching and pipelines were missing ❌.
Nx 🚀 → Extremely powerful, but also heavy 🏋️. For Cloak UI, which aims to stay lean and approachable for contributors, it felt like using a rocket to light a candle. 🕯️
Turborepo ⚡ → The sweet spot ✅. Lightweight, but packed with the features I actually needed — build caching, task pipelines, and smooth CI/CD integration.
👉 With Turborepo, builds became much faster ⏩, contributors could test just the component they were working 🔍 on instead of rebuilding everything, and the workflow stayed simple enough for anyone to jump in 🙌. For an open-source project like Cloak UI, that balance of simplicity + performance was exactly what I wanted. 🎯
5. The Challenges I Faced 🛠️
Of course, choosing a monorepo didn’t mean everything was smooth sailing ⛵. Setting it up for Cloak UI came with its own set of headaches 😅:
TSConfig Paths 🛣️ → TypeScript didn’t like resolving paths across multiple packages at first. After some trial and error 🧪, I fixed it with a base tsconfig and project references.
ESLint & Prettier 🎨 → Keeping consistent linting/formatting rules across all packages was messy 🌀. I ended up centralizing configs at the root 📂 and using overrides per package.
CI/CD Setup 🔄 → Getting linting, testing, building, and publishing all running cleanly in pipelines was tougher than expected. Turborepo’s caching made builds way faster ⚡, but it still took iteration 🔁.
👉 The biggest lesson? A monorepo isn’t “set it and forget it ❌.” It’s more like a living system 🌱 — you’ll constantly refine and optimize as the project grows.
6. What’s Next 🔮
Now that Cloak UI has a solid architecture in place 🏗️, the next step is setting up the developer experience 💻.
In Chapter 3, I’ll dive into the tools that make working on Cloak UI fun 🎉 and productive ⚡:
- Storybook 📖 for visual previews,
- ESLint & Prettier 🎨 for code quality,
- Commit conventions 📝 for consistency,
- And CI/CD 🔄 workflows for automation.
Stay tuned. Next chapter theme is going to be Mindcraft 🚀
Top comments (0)