103 个工具只用了 2 个布局组件:UtlKit 架构设计
📚 本文是 UtlKit 技术系列第 2 篇 — 系列索引 →
- 上一篇:故事与选型 →
- 下一篇:Hydration Mismatch →
103 个工具,但不需要 103 套 UI。好的架构设计让开发效率翻倍。
整体架构
项目整体架构图
目录结构
src/
├── app/
│ ├── layout.tsx # 根布局:Sentry、字体、主题
│ ├── page.tsx # 首页:分类标签 + 工具网格
│ ├── page.client.tsx # 首页客户端逻辑
│ ├── tools/
│ │ ├── json-formatter/
│ │ │ ├── page.tsx # 页面 + SEO metadata
│ │ │ └── formatter.tsx # 工具核心逻辑
│ │ ├── hash-generator/
│ │ ├── base64/
│ │ └── ... (共 103 个)
│ ├── about/page.tsx
│ ├── contact/page.tsx
│ ├── privacy/page.tsx
│ └── terms/page.tsx
├── components/
│ ├── ConverterLayout.tsx # 转换类工具共享布局
│ ├── ToolSection.tsx # 计算器类工具共享布局
│ ├── Header.tsx # 顶栏:导航 + 搜索 + 语言 + 主题
│ ├── Footer.tsx
│ ├── Breadcrumbs.tsx
│ ├── ThemeProvider.tsx
│ └── AdSlot.tsx
├── lib/
│ ├── tools.ts # 工具元数据(103 个工具的 name/icon/category)
│ ├── i18n/
│ │ ├── en.ts # 英文翻译 ~2200 行
│ │ └── zh-CN.ts # 中文翻译 ~2200 行
│ ├── md5.ts # 纯 JS MD5 实现
│ ├── sentry-release.ts
│ └── tool-seo.ts
└── styles/
└── globals.css # Tailwind + CSS 自定义属性
组件抽象:80% 的工具共享布局
103 个工具抽象为两类核心布局:
1. ConverterLayout — 输入→处理→输出型
JSON 格式化、Base64、Hash 等工具都用这个布局:
┌─────────────────────────────────┐
│ 输入区 │ 输出区 │
│ textarea │ textarea │
│ │ │
│ [转换按钮] │ [复制按钮] │
└─────────────────────────────────┘
2. ToolSection — 表单→计算→结果型
BMI、复利、贷款等计算器类工具:
┌────────────────────────┐
│ [输入项1] │
│ [输入项2] │
│ [输入项3] │
│ │
│ [计算按钮] │
│ │
│ ─── 结果 ─── │
│ 结果展示区 │
└────────────────────────┘
通过这两个共享布局 + 少量自定义逻辑,103 个工具的开发效率大幅提高。每个工具只需要写核心转换逻辑,UI 统一由布局组件处理。
浏览器内运行的取舍
最大的取舍:不能用 Node.js 生态
Node.js 有成熟的格式化/压缩库,但浏览器里没有 fs、net、child_process。
| 想要的库 | 依赖 Node.js | 替代方案 |
|---|---|---|
terser (JS 压缩) | ✅ fs | 自写正则压缩 |
html-minifier-terser | ✅ fs | 自写正则压缩 |
xml-formatter minify | ⚠️ ESM/CJS | 自写正则压缩 |
js-beautify (格式化) | ❌ 支持浏览器 | ✅ 直接用 |
csso (CSS 压缩) | ❌ 纯 JS | ✅ 直接用 |
结论:格式化用现成库,压缩用自写正则。
详细分析见系列第 5 篇 → Node.js 库在浏览器里跑不了的教训
加密:Web Crypto API 的限制
浏览器原生支持 SHA-256/384/512、AES-GCM、HMAC,但不支持 MD5。
MD5 已经被证明不安全,但实际使用场景仍然大量存在(文件校验、旧系统兼容等)。
解决方案:自己实现 MD5(约 100 行纯 JS,bitwise operations)。
详细分析见系列第 7 篇 → Web Crypto API 实现浏览器端加密
i18n:中英文双语的设计
src/lib/i18n/
├── en.ts (2208 行)
└── zh-CN.ts (2207 行)
使用方式:
const { t } = useI18n()
<button>{t('btn.copy')}</button> // "Copy" / "复制"
关键设计决策:
- 不用
next-intl— 静态导出模式下 SSR 安全有问题 - 用
localStorage+ Context — 简单、可控 - 所有页面 title 双语 — SEO 对中英文都友好
- 工具 name 也有双语 — 搜索、面包屑、sitemap
从 0 到 1 到 100
这两篇文章覆盖了"从 0 到 1"的设计和选型。后续文章记录的是"从 1 到 100"过程中踩的坑:
| 篇目 | 标题 | 核心问题 |
|---|---|---|
| 1 | React 19 静态导出报 Hydration Mismatch | SSR/CSR 不一致 |
| 2 | Cloudflare Pages 白页:index.txt 的坑 | content negotiation 机制 |
| 3 | Node.js 库在浏览器跑不了 | fs 依赖、ESM/CJS 互操作 |
| 4 | Sentry Source Map 从 0% 到完整解析 | tree-shake、HTTP API、区域检测 |
| 5 | Web Crypto API 做客户端加密 | MD5 缺失、AES-GCM、HMAC |
| 6 | 免费性能监控:PageSpeed CI | 0 成本持续监控 Core Web Vitals |
| 7 | Cloudflare 缓存命中率 7%→90% | 3 条 Cache Rules + 本地化优化 |
| 8 | 暗色模式完美切换 | 三层优先级策略 |
| 9 | 多语言站点的 6 个坑 | [locale] 路径前缀方案 |
📚 本文是 UtlKit 技术系列第 2 篇 — 系列索引 →
- 上一篇:故事与选型 →
- 下一篇:Hydration Mismatch →
项目信息
- 网站: utlkit.com
- 技术栈: Next.js 15 + React 18 + TypeScript + Tailwind CSS
- 部署: Cloudflare Pages
- 工具数: 103 个,8 个分类
- 成本: ¥0/月
如果觉得有帮助,欢迎关注系列更新。有建设性意见欢迎评论。