在 Expo Web 中使用 PowerSync

Expo 使用 Metro。Bundler,仅支持 CommonJS Module,而 PowerSync (及其依赖的 wa-sqlite 项目)仅支持 ESM,所以需要一些 hack 的手段来 Expo Web 环境下支持 PowerSync

准备 Web Workers Scripts

核心的点在于不要使用 npm 中自带的 Web Worker 脚本(因为其所利用的 import.meta.url 在 CommonJS Module 中不被支持),所以我们需要提取 Web Worker Scripts 然后让他在浏览器中利用 URL 加载。

Web Worker Scripts 的提取我写了个脚本获取,请参考 powersync-web-workers 仓库。下载 dist 中目录的内容,放置在你项目中的 public/lib/powersync/worker 目录下,效果如下

如果你所使用的 @powersync/web 版本不被仓库直接支持(可参考 tags),需要自行修改 package.json 文件中 @powersync/web 的版本并 build(具体可参考该仓库 README)

> tree public/lib/powersync/worker public/lib/powersync/worker ├── db │   ├── SharedWASQLiteDB.worker.js │   ├── WASQLiteDB.worker.js │   ├── wa-sqlite-async.wasm │   └── wa-sqlite.wasm └── sync └── SharedSyncImplementation.worker.js 3 directories, 5 files

Patch @powersync/web

因为 @powersync/web 不支持使用外部 URL 加载 Web Worker Script,所以需要进行一些 patch

以下 patch 以 pnpm 为例演示,你也可以自行使用 patch-package 来实现相同的效果

如果你使用的版本直接被仓库支持(可参考 tags),则只需复制 patch 文件(@powersync__web@xxx.patch)然后配置 pnpm patch 即可

复制 @powersync__web@xxx.patch 文件到 patches 目录下

编辑 package.json 文件,增加下面的内容

"pnpm": { "patchedDependencies": { "@powersync/web@1.0.0": "patches/@powersync__web@xxx.patch" } }

然后重新 pnpm install 即可

如果你使用的版本不被仓库直接支持,则需要手动进行下面的操作:

  1. 下载最新的 patch 文件,假设存放于 /tmp/@powersync__web@xxx.patch

  2. 在项目目录下执行 pnpm patch @powersync/web

  3. 打开第二步所输出的目录

  4. 在目录中执行 patch < /tmp/@powersync__web@xxx.patch

  5. 回到项目目录下执行,执行第二步所打印的 pnpm patch-commit 命令

提示:如果该项目「年久失修」,第四步的 patch 可能执行失败,你可能需要自行研究 patch 文件来替换脚本 URL