V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
devrsi0n
V2EX  ›  分享创造

开源了我独立开发的评论组件 SaaS 🔥 🚀

  devrsi0n ·
devrsi0n · 2022-01-14 12:16:25 +08:00 · 5005 次点击
这是一个创建于 1042 天前的主题,其中的信息可能已经有所发展或是发生改变。

👋 大家好,在独立开发一年后,今天开源了我的 Next.js App - Chirpy, 一个主打保护隐私、支持主题定制的评论组件 SaaS 。

太长不看版 🙈

这是 GitHub Repo, 欢迎点亮 🌟 收藏,欢迎参与贡献。对于初、中级工程师这里有所有你需要知道的一个完整的 SaaS 怎么运作的全部知识,非常适合学习。

官网目前正在 beta 测试,欢迎试用。如果想要数据完全由你控制,Chirp 也支持 docker 部署

预览 👀

评论组件,支持富文本编辑和 markdown shortcuts ( markdown 实时预览,类似 typora 的书写体验)

Untitled

主题定制 🌈(更多定制项开发中)

Untitled

组件使用情况分析面板(Analytics) 📈

Untitled

初心 ❤️

我在构建我自己的博客的时候想要一个类似 Disqus 一样的功能丰富、接入快捷的评论组件,但 Disqus 本身这几年因为不经用户同意就私加广告,出卖用户隐私等问题广为诟病。下面是我检索到的一些报道:

Bloomberg LawDisqus Faces $3 Million Sanction Over Alleged GDPR Breachesfor multiple breaches of EU privacy law.

Disqus facing $3M fine in Norway for tracking users without consent

我也用过 gitalk utterances 之类的基于 GitHub API 的免费评论系统,它们有一个显而易见的问题就是只支持 GitHub 登陆,而且受限 GitHub 本身 API ,很多功能并不好做,比如组件的使用情况分析 / Analytics 。

市面的组件基本都缺乏主题定制能力,放在自己的博客、网站有很大概率因为设计不协调导致的违和感,所以主题定制也是必要的。

基于以上种种问题所以我打算做一个完全开源同时也能解决以上痛点的评论组件系统。

技术选择与演进 🕺

Next.js 🆚 Gatsby

时间倒回到 2020 年,当年 React SSR 框架 Next.js 推出了 SSG( Static Site Generation )和 ISR( Incremental Static Regeneration ), 迅速变得炙手可热,相比 2019 年大热的静态网站生成器 Gatsby 优势明显。(如果放在今天重新选择,remix 也是一个非常好的选择。😄)

Gatsby Next.js
SSR 🔴
SSG
ISR 🔴
BUILD SPEED 🐌 ⚡️
HMR SPEED 🐌 ⚡️

npm 趋势图

Untitled

Next.js 的 ISR(增量静态更新) 特性特别适合评论组件的场景。想象有成千上万个 iframe 评论组件,用 ISR 渲染既有了类似 SSR 的灵活性,也有 CDN 的加速加持(减少并发渲染)。下图是 ISR 示意:

Untitled

一开始 Chirpy 选择了 egoist 的 Next FullStack Starter 作为始点,主要技术栈是:Next.js + Prisma + GraphQL + TypeGraphQL + Tailwindcss。但深入开发过程中发现 ORM Prisma 并不支持 Subscription/real-time API,这是一个对用户体验比较重要的功能,在慎重考虑之后 backend 迁移到了 Hasura

Prisma ➡️ Hasura

严格来说 PrismaHasura 并不算是同一类东西。Hasura 是一个支持高并发的 GraphQL server ,支持用 GraphQL 增删改查数据库(比如 PostgreSQL),同时也提供一套完整的权限控制。Prisma 是一个 ORM ,为了支持 GraphQL 还是需要手写所对应的 resolver 以及相应的权限控制,开发成本较高,但相应的比 Hasura 更加灵活。

Prisma Hasura
语言 TypeScript haskell
Type ORM GraphQL Server
GraphQL API 🟡 手动 ✅ 由数据库 Schema 生成
高并发 🟡 受限于  Node.js 性能和应用架构 ✅  (50M 内存支持 1000 q/sec)( https://hasura.io/blog/fast-graphql-execution-with-query-caching-prepared-statements/)
Subscription 🔴
灵活性 🟡

Hasura 应用的架构

Untitled

passportjs ➡️ next-auth

用户登陆系统(第三方登陆 + 传统账号密码)也有 2 个比较成熟的选择,一开始选择的是 passportjs, 在深入开发中遇到很多 OAuth 和安全相关的问题,最后重构换到了 next-auth 。相比之下 next-auth 更加现代化(提供 React Hooks ,库本身也是用 TypeScript 写的),更安全,Next.js 集成方便。

passportjs next-auth
第三方登陆
邮箱密码登陆
无密码登陆
安全性 🟡
React Hooks 🔴
Next.js 集成 🔴

Tailwindcss & twin.macro & radix-colors

Tailwind 是一个原子化 CSS 开发框架,在熟悉它之后 CSS 开发效率能显著的提升 🚀;同时它提供了一套完备且经得住考验的默认主题配置,以及一套丰富的 SaaS UI 库(不完全免费,但学会 tailwind 之后手写类似的 UI 不会太难,更重要的是这里有常用 SaaS 的 UI 设计可供参考,对我这个设计苦手非常有帮助 🥳)。

实际上 Chirpy 是和 twin.macro 一起用,这是一个结合 tailwind 和 CSS-in-JS ( styled-component & emotion ) 的库,tailwind 早期版本在组件化开发中会遇到样式类不能被 overwrite 的情况, 因为 tailwind 本身输出原子类:

<p className="w-1 h-1">...</p>

// 输出 CSS 👇

.w-1	{
  width: 0.25rem;
}

.h-1	{
  height: 0.25rem;
}

twin.macro 版本, 不需要 CSS !important 就能覆盖样式:

<p tw="w-1 h-1">...</p>

// 输出 html & css 👇

<p class="random-name">...</p>

.random-name	{
  width: 0.25rem;
  height: 0.25rem;
}

twin.macro 也支持 build 的时候校验,不合法的样式会报错(比如w-0.1),可以避免写出无用样式。以及自由组合多个 variants ,例如:sm:(bg-black hover:(bg-white w-10))。当然它也并不完美,tailwind 可以复用已有的 CSS 类,而它每个 tw 几乎都会生成新的样式, 最终输出的 bundle size twin 会更大一点。它也不支持一些 tailwind 的一些官方插件,比如:tailwindcss-typography(用于编辑器)。故两者是结合一起使用。

tailwind 的 Dark mode 主要靠用 dark: variant (如下面的🌰), 几乎每个颜色值都要写两遍,我理想中的 dark mode 是自动的。

<div class="bg-white dark:bg-gray-900">...</div>

因此这里需要 light/dark 2 套颜色,radix-colors 正满足要求。但它要怎么和 tailwind 一起用呢?答案是:CSS Variable

首先配置 tailwind 主题:

module.exports = {
  theme: {
    colors: {
      bg: `var(--tw-colors-bg)`
    },
  },
}

然后给应用注入样式:

:root {
  --tw-colors-bg: white;
}
:root.dark {
  --tw-colors-bg: black;
}

配合 next-themes 自动在用户切换 mode 时切换网站 CSS 类:

// next-themes 在用户切换 mode 时自动切换 .dark 有无
<html class="dark">...</html>

这样就能在应用切换 mode 时自动刷新颜色。

这里也顺便解决了组件的主题定制功能,Chirpy 只需要在组件渲染时注入用户自定义的变量值即可。

Slate ➡️ tiptap

评论组件体验最核心的是富文本编辑器,一开始 Chirpy 用的是 slate,因为它和 React 结合比较好,但开发到后期也遇到一些问题,比如 markdown shortcuts 实现并不顺利,后面迁移到了tiptap,功能更加完善,底层也基于更稳定的 ProseMirror

slate tiptap
基于 React ProseMirror
稳定性 🔴 issue( https://github.com/ianstormtaylor/slate/issues/3150)
Markdown shortcuts 🔴
功能丰富度 🔴

apollo-client ➡️ urql

apollo-client 毫无疑问是最流行的 GraphQL client ,最初选择的便是它。就在准备开源之前不久遇到了 2 个很诡异的 bug (某些状态死活不更新)。搜索相关问题也了解到 apollo 把开源当成一种营销手段,加之我一直很头痛它很大的 bundle size ,随后下定决心迁移到 urql 这个小巧的多的库,事实证明这次重构超值,减少了近 45KB bundle size 。

Untitled

apollo-client urql
bundle size 🟡 33kb ✅ 7.1kb
Next.js 集成 🔴 ✅ next-urql
Document Caching 🔴
Stale while Revalidate

Plausible 📈

一开始 Chirpy 自己实现了一个的数据统计 / Analytics ,但后面发现这里面需要考虑很多东西(聚合数据、性能、图表等),严重拖累了开发进度。最后迁移到了 Plausible,它也是一个主打保护隐私的开源 SaaS 。为了更好地保护用户隐私,Chirpy 用它跑在一个单独的服务器上而不是直接用它的服务。

Chirpy 复用了 Plausible 的前端代码以适配评论组件的场景。同时也把它发数据的脚本直接放到 Chirpy 的 bundle + 重映射发数据的 API 接口,可以很好的解决浏览器广告过滤器过滤掉请求导致数据不准确的问题。因此你可以把 Chirpy 当成一个免费且高精确度的 Analytics 工具来用 😉。

Plausible 的营收也是 Chirpy 努力的目标 💪

Untitled

CI & CD ♻

项目的 CI/CD 主要依靠 GitHub Action 。 开发流程是基于 PR ,每个 PR check-in 之前会跑 Cypress( 端到端测试),jest (单元测试),以及输出 Next.js bundle size 变化(避免无意引入代码造成 bundle size 问题)。

后面会引入 hasura schema CI/CD,减少人肉升级 schema 出问题。

部署 💿

这里分为 Next.js, Hasura 和 Plausible 几部分:

  • Next.js 自然选择部署到开发它的公司 → Vercel 是最佳选择,相比同类服务(比如 netlify)构建性能、图片之类的优化效果更好,部署体验也属一流。
  • Hasura 前置了一个 Caddy HTTP Server 可以自动给 HTTPS 域名签名,同时也为未来支持弹性负载均衡作准备。
  • Plausible 实例单独部署避免影响业务数据,同时也加上了 Caddy HTTP Server 。
  • Hasura 和 Plausible 各自部署到了一个 DigitalOcean 虚拟机,主要看中高性价比,使用方便。

后续支持图片上传考虑使用 Cloudflare Images, 功能齐全,性价比也不错。

远期规划 🛸

评论组件只是我的第一步,在功能逐渐完善之后 Chirpy 也会考虑做类似 intercom 的聊天组件(如下图),hasura + WebSocket 架构天然适合这种轻量聊天应用。Chirpy 目标是打造一套完整的开源用户沟通的解决方案。

Untitled

社区 /community 🏘

作为开源项目,社区是我很看重的一块,鼓励大家参与贡献( issue ,discussion ,PR )。计划有了一定收入也会定期给活跃的开发者发放一定的金钱支持,回馈社区。

非常感谢你看到这里,欢迎到 Chirpy 社区玩耍 🙌。

38 条回复    2022-01-21 21:21:24 +08:00
codespots
    1
codespots  
   2022-01-14 13:52:03 +08:00   ❤️ 2
东西挺好的,但你知道为啥多说之类的现在不存在了吗?所以还是面向海外用户吧
ljinkai
    2
ljinkai  
   2022-01-14 14:37:47 +08:00
好东西,Nuxt.js 的考虑集成下吗
enchilada2020
    3
enchilada2020  
   2022-01-14 16:23:02 +08:00 via Android
厉害 大佬 dddd (带带弟弟
wensonsmith
    4
wensonsmith  
   2022-01-14 16:37:16 +08:00
不错呀
yuyue001
    5
yuyue001  
   2022-01-14 17:04:28 +08:00
star 了
knightdf
    6
knightdf  
   2022-01-14 17:09:43 +08:00
@codespots 因为要你少说 手动狗头
devrsi0n
    7
devrsi0n  
OP
   2022-01-14 18:55:44 +08:00
@codespots 只面向海外用户
devrsi0n
    8
devrsi0n  
OP
   2022-01-14 18:57:34 +08:00
@ljinkai 哈哈,短期内不会吧。2 个框架差别蛮大的,欢迎 fork 玩玩
devrsi0n
    9
devrsi0n  
OP
   2022-01-14 19:01:52 +08:00
@yuyue001 感谢🙏
devrsi0n
    10
devrsi0n  
OP
   2022-01-14 19:05:13 +08:00
@enchilada2020 欢迎参与贡献,免费帮带 😜
Jiki
    11
Jiki  
   2022-01-14 19:06:16 +08:00   ❤️ 4
赏心悦目,无论是 UI 还是技术栈
devrsi0n
    12
devrsi0n  
OP
   2022-01-14 19:09:41 +08:00
@Jiki 感谢,这是我收到最暖心的评论 ❤️
lyhiving
    13
lyhiving  
   2022-01-14 19:25:01 +08:00 via Android
弄成 intercom 的样子才能看到钱
devrsi0n
    14
devrsi0n  
OP
   2022-01-14 19:28:50 +08:00
@lyhiving 不一定哈,你看 Plausible (文章里有介绍) 本身功能不多的,但是靠主打隐私牌一样月收入恐怖,这种模式是有成功先例的
Showfom
    15
Showfom  
   2022-01-14 19:34:38 +08:00
支持一下,就是感觉字体有点大呀

https://chirpy.dev/blog/open-source
devrsi0n
    16
devrsi0n  
OP
   2022-01-14 19:39:50 +08:00
@Showfom 因为 blog 和 docs 主要突出文本本身,不过后面加 TOC 侧边栏的时候会再斟酌下设计,感谢
lyhiving
    17
lyhiving  
   2022-01-15 16:45:28 +08:00 via Android
@devrsi0n 明白,但整体而言单靠一个功能就流行的在目前确实难
devrsi0n
    18
devrsi0n  
OP
   2022-01-15 17:03:12 +08:00
@lyhiving 要说单一的话 Plausible 因为要保护隐私功能可以说极少,而且就 2 个开发者,但一样不影响它赚钱。国外 Facebook 一系列事件下来让保护隐私的 SaaS 就是一个热门领域,况且 Chirpy 也不止这一个特点。产品也是慢慢摸索出来的,我会不断完善 Chirpy
shadeofgod
    19
shadeofgod  
   2022-01-17 12:39:15 +08:00
br_wang
    20
br_wang  
   2022-01-17 16:04:22 +08:00
整体方案和技术栈选择相关的说明好看
devrsi0n
    21
devrsi0n  
OP
   2022-01-17 22:31:52 +08:00
@shadeofgod 哈哈,原作者跟我是同一家公司(开源是我们的副业),在他公布 cusdis 的时候我已经开发了很久了,并且两个产品定位不太相同,大家喜欢哪个就用哪个 😉
devrsi0n
    22
devrsi0n  
OP
   2022-01-17 22:35:52 +08:00   ❤️ 1
@br_wang 把段开发经历分享给大家,能让人有所收获是最让我满足的,感谢分享 🙏
xrr2016
    23
xrr2016  
   2022-01-19 10:29:15 +08:00
棒,大佬牛
scyuns
    24
scyuns  
   2022-01-19 10:42:47 +08:00
感谢分享,可惜我英语不好。希望可以做本土化!祝越来越好
devrsi0n
    25
devrsi0n  
OP
   2022-01-19 10:46:03 +08:00
@scyuns 感谢,多语言支持也在计划之中,欢迎关注。
daolanfler
    26
daolanfler  
   2022-01-19 11:31:18 +08:00
把技术栈的选型都介绍了一遍,学到了多。赞
devrsi0n
    27
devrsi0n  
OP
   2022-01-19 12:47:12 +08:00
marcosteam
    28
marcosteam  
   2022-01-19 13:23:09 +08:00 via Android
你的下一步目标是打算做成 Crisp 之类的客服系统?
Showfom
    29
Showfom  
   2022-01-19 13:57:20 +08:00
突然发现个 typo

https://chirpy.dev/docs/self-hosted

We'll polish this document once we're Generally Available.

polish > publish
zhy0216
    30
zhy0216  
   2022-01-19 14:20:41 +08:00   ❤️ 1
别的不说 技术栈选的真不错
devrsi0n
    31
devrsi0n  
OP
   2022-01-19 16:14:11 +08:00 via iPhone
@marcosteam 👏恭喜你,你已经猜对 chirpy 的计划!只是一个实时聊天 widget 还不足以吸引人,能有一些 ai 智能客服应用场景会广的多。
devrsi0n
    32
devrsi0n  
OP
   2022-01-19 16:16:24 +08:00 via iPhone
@Showfom 不是 typo 哦,意思是我们产品真正发布的时候会更新 self hosted 的文档。毕竟谁也不想 slef hosted 的时候天天更新吧 😆
Showfom
    33
Showfom  
   2022-01-19 16:21:37 +08:00
@devrsi0n #32

polish > publish
slef > self

你这英语。。。
devrsi0n
    34
devrsi0n  
OP
   2022-01-19 17:36:32 +08:00 via iPhone
@Showfom 手机打字打错了,原文我写了,没有问题,建议好好读一下。
devrsi0n
    35
devrsi0n  
OP
   2022-01-19 17:39:24 +08:00 via iPhone
@Showfom 打错字真没啥哈,楼主在外企仍然天天遇到 typo 和语法错误,哈哈
rookiebulls
    36
rookiebulls  
   2022-01-19 18:43:21 +08:00 via iPhone
好奇这种靠什么收益呢
lanxyou
    37
lanxyou  
   2022-01-21 19:42:55 +08:00   ❤️ 1
不管怎么说,这么认真的分享,一定要支持一下
marcosteam
    38
marcosteam  
   2022-01-21 21:21:24 +08:00
@rookiebulls 一般就是提供自托管的服务并收取维护费用吧
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5713 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 58ms · UTC 01:45 · PVG 09:45 · LAX 17:45 · JFK 20:45
Developed with CodeLauncher
♥ Do have faith in what you're doing.