SQLite3 WebAssembly ドキュメントインデックス
(sqlite.org)- 最新の WASM 対応ブラウザで sqlite3 を直接使いたい開発者向けに、WebAssembly・JavaScript API ドキュメントを一か所に集約したハブ
- すぐに試すなら 3 ステップ HOWTO から始められ、ダウンロード・npm モジュール・ビルド・Emscripten の詳細ドキュメントでインストールと配布の流れを確認できる
- API ドキュメントは、読み込み方式、クライアントコードのレシピ、永続ストレージ、JS API における C 構造体、仮想テーブルやテーブル値関数の作成までを扱う
- SQLime、Evolu、SQLiteNext、sqlite-wasm-esm、sqlite-wasm-http といった実際の利用例と、sql.js、wa-sqlite、absurd-js などの 先行プロジェクトもあわせて整理
- ブラウザ SQLite、OPFS、IndexedDB、WASI 関連資料へリンクし、Web 環境で SQLite を使うための実装選択肢を素早く比較できる
sqlite3 WASM ドキュメントの範囲
- SQLite プロジェクトの WebAssembly・JavaScript API ドキュメントであり、最新の WASM 対応ブラウザで sqlite3 を使えるようにする API を扱う
-
プロジェクト案内とサポート経路
- About the sqlite3 WASM subproject
- Project news
- FAQ: Frequently Asked Questions
- TODOs: 計画中の機能と未計画の機能の両方を扱う
- 技術サポートとフィードバックは SQLite forum で受け付けており、commercial SQLite support contracts の契約者は既存のサポートチャネルを利用できる
-
実行・インストール・ビルド文書
- three-step HOWTO: sqlite3 WASM モジュールと関連する JavaScript API を組み込み、実行する方法を実演
- Downloads: メインプロジェクトのダウンロードページで提供
- Building sqlite3 WASM: sqlite3 WASM と関連 JS コードのビルド手順を扱う
- Emscripten ビルドの詳細
-
API と実装詳細ドキュメント
- The API index: 複数の API バリエーションと読み込み・アクセス方式を説明
- Cookbook: クライアントレベルのコード向けレシピ
- Persistent storage options: 永続ストレージの選択肢
- C-structs: JS API で C 構造体を使う方法
- virtual tables: JS で仮想テーブルとテーブル値関数を作る方法
- API changes: クライアントに影響する可能性のある API 変更点
- module symbols app: JavaScript/WASM モジュール内の sqlite3 API シンボル一覧を生成
-
ドキュメントとリポジトリの保守
利用例と関連エコシステム
-
このプロジェクトを使うサードパーティプロジェクト
- SQLime: データベースブラウザのインターフェースを提供
- Evolu: プライバシー、使いやすさ、ベンダーロックインなしを重視したローカルファースト(local-first)プラットフォーム
- SQLiteNext: このプロジェクトを next.js と統合するデモ
- sqlite-wasm-esm: Vite ツールチェーンでこのプロジェクトを使う方法を実演
- sqlite-wasm-http: HTTP 経由で直接提供されるデータベースへの読み取り専用アクセスを提供する SQLite VFS
-
先行研究と隣接プロジェクト
- Alon Zakai の sql.js: WebSQL を除けば、ブラウザで sqlite3 を直接利用した最初期の事例として知られ、2012年のコミットまでさかのぼる
- Roy Hashimoto の wa-sqlite: sqlite3 データベース向け OPFS storage の初期実装として知られ、JS 側の SQLite VFS 関連作業も含む
- James Long の absurd-js: sqlite3 データベースを IndexedDB データベース内に保存する方法を実演
- postgres-wasm: ブラウザで Postgres database server を実行
- Jaccwabyt: WASM 上でホストされた C 構造体を JS コードで操作する小さな JS ライブラリで、このプロジェクトの OPFS sqlite3_vfs 実装を支援するために作られた
- CoWasm: “Collaborative WebAssembly for Servers and Browsers” であり、demo app に sqlite3 shell アプリケーションの WASM ビルドを含む
- absurder-js: Nicholas G. Piesco が absurd-js を再構想したプロジェクトで、SQLite forum announcement もある
- sqlite-wasm-rs:
wasm32-unknown-unknownビルド向けの Rust 製 SQLite バインディングを提供
-
外部ドキュメントと記事
- Porting WebSQL to OPFS: Google Chrome dev team による SQLite WASM 関連記事
- building SQLite3 for WASI: VMWare OCTO チームによる WASI 向け SQLite3 ビルド記事
1件のコメント
Hacker News のコメント
ブラウザ上でインメモリ SQLiteを動かしつつ、Litestream や Cloudflare Durable Objects が使っている方式のように、WAL ログのコピーをサーバーへストリーミングすると面白そう
WebSocket を使ってもいいし、断続的な
fetch()POST でも可能に見える。その後の訪問時には、サーバー側のデータを使ってクライアントの SQLite を再び埋める方式になるただし SQLite フォーラムの投稿 を見ると、標準の SQLite WASM ビルドでは WAL モードが外されているので、カスタムビルドが必要になりそう
インメモリ SQLiteは WAL を使わないし、ブラウザ Wasm は SQLite の WAL モードが想定する共有メモリ API のようなものをサポートしていない
Litestream には非常に厳密な WAL 構成が必要で、ネイティブ SQLite の標準構成ではたまたまうまく合っているが、Wasm で再現するのは難しい
Cloudflare Durable Objects は Litestream に着想を得ている可能性はあるが、実際の動作はかなり異なるし、LiteFS や Turso も同様
SQLite の変更分をストリーミングするという大きなアイデア自体は可能だが作業量が多く、ブラウザ Wasm の並行性モデルのため実装は厄介
そのフォーラム投稿は以前に自分が書いたもので、サーバー側の Wasm SQLite ビルドでは WAL を動かしたが、ブラウザで使える、あるいは実現可能な選択肢ではなかった
justjs14当時のコードは探す必要があるが、ブラウザで VFS 付きの SQLite を Wasm にコンパイルして DB を開き、変更後に WAL をサーバーへプッシュ/プルできるようにしていた。手動でも WebRTC でもブラウザ間同期が可能で、ブラウザクライアントに GitHub トークンを渡せば GitHub Pages でも動作する
興味があれば、また最初から実行できるようにしてみてもよい。当時このアプローチでかなり実験していて、少なくとも一部のアプリケーションには有用になり得ると考えている
プル機能だけのデモもここにある: https://just.billywhizz.io/sqlite/demo/#https://just.billywhizz.io/sqlite/demo/db/chinook.db
「共有メモリ」は
SharedArrayBufferにできるし、DB 接続を一度に1つだけ開くなら通常のバッファでも可能。たとえば、すでに一般的なSharedWorkerの中でそのようにできる実装は単純ではないだろうが、明らかに可能。実際には、より大きな問題は行単位ではなくブロック単位の変更をキャプチャする点にある
そのため DB 全体の複製には使えるが、一部の行を他のユーザーと共有するような部分同期は難しい
部分同期のために行単位の変更が必要なら、トリガーや SQLite セッション拡張のようなものを使う必要がある: https://sqlite.org/sessionintro.html
PowerSync ではクライアント側トリガーを使っており、トリガーの保守作業以外には大きな欠点は見つからなかった
たとえば一般的なテンプレートレンダリングや一部の Htmx エンドポイントを Wasm で動かせば、普通のサーバーサイド Web フレームワークでも、OP が言っているものに近い SQLite Wasm ストアでオフライン機能を提供できる
Django の完全な例: https://github.com/m-butterfield/django_webassembly
マクロでクライアント/サーバーを分離した最小限の Rust 例: https://github.com/richardanaya/wasm-service
Wasm なしで同じようなことを、より多くのマクロで行う Clojure Electric: https://github.com/hyperfiddle/electric
最近の Microsoft 系の Web ツールには B で始まるものもある
ここ数年で Python エコシステムの意外に多くの部分が Wasm 対応を得て、このアプローチに活用できるようになった。明らかな機械学習関連ライブラリだけでなく、Pygame や Pyxel のようなゲームライブラリもあり、SDL2 が対応を追加したので、マルチタッチ UI ライブラリである Kivy の対応も遠くなさそう
どんなコンピュータでもコードを実行し、必要なら Web ブラウザのサンドボックス内でプラットフォームの官僚主義や手数料を避けられる、新しい可能性が多くありそう
ドキュメントには、これらのコンポーネントは 3.40 で公開ベータとして初めて登場し、コミュニティからのフィードバックに応じて 3.41 で API を安定化する予定だと書かれている
ただし最新の SQLite リリースは 2024-08-13 の 3.46.1 なので、おそらく API の安定化はすでに済んでいて、ドキュメントが更新されていないだけのようだ
SQLite チームが WASM 版をまとめた公式 npm パッケージを出してくれれば、よい配布手段になりそうだ。あとで見ると、返信によればすでに存在するらしい
個人的にいちばん気に入っている SQLite-in-WASM は今でも Pyodide 版だ。公式 SQLite 実装よりずっと前から存在していて、Pyodide を使うと Python 標準ライブラリの一部として WASM SQLite が付いてくる
https://lite.datasette.io/ ではその形で使っており、https://pyodide.org/en/stable/console.html でも試せる
sqlite3.connect(':memory:')でselect sqlite_version()を実行すると 2022-06-25 の 3.39.0 が返るので、Pyodide はバージョンアップが必要そうだ。このバージョンは emscripten から引き継いでいるようだ: https://github.com/emscripten-core/emscripten/blob/main/tools/ports/sqlite3.pyただし SQLite チームが公式 npm パッケージを出すことはないだろう。私たちは純粋な JS だけを配布しており、言語外ツールのサポートという泥沼に入ることは断固として拒んでいる。プロジェクトメンバーの誰もそうしたツールを使っていない
Thomas Steiner がメンテナンスしている「公式承認済み」の npm ビルドはサポートしているが、どの JS フレームワークも積極的な開発対象にはしていない
特定のフレームワーク、npm を含む、を直接サポートすると、そのフレームワークを推奨しているという印象を与えかねず、私たちはサードパーティープロジェクトの推奨を積極的に避けている
@sqlite.org/sqlite-wasmをjsdelivrから取り込み、sqlite3-bundler-friendly.mjsとsqlite3.wasmをロードすればよいそうすれば SQLite の C API と
oo1オブジェクト指向 API を使え、通常のtype=moduleスクリプトタグや Deno でも動作するサンプル HTML はここにある: https://github.com/Ciantic/experimenting-sqlite-wasm/blob/main/standalone.html
sqlite-wasmは Pyodide よりはるかに速くロードされるので、Python が不要なら前者のほうがよい選択だただし、かなり制限があるようだ。
sqlite_version()がないのでバージョン確認すらできず、リポジトリのバージョンは 3.38.1 とかなり古い現在の DuckDB Web シェルは、昨日出た 1.1.2 向けの SQLite 拡張がまだリリースされていないため、SQLite 拡張をロードできない。以前のバージョンは最近更新された WASM エディションで動作する
空間拡張、GDAL、ベクトル検索なども組み込める: https://github.com/duckdb/duckdb-wasm/releases/tag/v1.29.0
自前で「SQL Web シェル」を作るのもそれほど難しくはなかったが、ドキュメントは十分に完全とは言えなかった
https://github.com/duckdb/sqlite_scanner/blob/main/src/sqlite/sqlite3.h
Go で使う場合は、ncruces の Wasm SQLite パッケージ https://github.com/ncruces/go-sqlite3 が本当に気に入っている
cznic の Go パッケージも素晴らしいが、この Wasm 版は OpenBSD のような環境でもうまく動作する
WebSQL は単に SQLite であるべきだったし、そうであればオフラインファーストやアプリ全般のストレージエコシステムはずっと良くなっていただろう
今からでも可能性はあるだろうか。SQLite を抽象化して過剰に仕様化するより、ブラウザーがサポートすべき SQLite API バージョンを仕様化し、定期的にバージョンを上げていく形にはできないだろうか?
Web の核心のひとつは、可能な限り既存のものが動き続けるべきだという点で、そうした破壊的変更は難しい
仕様がいくつかのバージョンを列挙し、Web ページが選べるようにしたとしても、ブラウザーはもはやサポートされていないかもしれない古い SQLite バージョンを維持するという厄介な負担を抱えることになる。各バージョンはさらに 1MB ほどを占める
それなら、今のように各 Web サイトが自分の選択の代償を負うようにしておくほうがよいのではないかと思う
共通リソースを繰り返しダウンロードすることが心配なら、それはすでに他の CDN でも受け入れられている問題だ。共通依存関係の共有キャッシュ解決策は、SQLite だけに限定されるものよりはるかに価値が大きいだろう
現在の方式のほうが、ブラウザー提供版より良さそうに見える
今では必要なときに 410KB の圧縮 WASM blob として最新の SQLite を取得できる。ブラウザーが強制する SQLite バージョンに縛られていたら、今ごろ 10 年前のバージョンを使っていたかもしれない
ページをざっと見ただけでは、ユースケースがよく分からない
もっと具体的には、これは IndexedDB の代替になり得るのか? データは永続化されるのか、それとも SQLite ファイルを File System API や IndexedDB/localStorage に直接保存する必要があるのか?
現時点では Origin-Private FileSystem(OPFS)と、非常に限定的ながら
window.localStorage、window.sessionStorageバックエンド経由の保存を含む最近 ローカルファースト領域にかなり関心があるが、ブラウザ内蔵のストレージ API、特に IndexedDB を使う場合と比べると、SQLite を埋め込むのはかなり重く感じる
主要なオープンソースライブラリも、おおむね内蔵 API を使っているように見える
WebAssembly でさらに別の実行ファイルを入れようとするより、ブラウザネイティブのストレージ上に SQLite 風の API と同期を提供するオープンソースの解法を見てみたい
if()フィルタの代わりにWHERE句を使えば メモリと CPU の使用を抑えられるかもしれない公式ダウンロードページから取得して
mjsファイルと「bundler-friendly」ファイルをすべて取り除いても、最小の SQLite Wasm 依存関係は約 1.3MB になるブラウザアプリでは少し大きめに見えるが、最近の Wasm は他の場所でも実行されるので、そうした環境ではより筋が通るかもしれない
sqlite3.jsと Wasm は元のサイズで 1.3MB だが、JS を最小化し、2つのファイルを Brotli で圧縮すると 410KB まで下がるユーザー設定を保存する程度なら当然 SQLite をダウンロードする必要はないが、完全なデータベースが利点になる作業なら、1MB を気にしすぎて無駄に車輪の再発明をする必要はない
他のコメントが正しければ、ネットワーク上ではそもそも 1.3MB ですらないはず
それでも Figma や Photoshop のようなアプリ、機械学習アプリのように、アプリケーションコードとデータがもともと大きいブラウザアプリでは、1.3MB は大きな追加負担ではないかもしれない
Wasm のパースは JS よりかなり速いという点も考慮に値する。この主張の出典はいま見つけられないが、関連する良い記事が少なくとも一つはあった
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
ローカルかもしれないし、中央サーバーかもしれないし、近くの エッジかもしれない
また WASI はまだ答えには程遠い。SQLite amalgamation は WASI で問題なくビルドできるが、同時実行性は未解決の問題
Wasm ベースの SQLite ドライバを使える状態にするために、VFS を一から作る必要があった
https://github.com/ncruces/go-sqlite3/blob/main/vfs/README.md
しばらく Rust エコシステムでこれを動かそうとしていたが、blessed.rs の SQL ラッパーである
rusqlite、sqlxはまだこれを活用できないようだった自分でラップするのも難しく、emscripten Wasm コードを
wasm32-unknown-unknownと噛み合わせて動作させる方法を見つけられなかった結局、何らかの形で JS ラッパーが必要になり、そうなるとそれらのクレートが期待するインターフェースを実装して JS から公開しなければならない。Rust でこれが解決されれば本当に良くなるはず
本質的には、
wasm-bindgenでextern Cヘッダーとして SQLite emscripten ビルドを取り込み、共有配列バッファへのアクセスを可能にするためマルチスレッドモードでコンパイルしつつ、VFS を Rust で再実装する必要があるその後は SQLite の行を生の Wasm バイトとしてアクセスできるようになり、Rust-SQLite スタイルのラッパーや統合を作れる
接続プーリングのような便利機能は依然としてないだろうが、Wasm では DB を 排他モードで使うほうがよい可能性が高い
今週 0.2 リリースを準備中で、いくつかの問題を調整する予定。それ以外は Diesel ORM をネイティブ同様に使える
emscriptenWasm コードとwasm32-unknown-unknownをうまく噛み合わせる部分については良いニュースがあるEmscripten と Rust が Wasm 上でうまく連携できるようにする計画がある: https://github.com/rustwasm/wasm-bindgen/pull/4014#issuecomment-2356908451
SQLite の Wasm ビルドと Chicory ランタイムを使って、純粋な JVM 上で動作する SQLite ライブラリを作った: https://github.com/dylibso/sqlite-zero
本番投入を目指したものというよりは実験に近いが、依存関係のない SQLite ツールを JVM エコシステムに持ち込むうえでは有用かもしれないと思う
一般的な質問だが、どんな状況なら DB 全体を送ってブラウザ側でクエリを処理させるほうが有利なのか?
言い換えると、従来のサーバーホスティング DB モデルよりユーザー体験を改善するために、これはいつ使うことになるのか?
適切なドライバを使えば、データベース全体を送る代わりに必要なデータベースのチャンクをストリーミングできる: https://github.com/mmomtchev/sqlite-wasm-http
FTS データベース全体をダウンロードしなくても SQLite の全文検索ができる。検索語が十分短いと大部分は受け取るが、全部ではない
https://medium.com/offline-camp/couchdb-pouchdb-and-hoodie-as-a-stack-for-progressive-web-apps-a6078a985f18
オーディオライブラリから 3D モデリングソフトウェアまで考えられる。変更をローカルで作成して永続化し、その後、定期的に、または再びオンラインになったときにサーバー側と同期すればよい
こうしたアプリは クライアント側の組み込み DB によく合う候補だ