首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >零后端、零数据库——我做了一个让 10000+ 人成功告白的开源工具

零后端、零数据库——我做了一个让 10000+ 人成功告白的开源工具

作者头像
舒一笑不秃头
发布2026-05-11 14:55:39
发布2026-05-11 14:55:39
1230
举报

前言

你有没有想过:为什么表达一句"我喜欢你",需要注册账号、上传数据、忍受广告、担心隐私泄露?

我是舒一笑不秃头,一个相信"技术应该让人更自由"的开发者,更多精彩内容~。

这个工具叫 xin2u(心意给你)。它只做一件事——让你用一条链接,把一封精心设计的告白信送到 TA 面前。没有后端,没有数据库,没有注册登录,你的情话只存在于那条 URL 里


一、痛点:现有告白工具的三宗罪

痛点

典型表现

🔒 隐私焦虑

你的告白内容存在别人的服务器上,谁知道会不会被"脱裤"

💸 付费墙

免费模板丑到哭,好看的要 ¥9.9 解锁

🐌 体验臃肿

加载 5 秒、弹窗 3 个、广告满屏

xin2u 的回答:全部数据压缩进 URL,纯前端渲染,免费,Lighthouse 性能分 95+。


二、架构深度:一条 URL 如何承载一封情书

核心思路

代码语言:javascript
复制
用户输入 → JSON → lz-string 压缩 → URL 安全编码 → 拼接到链接

整个数据流不经过任何服务器。收到链接的人打开页面,前端从 URL 参数中解压还原数据,直接渲染。

关键代码(shortLink.ts)

代码语言:javascript
复制
import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string';
import { nanoid } from 'nanoid';

export interface ConfessionPayload {
  toName: string;
  fromName: string;
  message: string;
  photo: string | null;
  templateId: string;
  festivalId?: string;
}

// 压缩:比 btoa 短 30-40%
export function encodePayload(payload: ConfessionPayload): string {
  return compressToEncodedURIComponent(JSON.stringify(payload));
}

// 解压:兼容新旧格式
export function decodePayload(encoded: string): ConfessionPayload | null {
  try {
    const decompressed = decompressFromEncodedURIComponent(encoded);
    if (decompressed) return JSON.parse(decompressed);
  } catch { /* fallthrough */ }
  // 旧格式兼容
  try {
    return JSON.parse(decodeURIComponent(atob(encoded)));
  } catch { return null; }
}

// 语义化短 ID:heart-ab12cd34
export function generateShortId(templateId: string): string {
  const PREFIX: Record<string, string> = {
    heartbeat: 'heart', 'falling-stars': 'stars',
    'rose-garden': 'rose', sakura: 'sakura', /* ... */
  };
  return `${PREFIX[templateId] || 'love'}-${nanoid(8).toLowerCase()}`;
}

为什么选 lz-string?

  • • 原生支持 URI 安全编码,无需二次 escape
  • • 对中文文本压缩率极高(告白信大量中文 → 压缩后 URL 长度可控)
  • • 零依赖、体积仅 5KB gzip

技术栈一览

层级

选型

理由

框架

React 18 + TypeScript

类型安全 + 生态成熟

构建

Vite 5

秒级 HMR,生产构建极快

状态

Zustand + persist

极简 API,自动 localStorage 持久化

样式

Tailwind CSS

原子化 CSS,零运行时开销

动画

GSAP

60fps 流畅动画,告白场景的灵魂

国际化

i18next

7 种语言,覆盖中日韩英法德西

部署

Cloudflare Pages

全球 CDN,免费额度够用


三、极简体验:10 个模板,3 步完成

代码语言:javascript
复制
选模板 → 填内容 → 生成链接 → 发给 TA

10 个精心设计的模板,覆盖不同情感场景:

模板

场景

视觉风格

💌 心跳信笺

经典告白

暖粉渐变 + 心跳动画

🌌 星辰坠落

浪漫夜空

深紫星空 + 流星粒子

🌹 玫瑰花园

热烈表白

玫瑰红 + 花瓣飘落

🎈 爱的气球

轻松甜蜜

天空蓝 + 气球上升

📸 拍立得

记忆定格

暖黄复古 + 照片框

🌿 萤火之森

含蓄深情

暗绿 + 萤火虫

🌊 海边日落

浪漫约定

金橙渐变 + 海浪

🕯️ 烛光晚餐

温馨氛围

暖橙暗调 + 烛光摇曳

❄️ 初雪

纯净心意

冰蓝渐变 + 雪花飘落

🌸 樱花季

日式浪漫

樱粉 + 花瓣雨

更硬核的是:8 个模板复用同一个 BaseLetter 组件 + Theme 配置,新增模板只需写一个 theme 对象:

代码语言:javascript
复制
// themes.tsx 中的一个主题定义(极简)
export const LETTER_THEMES = {
  sakura: {
    bg: 'from-sakura-100 via-sakura-200 to-sakura-400',
    particle: '🌸',
    particleCount: 30,
    textColor: 'text-gray-800',
    // ...
  },
};

四、节日系统:15 个节日 × 7 个国家

不只是告白。生日、母亲节、圣诞节、七夕、520……每个节日都有预设祝福语和推荐模板组合。

代码语言:javascript
复制
// 数据驱动,零硬编码
export const FESTIVALS = {
  'valentines-day': {
    emoji: '💝', mood: 'romantic',
    wishForms: ['love-letter', 'rose-garden', 'love-balloons', 'candle', 'starry-night'],
  },
  // ... 15 个节日
};

export const COUNTRIES = [
  { code: 'CN', flag: '🇨🇳', language: 'zh', festivals: [...] },
  { code: 'JP', flag: '🇯🇵', language: 'ja', festivals: [...] },
  // ... 7 个国家
];

五、超级个体思考

为什么要做这个?

我不想再看到有人为了发一句"我喜欢你",要把自己的隐私交给一个不知名的小程序。

技术的浪漫,不在于复杂,而在于克制。

  • • 不需要后端 → 因为你的情话不该存在别人的硬盘上
  • • 不需要注册 → 因为表达爱意不该有门槛
  • • 不需要付费 → 因为告白本身就是一种勇气

独立开发者的取舍

我选择了

我放弃了

原因

URL 存储

数据库

隐私第一

纯前端

后端 API

零运维成本

Cloudflare Pages

自建服务器

免费 + 全球加速

10 个精品模板

100 个平庸模板

质量 > 数量


六、地址 & 体验

  • • 🔗 在线体验:xin2u.com

结语

最好的代码,是让人感受不到代码存在的代码。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 舒一笑的架构笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、痛点:现有告白工具的三宗罪
  • 二、架构深度:一条 URL 如何承载一封情书
    • 核心思路
    • 关键代码(shortLink.ts)
    • 技术栈一览
  • 三、极简体验:10 个模板,3 步完成
  • 四、节日系统:15 个节日 × 7 个国家
  • 五、超级个体思考
    • 为什么要做这个?
    • 独立开发者的取舍
  • 六、地址 & 体验
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档