本地优先架构与 Expo

编辑

对新兴本地优先软件运动的介绍,包括相关学习资源和工具的链接。


本指南仍在完善中。如果您有任何反馈,请在我们的 GitHub 存储库中提交问题

“本地优先”这一术语最早出现在研究实验室 Ink & Switch 撰写的论文 "Local-first software" 中,但其背后的理念早已存在。它是支持一些我们最喜爱的应用程序的架构,如 LinearSuperhumanExcalidraw 甚至 Apple Notes.

在本地优先软件中,“另一台计算机的可用性永远不应妨碍你工作”(通过 Martin Kleppmann)。当你离线时,你仍然可以直接从/写入设备上的数据库。你可以信任软件在离线状态下的可靠性,并且当你连接到互联网时,数据会无缝地同步并在运行该应用程序的任何设备上可用。当你在线时,这种架构非常适合“多人”应用程序,如 Figma 所推广的

要深入了解本地优先的意义及其工作原理,请参考下面的 附加资源

为什么使用本地优先架构?

用户体验的好处

本地优先软件感到 快速,因为交互不再依赖于网络,你可以直接从/写入设备上的数据库。

你可以信任软件在离线状态下的运行,当你连接到互联网时,数据会无缝地同步并在运行该应用程序的任何设备上可用。

本地优先软件的另一个特点是它是协作性的——多个设备可以共同处理相同的数据,并且所有变化会在它们之间同步。当你在 Figma 中共同设计时,这种同步可以实时发生,或者是在离线状态下在 Linear 中创建任务并在你再次在线时同步。

开发者体验的好处

你不再需要为每个网络请求管理应用程序的各种状态——“已加载”、“加载中”、“错误”等,以及它们相应的 UI 状态和其他逻辑。写入本地数据库,应用程序将自动将更改同步到服务器。这意味着你可以专注于构建应用程序,而不必过多担心网络和离线状态的问题。

你的服务器可用性可能仍然很重要,但在停机的情况下,用户仍然可以访问应用程序并继续工作。你甚至可以提供一个机制,在不经过服务器的情况下同步数据。

构建本地优先应用程序的挑战

今天可用的工具仍处于早期阶段,因此你可能会发现自己在解决本应由你今天使用的工具解决的问题。例如,你可能需要实现一个自定义的同步层,或者可能必须弄清楚如何处理多个用户在同一数据上操作的权限。随着生态系统的发展,我们预计构建本地优先应用程序将变得更加简单。如果你没有准备好成为早期采用者,以及随之而来的所有挑战,可能想等到工具成熟后再开始使用本地优先工具构建应用程序。

构建本地优先应用程序的工具

关于工具的全面列表可以在 "Local-first software" community website 上找到。以下是我们在 Expo 直接使用过的一些工具的简略列表。

一种思考本地优先工具的方式是按以下类别进行分组:持久性、状态管理和同步。如果某些工具处理了问题的多个方面,它们可能会适合多个类别。同步可以进一步细分为可同步的数据结构和传输层。

Legend-State

Legend-State 是一个超级快速的全能状态和同步库,让你输入更少的代码来制作更快的应用程序。它有以下主要目标:

  • 更快的 React 应用状态管理
  • 细粒度反应以实现最小渲染
  • 强大的同步和持久化(支持 Supabase 内置)

它与 Expo 和 React Native 一起使用(通过 react-native-async-storage)。这使得它成为构建本地优先移动和 Web 应用程序的完美选择。通过使用 Legend-State Supabase 示例 开始:

Terminal
npx create-expo-app --example with-legend-state-supabase

TinyBase

TinyBase 自称为“本地优先应用的反应式数据存储”。它是一个状态管理库,可以与许多流行的同步和持久层(如 YjsSQLite)结合使用。它是构建需要持久和同步数据的本地优先应用的一个好选择。通过使用 TinyBase 示例 开始:

Terminal
npx create-expo-app --example with-tinybase

TinyBase 与 Expo Go 无缝协作,使你能够快速开发。在安卓和 iOS 上,它使用 expo-sqlite 库来持久化数据。在 Web 上,它依赖于 localStorage API。Beto Moedano 在以下视频中展示了如何构建一个 通用本地优先购物清单应用

观看:使用 Expo 和 TinyBase 构建本地优先实时购物清单应用
观看:使用 Expo 和 TinyBase 构建本地优先实时购物清单应用

SQLite

Expo SQLite 是一个 SQLite 库,非常适合用于本地优先应用的持久化。你可以将 SQLite 与不同的状态管理和同步层结合使用,例如 y-expo-sqlite 来持久化 Yjs 文档,并使用 TinyBase 作为状态管理层。使用 SQLite 灵活,但你需要将其与其他工具结合使用或构建自己的工具,以获得完整的本地优先解决方案。有关更多信息,请参见 Expo SQLite API 参考

Yjs

Yjs 是一种 CRDT 实现,提供可以在多个客户端之间同步的数据类型。当使用 Yjs 构建应用程序并处理希望能够同步的数据时,你应该使用 Y.ArrayY.Map 来表示你的数据,而不是使用 ArrayObject。你可以在 Yjs 基础上使用像 TinyBase 这样的库进行状态管理,持久化可以通过多种工具处理,从文件系统上的 JSON 文件到完整的数据库(如 y-expo-sqlite)及其间的所有其它工具。有关更多信息,请参见 Yjs 的 GitHub 存储库

Prisma

Prisma 作为 Node.js 和 TypeScript 后端最流行的 ORM 而闻名,现在已在 Expo 和 React Native 早期访问 中可用。Prisma 致力于提供完整的本地优先解决方案,涵盖状态管理、同步和持久性。尽管仍在早期阶段,但 Beto Moedano 已经整理了一份完整的指南,介绍如何使用 Prisma 和 Expo 构建本地优先 Notion 克隆,请查看 GitHub 上的代码

观看:使用 React Native Expo 和 Prisma 构建本地优先 Notion 克隆
观看:使用 React Native Expo 和 Prisma 构建本地优先 Notion 克隆

Jazz

Jazz.tools 是一个构建本地优先应用的框架。它是开源的,提供对 Expo 的一流支持,你可以自托管它或使用 Jazz Cloud 快速开始。Jazz。要了解更多,请查看 示例 或参阅 入门指南 以获取详细说明。

LiveStore

LiveStore 是一个以客户端为中心的本地优先数据层,适用于高性能应用程序。它为 Expo 提供了一流的支持,是构建本地优先应用的不错选择。请参见关于 LiveStore: 基于 SQLite 的本地优先应用的数据层 的博客文章。

观看:如何使用 LiveStore 和 Expo 构建本地优先原生应用
观看:如何使用 LiveStore 和 Expo 构建本地优先原生应用

Turso

Turso 是一个基于 SQLite 的现代数据库服务。它现在支持 离线同步,使真正的本地优先体验得以实现。你可以在本地和远程源之间以双向同步和内置冲突检测同步数据库。虽然自动冲突解决功能尚不可用,但这一特性仍然是一个重大进步。你今天可以与 expo-sqlite 一起使用 Turso。要了解更多信息,请阅读 Turso: 离线同步公共测试版 的博客文章。有关示例集成,请查看 Notes App

观看:如何使用 Turso 和 Expo 构建本地优先 Notes App
观看:如何使用 Turso 和 Expo 构建本地优先 Notes App

Instant

Instant 是 Firebase 的现代替代品。它为你提供了一个实时数据库,让你能专注于构建应用程序的前端。要开始,请查看 入门指南。你还可以探索下面视频中展示的 Sketch App

观看:使用 Expo、Instant 和 Reanimated 构建本地优先 Sketch App
观看:使用 Expo、Instant 和 Reanimated 构建本地优先 Sketch App

其他工具

以下列表并不全面,但提供了其他一些引起我们关注的工具,您可能会发现它们有趣并值得探索。有关更全面的工具列表,请参见 "Local-first software" community website

附加资源