<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>RxDB Blog</title>
        <link>https://docs.aiao.io/blog</link>
        <description>RxDB Blog</description>
        <lastBuildDate>Tue, 12 Aug 2025 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[为什么我又重新看好 Local-first 了]]></title>
            <link>https://docs.aiao.io/blog/local-first</link>
            <guid>https://docs.aiao.io/blog/local-first</guid>
            <pubDate>Tue, 12 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[回顾 Local-first 从 PouchDB 时代到今天的变化，以及浏览器数据库能力成熟后前端数据层为什么值得重做。]]></description>
            <content:encoded><![CDATA[<p>Local-first 最近又被频繁提起，但这次和十年前已经不是同一个语境了。</p>
<p>当我初次接触 <a href="https://pouchdb.com/" target="_blank" rel="noopener noreferrer" class="">PouchDB</a> 与 <a href="https://couchdb.apache.org/" target="_blank" rel="noopener noreferrer" class="">CouchDB</a> 时，就意识到这条路线真正想改的不是缓存策略，而是 Web 应用默认把可用性和响应速度都押在网络上的前提。</p>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="pouchdb-当年其实已经把方向指对了">PouchDB 当年其实已经把方向指对了<a href="https://docs.aiao.io/blog/local-first#pouchdb-%E5%BD%93%E5%B9%B4%E5%85%B6%E5%AE%9E%E5%B7%B2%E7%BB%8F%E6%8A%8A%E6%96%B9%E5%90%91%E6%8C%87%E5%AF%B9%E4%BA%86" class="hash-link" aria-label="PouchDB 当年其实已经把方向指对了的直接链接" title="PouchDB 当年其实已经把方向指对了的直接链接" translate="no">​</a></h2>
<p><strong>PouchDB</strong> 让前端开发者第一次比较系统地拥有了在用户设备上存储结构化数据、离线读写、再与远端同步的能力。那时它最打动人的地方，不是某个 API 设计得多漂亮，而是它让人意识到：原来 Web 应用也可以在断网时继续工作，而不是只能原地报错。</p>
<p><strong>CouchDB</strong> 的设计也很有启发性。它把同步、版本和文档模型变成数据库内建能力，而不是全部交给业务系统自己拼。前端和数据库之间的距离被明显拉近了，很多过去必须经过中间层才能完成的事情，第一次有了更直接的实现路径。</p>
<p>但这条路线并没有在当年真正进入主流。PouchDB 生态后来逐渐降温，社区也慢慢沉寂下来。问题不在方向错了，而在当时的浏览器、工具链和团队认知都还没准备好。</p>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="问题不是理念不对而是当时条件不够">问题不是理念不对，而是当时条件不够<a href="https://docs.aiao.io/blog/local-first#%E9%97%AE%E9%A2%98%E4%B8%8D%E6%98%AF%E7%90%86%E5%BF%B5%E4%B8%8D%E5%AF%B9%E8%80%8C%E6%98%AF%E5%BD%93%E6%97%B6%E6%9D%A1%E4%BB%B6%E4%B8%8D%E5%A4%9F" class="hash-link" aria-label="问题不是理念不对，而是当时条件不够的直接链接" title="问题不是理念不对，而是当时条件不够的直接链接" translate="no">​</a></h2>
<p>我现在回头看，至少有三类阻力很现实：</p>
<ol>
<li class=""><strong>工程门槛高</strong>：你不仅要会写前端，还得理解建模、同步、索引、冲突这些原本更像数据库工程的问题。</li>
<li class=""><strong>默认架构惯性太强</strong>：大多数团队早就习惯了“前端调接口，服务端管数据”，要切到“本地先可用”并不只是换个库。</li>
<li class=""><strong>浏览器能力当时不够成熟</strong>：早期存储能力、执行性能和相关 API 远没有今天稳定，复杂数据应用很容易撞墙。</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="现在回头看时机确实不一样了">现在回头看，时机确实不一样了<a href="https://docs.aiao.io/blog/local-first#%E7%8E%B0%E5%9C%A8%E5%9B%9E%E5%A4%B4%E7%9C%8B%E6%97%B6%E6%9C%BA%E7%A1%AE%E5%AE%9E%E4%B8%8D%E4%B8%80%E6%A0%B7%E4%BA%86" class="hash-link" aria-label="现在回头看，时机确实不一样了的直接链接" title="现在回头看，时机确实不一样了的直接链接" translate="no">​</a></h2>
<p>过去几年真正改变局面的，不是一句“离线优先”口号，而是浏览器底层能力终于补上来了。尤其是 WebAssembly 和配套存储能力成熟之后，前端第一次有条件认真讨论“在浏览器里跑数据库”这件事。</p>
<p>几个变化尤其关键：</p>
<ul>
<li class=""><a href="https://github.com/rhashimoto/wa-sqlite" target="_blank" rel="noopener noreferrer" class="">wa-sqlite</a> 把 SQLite 带进浏览器，让本地关系型查询、索引和事务不再只是原生应用的专利。</li>
<li class=""><a href="https://github.com/electric-sql/pglite" target="_blank" rel="noopener noreferrer" class="">PGlite</a> 进一步把 PostgreSQL 风格的能力推进到前端运行时，复杂查询不必一开始就退回服务端。</li>
<li class="">浏览器侧持久化、Worker、WASM 配套工具链也比过去成熟得多，本地数据层终于有了可持续工程化的基础。</li>
</ul>
<p>这意味着 Local-first 不再只能停留在“缓存列表页数据”这种轻量级用法，而开始有机会支撑真正复杂的业务数据场景。</p>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="前端已经不只是调接口然后渲染了">前端已经不只是“调接口然后渲染”了<a href="https://docs.aiao.io/blog/local-first#%E5%89%8D%E7%AB%AF%E5%B7%B2%E7%BB%8F%E4%B8%8D%E5%8F%AA%E6%98%AF%E8%B0%83%E6%8E%A5%E5%8F%A3%E7%84%B6%E5%90%8E%E6%B8%B2%E6%9F%93%E4%BA%86" class="hash-link" aria-label="前端已经不只是“调接口然后渲染”了的直接链接" title="前端已经不只是“调接口然后渲染”了的直接链接" translate="no">​</a></h2>
<p><a href="https://www.figma.com/" target="_blank" rel="noopener noreferrer" class="">Figma</a> 这类产品已经证明，浏览器不是只能负责展示的壳。它完全可以承载复杂状态、实时协作和大量客户端计算。这个变化对前端开发的影响很直接：</p>
<ul>
<li class="">前端不再只是消费 API 的一层界面。</li>
<li class="">复杂业务规则和部分数据处理可以直接在客户端落地。</li>
<li class="">用户体验不必处处受制于网络往返和服务端响应时间。</li>
</ul>
<p>所以我现在更愿意把 Local-first 理解成一种架构选择：把“先可用、先响应、先落地到用户设备”作为默认前提，再去设计同步、协作和远端一致性，而不是反过来。</p>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="这也是我们为什么要做-aiaorxdb">这也是我们为什么要做 @aiao/rxdb<a href="https://docs.aiao.io/blog/local-first#%E8%BF%99%E4%B9%9F%E6%98%AF%E6%88%91%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%81%9A-aiaorxdb" class="hash-link" aria-label="这也是我们为什么要做 @aiao/rxdb的直接链接" title="这也是我们为什么要做 @aiao/rxdb的直接链接" translate="no">​</a></h2>
<p>基于这些思考，我们团队正在打造 <strong>@aiao/rxdb</strong>。它想解决的不是“再包装一个 Local-first 概念”，而是把浏览器内数据层真正做成可复用、可维护、能落在业务里的工程基础设施。</p>
<p>目前我们更关注下面几件事：</p>
<h3 class="anchor anchorTargetStickyNavbar_u3Dh" id="1-先把模型立住">1. 先把模型立住<a href="https://docs.aiao.io/blog/local-first#1-%E5%85%88%E6%8A%8A%E6%A8%A1%E5%9E%8B%E7%AB%8B%E4%BD%8F" class="hash-link" aria-label="1. 先把模型立住的直接链接" title="1. 先把模型立住的直接链接" translate="no">​</a></h3>
<ul>
<li class="">用声明式模型定义实体、字段、关系和约束。</li>
<li class="">让类型、查询能力和生成代码围绕模型展开，而不是散落在页面和服务层里。</li>
<li class="">降低“业务越复杂，数据代码越碎”的问题。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_u3Dh" id="2-再把数据库能力接进熟悉的前端栈">2. 再把数据库能力接进熟悉的前端栈<a href="https://docs.aiao.io/blog/local-first#2-%E5%86%8D%E6%8A%8A%E6%95%B0%E6%8D%AE%E5%BA%93%E8%83%BD%E5%8A%9B%E6%8E%A5%E8%BF%9B%E7%86%9F%E6%82%89%E7%9A%84%E5%89%8D%E7%AB%AF%E6%A0%88" class="hash-link" aria-label="2. 再把数据库能力接进熟悉的前端栈的直接链接" title="2. 再把数据库能力接进熟悉的前端栈的直接链接" translate="no">​</a></h3>
<ul>
<li class="">在 Angular、React、Vue 中复用同一套模型、查询和实体语义。</li>
<li class="">差异只保留在各框架自己的绑定层，而不是把数据层 API 做成三套完全不同的东西。</li>
<li class="">让团队可以先讨论数据结构和查询语义，再讨论具体 UI 框架怎么接。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_u3Dh" id="3-把数据层和界面层拆开">3. 把数据层和界面层拆开<a href="https://docs.aiao.io/blog/local-first#3-%E6%8A%8A%E6%95%B0%E6%8D%AE%E5%B1%82%E5%92%8C%E7%95%8C%E9%9D%A2%E5%B1%82%E6%8B%86%E5%BC%80" class="hash-link" aria-label="3. 把数据层和界面层拆开的直接链接" title="3. 把数据层和界面层拆开的直接链接" translate="no">​</a></h3>
<ul>
<li class="">让本地持久化、响应式查询、实体操作和 UI 层之间有清晰边界。</li>
<li class="">少写围绕缓存、同步状态和接口转换的胶水代码。</li>
<li class="">为后续的同步、协作和版本能力留出稳定扩展点。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_u3Dh" id="4-让前端的数据结构真正变成资产">4. 让前端的数据结构真正变成资产<a href="https://docs.aiao.io/blog/local-first#4-%E8%AE%A9%E5%89%8D%E7%AB%AF%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9C%9F%E6%AD%A3%E5%8F%98%E6%88%90%E8%B5%84%E4%BA%A7" class="hash-link" aria-label="4. 让前端的数据结构真正变成资产的直接链接" title="4. 让前端的数据结构真正变成资产的直接链接" translate="no">​</a></h3>
<ul>
<li class="">当数据真正落在前端，本地数据结构就不再只是临时状态，而会逐渐变成可复用资产。</li>
<li class="">复杂查询、树结构、关系遍历、派生视图这些能力，应该像组件一样被复用，而不是每个项目从头再写一遍。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_u3Dh" id="什么情况下你应该认真试一次-local-first">什么情况下，你应该认真试一次 Local-first<a href="https://docs.aiao.io/blog/local-first#%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E4%BD%A0%E5%BA%94%E8%AF%A5%E8%AE%A4%E7%9C%9F%E8%AF%95%E4%B8%80%E6%AC%A1-local-first" class="hash-link" aria-label="什么情况下，你应该认真试一次 Local-first的直接链接" title="什么情况下，你应该认真试一次 Local-first的直接链接" translate="no">​</a></h2>
<p>如果你的应用已经出现这些信号，现在就值得认真看一遍这条路线：</p>
<ul>
<li class="">页面越来越像一个本地工作台，而不是简单的数据展示层。</li>
<li class="">用户对离线可用、秒开、低延迟操作反馈开始有明确要求。</li>
<li class="">前端里已经堆了大量缓存逻辑、状态补丁和接口二次封装。</li>
<li class="">你希望同一套数据抽象能在不同框架里复用，而不是反复重写。</li>
</ul>
<p>Local-first 对我来说，已经不是一句“未来趋势”的判断，而是前端工程边界变化后的自然结果。浏览器现在终于有能力承接更重的数据职责，接下来真正有价值的问题，不是要不要继续喊口号，而是怎样把这层能力做得更稳、更清晰、更适合真实业务。</p>
<p>如果这些问题也是你现在正在面对的，欢迎看看我们的 <a href="https://github.com/aiao-io/aiao" target="_blank" rel="noopener noreferrer" class="">GitHub 仓库</a>，也欢迎直接拿实际业务场景来讨论。比起再讲一遍愿景，我更关心它能不能在真实项目里成立。</p>]]></content:encoded>
            <category>RxDB</category>
            <category>Local-first</category>
            <category>WebAssembly</category>
            <category>前端开发</category>
        </item>
    </channel>
</rss>