我如何构建 Wikibeem:将 ClickUp Docs 转换为专业文档站点
Source: Dev.to
请提供您希望翻译的正文内容,我将把它翻译成简体中文并保留原有的格式、Markdown 语法以及技术术语。
从挫折到产品发布的独立开发者之旅
我爱 ClickUp。它是我们团队的工作中心——任务、文档、维基,一切都相互关联。
但每次需要把文档分享给客户时,我都会碰到同样的障碍:
https://doc.clickup.com/d/2kxuepwx-192
那丑陋、带品牌、显得不专业的 URL。客户会问:“我们为什么要用 ClickUp?能不能放到你们的网站上?”
我花了好几个小时:
- 导出为 PDF(格式会乱)
- 复制粘贴到 Notion(链接会失效)
- 在 GitBook 里重新搭建(上下文丢失)
像 Cloakist 之类的变通办法只能代理 ClickUp 页面,客户仍然可以随意点击并看到内部内容。
常见问题
我在 Reddit、ClickUp 论坛和反馈板上搜索,结果发现我并不孤单:
- “与潜在客户共享 doc.clickup.com。他们以为我们内部使用 ClickUp,于是退出了。” — r/clickup
- “想要分享入职章节。却无法在不暴露整个任务路线图的情况下进行。” — feedback.clickup.com
- “文档导出会破坏嵌入,项目符号消失。重新在 Notion 中创建需要 4 小时的工作。” — Agency PM on Reddit
数百人都有同样的挫败感:机构、SaaS 团队、自由职业者——都被同样的问题卡住了。
介绍 Wikibeem
有一天晚上,我想:如果我能为自己解决这个问题 并且 为他们解决呢? 这就是 Wikibeem 诞生的原因。
技术栈
| 组件 | 技术 |
|---|---|
| 前端 / 服务器 | Next.js 16(App Router),React 19,Tailwind CSS 4 |
| 数据层 | PostgreSQL + Prisma ORM |
| 托管 | Vercel(edge functions) |
| 认证 | NextAuth v5(beta)– 凭证 + OAuth |
| 支付 | Paddle(处理全球税务) |
| ClickUp 集成 | ClickUp API v3(OAuth 2.0) |
| HTTP 客户端 | Axios |
| 同步引擎 | 用于嵌套页面、维基、文档层级的自定义逻辑 |
| Markdown ↔ HTML | Marked、Cheerio、Turndown |
| 搜索 | Fuse.js(客户端模糊搜索) |
| SEO | 按站点和按文档的 SEO,自动生成站点地图 |
| 域名 | Vercel SDK(编程式自定义域名设置,自动 SSL) |
| 国际化 | next‑intl(9 种语言:EN、FR、DE、ES、PT、IT、RU、AR、ZH) |
Wikibeem 的工作原理(内部实现)
┌─────────────────┐ OAuth ┌─────────────────┐
│ ClickUp API │◄──────────────►│ Wikibeem │
│ (Your Docs) │ │ (Next.js) │
└─────────────────┘ └────────┬────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌─────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ PostgreSQL │ │ Vercel │ │ Paddle │
│ (Prisma) │ │ (Domains) │ │ (Payments) │
└───────────┘ └─────────────┘ └─────────────┘
数据模型
User
└── Workspace (ClickUp connection)
└── Site (your docs website)
├── Documents (synced from ClickUp)
│ └── Children (nested pages)
├── Domain (custom domain)
├── Theme (colors, logo)
└── SEO Settings
同步引擎细节
ClickUp 的 API 返回的文档可能包含:
- 嵌套页面
- 具有自身结构的 Wiki
- 多种格式的内容(JSON 块、Markdown、HTML)
引擎必须:
- 从工作区获取所有文档。
- 递归处理页面及其子页面。
- 将内容转换为干净的 HTML。
- 构建父子关系的层级结构。
- 为 URL 生成唯一的 slug。
- 处理更新而不产生重复。
处理根文档重复
// The fix: Track root doc IDs and filter them out
const rootDocIds = new Set(docs.map(d => d.id))
// When processing pages, skip if it's actually a root doc
if (rootDocIds.has(page.id)) {
continue // This page is a doc, not a child page
}
优化 slug 检查
首个版本对每个 slug 都查询数据库,导致 100 页产生 100+ 次往返。
// In‑memory slug tracking
const existingSlugs = new Set()
// Instead of: await prisma.document.findUnique(...)
// Now:
if (existingSlugs.has(slug)) {
// generate a new slug
}
existingSlugs.add(newSlug) // Track immediately
同步时间从 30 + 秒 降至 10 秒 以下。
程序化域名配置(Vercel SDK)
import { Vercel } from '@vercel/sdk'
const vercel = new Vercel({ accessToken: process.env.VERCEL_TOKEN })
// Add domain
await vercel.projects.addProjectDomain({
idOrName: projectId,
requestBody: { name: 'docs.yourcompany.com' }
})
// Get verification records
const config = await vercel.domains.getDomainConfig({
domain: 'docs.yourcompany.com'
})
用户添加 CNAME 记录,点击 “Verify”,文档会自动在其自定义域名上通过 HTTPS 上线。
未来路线图(进行中的功能)
- 通过 ClickUp Webhook 实时同步
- 分析 – 查看用户阅读了哪些文档
- 密码保护文档 – 用于私密客户门户
- 更多主题
- API 访问 – 为高级用户提供
开始使用
Wikibeem 已上线于 wikibeem.com。
- 连接您的 ClickUp 工作区。
- 同步您的文档。
- 添加您的自定义域名。
不到 5 分钟即可拥有专业的文档站点。
反馈
我正在公开构建此项目,真诚地希望得到你的反馈。哪些功能会让它对你有用?还有哪些缺失?
通过 Twitter/X 或 LinkedIn 与我联系。让我们一起构建它。