esbuild 打包 PGlite 时 new URL() 资源解析失败如何手动提供 WASM 模块与 fsBundle?
【免费下载链接】pgliteEmbeddable Postgres with real-time, reactive bindings.项目地址: https://gitcode.com/GitHub_Trending/pg/pglite
当你用 esbuild 打包一个使用 PGlite 的前端项目时,会遇到一个典型的资源解析问题:PGlite 靠new URL('./file', import.meta.url)这个写法来定位自己的 WebAssembly 模块和数据文件,而 esbuild 不支持这种模式,导致自动的文件解析开箱即用不了。这篇文章解决的就是这一个具体问题——在 esbuild 环境下,如何手动提供pgliteWasmModule、initdbWasmModule和fsBundle这三项,让 PGlite 实例正常创建,并说明如何验证它确实跑起来了。
先说清楚 PGlite 到底在用这些资源做什么。在 pglite.ts 里,创建实例时会用new URL('../release/pglite.wasm', import.meta.url)、new URL('../release/initdb.wasm', import.meta.url)和new URL('../release/pglite.data', import.meta.url)去定位三个文件(见 pglite.ts#L315-L338)。esbuild 不认这种 URL 写法,所以打包后这些路径就失效了。解决办法就是绕过自动解析,自己把这三样东西喂给 PGlite。
准备条件
- 项目中已安装
@electric-sql/pglite,node_modules/@electric-sql/pglite/dist/目录里能找到pglite.wasm、initdb.wasm和pglite.data这三个文件。 - 你使用 esbuild 作为构建工具,且需要你的 Web 服务器能够对外提供这三个静态文件。
第一步:把三个文件复制到静态资源目录
把pglite.wasm、initdb.wasm和pglite.data从node_modules/@electric-sql/pglite/dist/复制到你的 public/build 目录,让你的 Web 服务器能直接按路径访问到它们。
这一步只是文件搬运,不涉及安装系统工具或改动环境。复制后,这三个文件在你的站点根路径下应该能通过/pglite.wasm、/initdb.wasm、/pglite.data访问到。
第二步:创建实例时手动传入三个选项
在创建 PGlite 实例时,不再依赖自动解析,而是用fetch把三个资源拉下来,再作为选项传进去:
import { PGlite } from '@electric-sql/pglite' const [pgliteWasmModule, initdbWasmModule, fsBundle] = await Promise.all([ WebAssembly.compileStreaming(fetch('/pglite.wasm')), WebAssembly.compileStreaming(fetch('/initdb.wasm')), fetch('/pglite.data').then((response) => response.blob()), ]) const db = await PGlite.create({ pgliteWasmModule, initdbWasmModule, fsBundle, })这里对应的是 interface.ts#L98-L100 中声明的三个可选选项:pgliteWasmModule?: WebAssembly.Module、initdbWasmModule?: WebAssembly.Module、fsBundle?: Blob | File。
注意类型要匹配:
pgliteWasmModule和initdbWasmModule需要是WebAssembly.Module,所以用WebAssembly.compileStreaming(fetch(...))来编译,它返回的正是这个类型。fsBundle需要是Blob | File,所以用fetch('/pglite.data').then((r) => r.blob())得到一个Blob。
/pglite.wasm、/initdb.wasm、/pglite.data这三个路径对应你在第一步里放到站点根目录的文件。如果你的部署里静态资源挂在别的子路径下,把 fetch 里的路径改成对应的实际地址即可,但要保证路径指向的就是刚才复制的那三个文件。
验证:确认实例能正常查询
创建成功后db就是一个可用的 PGlite 实例。用项目 README 里的标准查询来验证它确实跑起来了:
const result = await db.query("select 'Hello world' as message;") // 文档示例:{ rows: [ { message: "Hello world" } ] }如果这条查询按 README 示例返回了rows,说明 WASM 模块和数据文件都正确加载了,资源解析问题已经解决。
排查:fsBundle 大小不匹配时的报错
如果你手动复制了pglite.data,但要留意一个校验点。源码里会检查fsBundle的实际字节数是否等于期望的包大小,不一致时抛出Invalid FS bundle size: ${fsBundleBuffer.byteLength} !== ${remotePackageSize}(见 pglite.ts#L377-L387)。如果你看到这条报错,通常意味着你复制的pglite.data和当前@electric-sql/pglite版本不配套——重新确认你复制的三个文件都来自当前安装版本的node_modules/@electric-sql/pglite/dist/,而不是旧版本或别处的残留文件。
可选:改用 esbuild 插件自动处理
如果你不想手动搬运和传入这三个文件,文档给了另一条路径:使用 esbuild 插件(如@chialab/esbuild-plugin-meta-url)来自动处理new URL()导入。这样可以让 esbuild 自己解析出 URL 指向的资源,省去手动复制和手动传参的步骤。是否采用取决于你的项目是否方便引入额外插件;上面手动提供三项的方式则是文档给出的、不依赖任何插件的通用解法。
两种方案的边界:手动方式不引入任何新依赖,但需要你保证静态服务器能正确提供这三个文件,并在代码里明确传参;插件方式改动集中在 esbuild 配置里,但需要引入并正确配置该插件。选哪条,以你的构建约束为准。
【免费下载链接】pgliteEmbeddable Postgres with real-time, reactive bindings.项目地址: https://gitcode.com/GitHub_Trending/pg/pglite
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考