150+ Tools with Only 2 Layout Components: UtlKit Architecture Design
UtlKit Series Part 2/2: Architecture and Trade-offs
Part 1 covers the story and tech choices → Read Part 1
150+ tools, but only 2 core layouts. Good architecture doubles development speed.
Overall Architecture
Directory Structure
src/
├── app/
│ ├── layout.tsx # Root layout: Sentry, fonts, theme
│ ├── page.tsx # Homepage: category tabs + tool grid
│ ├── page.client.tsx # Homepage client-side logic
│ ├── tools/
│ │ ├── json-formatter/
│ │ │ ├── page.tsx # Page + SEO metadata
│ │ │ └── formatter.tsx # Tool core logic
│ │ ├── hash-generator/
│ │ ├── base64/
│ │ └── ... (150+ tools total)
│ ├── about/page.tsx
│ ├── contact/page.tsx
│ ├── privacy/page.tsx
│ └── terms/page.tsx
├── components/
│ ├── ConverterLayout.tsx # Shared layout for converter tools
│ ├── ToolSection.tsx # Shared layout for calculator tools
│ ├── Header.tsx # Nav + search + language + theme toggle
│ ├── Footer.tsx
│ ├── Breadcrumbs.tsx
│ ├── ThemeProvider.tsx
│ └── AdSlot.tsx
├── lib/
│ ├── tools.ts # Tool metadata (150+ tools: name/icon/category)
│ ├── i18n/
│ │ ├── en.ts # English ~2200 lines
│ │ └── zh-CN.ts # Chinese ~2200 lines
│ ├── md5.ts # Pure JS MD5 implementation
│ ├── sentry-release.ts
│ └── tool-seo.ts
└── styles/
└── globals.css # Tailwind + CSS custom properties
Component Abstraction: 80% of Tools Share Layouts
150+ tools distilled into two core layouts:
1. ConverterLayout — Input → Process → Output
JSON formatter, Base64, Hash, and similar tools all use this:
┌─────────────────────────────────┐
│ Input │ Output │
│ textarea │ textarea │
│ │ │
│ [Convert] │ [Copy] │
└─────────────────────────────────┘
2. ToolSection — Form → Calculate → Result
BMI, Compound Interest, Loan calculator and similar:
┌────────────────────────┐
│ [Input 1] │
│ [Input 2] │
│ [Input 3] │
│ │
│ [Calculate] │
│ │
│ ─── Result ─── │
│ Result display area │
└────────────────────────┘
These two shared layouts + minimal custom logic per tool dramatically improved development efficiency. Each tool only needs to implement its core conversion logic — the UI is handled uniformly by the layout components.
Browser-Only Trade-offs
The Biggest Trade-off: No Node.js Ecosystem
Node.js has mature formatting/minification libraries, but the browser doesn't have fs, net, or child_process.
| Library | Node.js Dependency | Alternative |
|---|---|---|
terser (JS minification) |
✅ fs
|
Custom regex minifier |
html-minifier-terser |
✅ fs
|
Custom regex minifier |
xml-formatter minify |
⚠️ ESM/CJS issues | Custom regex minifier |
js-beautify (formatting) |
❌ Browser-compatible | ✅ Use directly |
csso (CSS minification) |
❌ Pure JS | ✅ Use directly |
Conclusion: Use existing libraries for formatting, write custom regex for minification.
Full analysis in Part 3 → Why Node.js Libraries Don't Work in the Browser
Encryption: Web Crypto API Limitations
The browser natively supports SHA-256/384/512, AES-GCM, and HMAC — but not MD5.
MD5 is proven insecure, but it's still widely used in practice (file checksums, legacy system compatibility, etc.).
Solution: Implement MD5 yourself (~100 lines of pure JS, bitwise operations).
Full analysis in Part 5 → Client-Side Encryption with Web Crypto API
i18n: Bilingual Design
src/lib/i18n/
├── en.ts (2208 lines)
└── zh-CN.ts (2207 lines)
Usage:
const { t } = useI18n()
<button>{t('btn.copy')}</button> // "Copy" / "复制"
Key decisions:
-
Not using
next-intl— SSR safety issues in static export mode -
localStorage+ Context — Simple and controllable - All page titles bilingual — SEO-friendly for both languages
- Tool names also bilingual — Search, breadcrumbs, sitemap
From 0 to 1 to 100
These two articles cover the "0 to 1" — design decisions and architecture. The following articles cover the "1 to 100" — real-world pitfalls:
| Part | Title | Core Problem |
|---|---|---|
| 1 | React 19 Hydration Mismatch in Static Export | SSR/CSR inconsistency |
| 2 | Cloudflare Pages Blank Page: the index.txt Bug | Content negotiation mechanism |
| 3 | Why Node.js Libraries Fail in the Browser |
fs dependencies, ESM/CJS interop |
| 4 | Sentry Source Maps: From 0% to Full Resolution | Tree-shaking, HTTP API, region detection |
| 5 | Client-Side Encryption with Web Crypto API | MD5 gap, AES-GCM, HMAC |
| 6 | Free Performance Monitoring: PageSpeed CI | Zero-cost Core Web Vitals monitoring |
| 7 | Cloudflare Cache Hit Rate: 7% → 90% | 3 Cache Rules + localization optimization |
| 8 | Perfect Dark Mode: From Hydration Error to Zero Flicker | Troubleshooting 8 pitfalls |
| 9 | 6 Pitfalls of Multilingual Sites | query string → path prefix, 3 rounds of redesign |
Project Info
- Website: utlkit.com
- Stack: Next.js 15 + React 18 + TypeScript + Tailwind CSS
- Hosting: Cloudflare Pages
- Tools: 150+ tools, 8 categories
- Cost: $0/month
If you find this helpful, follow along for the rest of the series. Constructive feedback welcome in the comments.

Top comments (0)