全球7000种语言,AI能翻译的不到200种。而在前端开发领域,一个白板应用通常要加载200万个字符的JavaScript——这相当于把《战争与和平》塞进你的浏览器,只为画几根线。
开发者@joshwcomeau(化名)受够了这种臃肿。他测试的每一款白板工具都要求注册账号、同步云端,或者加载庞大的依赖树。他的需求很简单:打开网页,获得一块空白画布。这个看似基础的功能,在2024年的软件生态中反而成了稀缺品。
于是他做了MindNotes Pro——一个只有3个生产依赖的白板应用:react、react-dom、zustand。没有Redux,没有styled-components,没有axios,没有lodash。整个绘图引擎塞进单个Canvas.tsx文件,约600行代码。
这个技术选择背后是一场关于"足够好"的辩论。Canvas API还是SVG?Zustand还是Redux?外部CDN还是完全打包?每一个决策都在极简主义与功能完整之间寻找平衡点。
正方:Canvas API的硬件加速优势
支持方认为,Canvas API提供了SVG无法匹敌的性能基底。硬件加速的2D绘制能力让应用能流畅处理数千笔笔触,而无需承受DOM操作的开销。SVG虽然在做点击检测时更方便——每个元素都是独立的DOM节点,天然支持事件冒泡——但一旦笔画数量过千,浏览器就开始喘息。
实际测试中,Canvas方案在老旧笔记本上仍能保持60fps的绘制帧率。代价是开发者需要自己实现命中检测算法:计算鼠标坐标与每条贝塞尔曲线的距离,判断用户是否点中了某一笔画。这增加了约200行数学代码,但换来了指数级的性能余量。
反方:Zustand的状态管理争议
批评者指出,Zustand的"无样板代码"承诺存在隐性成本。这个不足1KB的库确实比Redux轻量,但其基于订阅的更新机制在复杂场景下可能引发不可预期的重渲染。MindNotes Pro用3个独立的store切割状态:useDrawingStore负责笔画、形状、工具、撤销重做和localStorage持久化;useViewStore管理缩放与平移;useThemeStore处理深色/浅色模式及系统检测。
这种分割策略有效隔离了变更传播范围。当用户切换画笔颜色时,只有绘图相关的组件需要更新,视图和主题store保持静默。但反对者认为,对于单人维护的项目,这种架构过度设计——一个useReducer配合Context可能更透明。
判断:打包策略的地缘政治考量
最具争议的决策是"零外部CDN"。所有资源——字体、图标、甚至纸张背景的SVG噪点纹理——全部打进bundle。这使最终体积略微膨胀,但确保应用在中国境内无需VPN即可访问。这个设计选择将技术决策与网络基础设施的现实摩擦直接挂钩:当Cloudflare和Google Fonts在某些地区不稳定时,自给自足成为可用性的前提。
视觉设计同样反潮流。开发者摒弃了科技产品惯用的冷蓝/灰色调,采用暖大地色系:#f5f0e8作为背景,#c47a5a作为强调色,配合SVG分形噪点模拟纸张纹理。这种"温暖羊皮纸"美学试图降低数字工具的侵入感——你不是在操作软件,而是在一张无限延伸的纸上书写。
功能集没有因极简而缩水:6种画笔类型(钢笔、荧光笔、铅笔、书法笔、虚线、发光)、9种绘图工具、6种导出格式(PNG、JPG、PDF、SVG、Word、JSON)、50步撤销重做、缩放与迷你地图导航、完整的触控支持。自动保存到localStorage意味着数据完全本地留存,没有账户体系,没有云同步,也没有隐私条款需要同意。
技术栈最终定格为:React 18、TypeScript 5、Vite 5、Zustand、Canvas API、Tailwind CSS。构建工具Vite的按需编译让开发服务器在毫秒级启动,这与应用本身的轻量哲学形成呼应。
这个项目的真正价值或许不在于代码本身,而在于它提出的反问:当行业标准解决方案持续膨胀时,"刚好够用"的边界在哪里?3个依赖不是道德优越,而是一种可量化的约束条件——它强迫开发者区分"需要"与"想要",在功能清单上做减法而非加法。
结果已公开测试。对于厌倦了注册流程、同步冲突和加载动画的用户,600行代码提供的空白画布可能比2MB的"全功能套件"更接近工具的本质。
热门跟贴