DuckDB-Wasm (OPFS) メモ

DuckDB-Wasm に OPFS 対応がマージされたので、自分用にメモしていきます。
Add OPFS (Origin Private File System) Support by e1arikawa · Pull Request #1856 · duckdb/duckdb-wasm
DuckDB-Wasm の OPFS 対応は DuckDB-Wasm のデータベース保存先を OPFS にするという仕組みです。この仕組みを利用することでブラウザを閉じてもデータが残るようになります。
今まで自前で Parquet ファイルなどを OPFS に保存する仕組みが一切不要になります。
npm パッケージ
2025 年 2 月 9 日現在で 1.29.1-dev68.0 で動作を確認しています。

利用方法はシンプルで db.instantiate した後に db.open で path に opfs:// から始めます。
書き込みと読み込みをするので、 accessMode を READ_WRITE にします。
import * as duckdb from '@duckdb/duckdb-wasm'
import duckdb_worker from '@duckdb/duckdb-wasm/dist/duckdb-browser-eh.worker.js?worker'
import duckdb_wasm from '@duckdb/duckdb-wasm/dist/duckdb-eh.wasm?url'
const worker = new duckdb_worker()
const logger = new duckdb.ConsoleLogger()
const db = new duckdb.AsyncDuckDB(logger, worker)
await db.instantiate(duckdb_wasm)
await db.open({
path: 'opfs://duckdb-wasm-opfs.db',
accessMode: duckdb.DuckDBAccessMode.READ_WRITE,
})
実際に書き込む場合は CHECKPOINT;
を呼び出すことで、 OPFS の WAL から DB へ書き込まれます。
CHECKPOINT Statement – DuckDB
const con = await db.connect()
// ここで WRITE 処理を行う
await conn.send('CHECKPOINT;')
await conn.close()

OPFS に保存されるファイルの確認と削除
確認方法は OPFS Explorer がお勧めです。
削除は今のところ OPFS API をそのまま使う方法が良さそうです。
await db.terminate()
const opfsRoot = await navigator.storage.getDirectory()
await opfsRoot.removeEntry('duckdb-wasm-opfs.db').catch(() => {})
await opfsRoot.removeEntry('duckdb-wasm-opfs.db.wal').catch(() => {})
DuckDB-Wasm の OPFS のテストがそのまま利用してるので現時点ではこれで良さそうです。

デモ
雑なコードですが、以下で確認できます。
DuckDB-Wasm + Parquet + S3-compatible object storage + OPFS

VoidLogger
console.log にログを出さないには VoidLogger() を利用すると良い。
const logger = new duckdb.VoidLogger()
this.db = new duckdb.AsyncDuckDB(logger, worker)

課題
複数タブを開いたときの挙動が不安定。OPFS を両方から読もうとしてしまう。Web Locks API を利用してなんとかうまくやる必要がある。