未分類

ブラウザでSQLが動く?PGliteを使う理由

開発を進めるとき、「まずローカルで動かして、あとでサーバーに繋ぐ」という流れはよくあります。でもそのとき、こんな問題が起きたことはありませんか?

「ローカル用に書いたコード、サーバー対応に書き直さないといけないじゃん…」

今回紹介する PGlite は、そのストレスをなくすために使っています。


そもそもブラウザのデータ保存って?

ブラウザには標準で IndexedDB というデータ保存の仕組みがあります。ブラウザを閉じてもデータが消えない、サーバー不要で使える、という点では優秀です。

ただ、直接使うのがかなり面倒です。

// IndexedDB を直接使う場合
const tx = db.transaction('locations', 'readwrite');
const store = tx.objectStore('locations');
store.add({ id: '1', name: '自宅' });
// SQLが使えない、キーバリュー形式のみ

SQLは使えない、キーと値のペアしか扱えない——柔軟なデータ操作が必要になった途端に辛くなります。


PGlite とは

PGlite は、ブラウザの中でPostgreSQLを動かすライブラリです。PostgreSQLエンジンをWebAssembly(Wasm)にコンパイルして動かし、データの実際の保存先としてIndexedDBを使います。

あなたのコード(SQL文)
      ↓
PGlite(PostgreSQLエンジンをWasmで動かす)
      ↓
IndexedDB(バイナリデータとして実際に保存)

IndexedDBはあくまでバイナリデータの置き場として使われるだけで、SQL解釈やテーブル管理はPGliteが担っています。使う側からは「普通のPostgreSQL」として扱えます。

// PGlite を使う場合
await db.query(`INSERT INTO locations (id, name) VALUES ($1, $2)`, ['1', '自宅']);
await db.query(`SELECT * FROM locations WHERE name = '自宅'`);

なぜ PGlite を選んだのか

一番の理由は、Supabaseとの相性です。

このアプリでは最終的にバックエンドとして Supabase(PostgreSQLベースのBaaS)を使う予定があります。でも開発の初期段階から外部サービスとの連携を考えながら実装するのは、開発スピードを著しく落とします。

そこで考えたのが、こういう方針です。

「最初からSupabaseで使うのと同じSQLを書いておけば、繋ぎ替えるだけで済む」

たとえば、IndexedDBをラップした独自の仕組みでローカル保存を実装してしまうと、後でSupabaseに移行しようとしたときにデータアクセスのコードを全部書き直す羽目になります。

PGliteを使えば、ローカル環境でもSupabaseでも同じPostgreSQL構文のSQLで書けるので、移行時の変更は接続先の切り替えだけ。最初にプラグを用意しておいて、本番では挿すだけ、というイメージです。


SQLって何?

念のため、SQLについて簡単に触れておきます。

SQLはデータベースを操作するための専用言語です。TypeScriptなどのプログラミング言語とは別物ですが、ほぼ英語の文章そのままで読めるのが特徴です。

操作SQL意味
取得SELECT読む
追加INSERT書く
更新UPDATE書き換える
削除DELETE消す

MySQL・PostgreSQL・SQLiteなど種類はありますが、基本的な文法はどれもほぼ同じです。一度覚えれば、どの環境でも使い回せます。


PGlite の特徴まとめ

  • 端末ごとに独立している(PCとスマホで別々のIndexedDB)
  • ブラウザを閉じてもデータは消えない
  • アプリをアンインストール(ブラウザのデータ削除)すると消える
  • サーバー不要でブラウザだけで動く
  • PostgreSQL互換なのでSupabaseへの移行がスムーズ

まとめ

PGliteを使う理由は、単に「ブラウザでSQLが使えて便利」というだけではありません。最初から本番を見据えた設計にしておくことで、後の移行コストをゼロに近づけるという判断です。

開発初期から外部連携を作り込みすぎると手が止まる。でも将来の拡張を無視して実装すると後で詰む。そのバランスをとるための選択として、PGliteはちょうどいい落とし所でした。