PGliteとは
PGliteは、PostgreSQLをWebAssemblyバイナリとしてビルドしたTypeScript(JavaScript)のクライアントライブラリです。これを使用すると、ブラウザやNode.js上でPostgreSQLを動作させることができます。
最近では、ブラウザ内でAI機能付きのPostgreSQLを動作させる『database.build』というサービスも登場しました。これはPGliteを基盤としています。
この記事では、ブラウザ内で動作するPostgreSQLがどのようなものなのか、どのようなことができるのかを実際に試しながら解説します。
前提
以下の環境で動作確認を行っています。
os | windows11(4cpu、16GB) |
PGlite | 0.2.17 |
typescript | 5.8.2 |
vue | 3.5.13 |
IDE | Visual Studio Code |
基本的なDB操作
PGliteの公式ドキュメントを参考に進めていきます。
インストール
まず、PGliteをインストールします。
npm install @electric-sql/pglite
in-memory Postgresを試す
まずは、データをメモリ内に保存するシンプルな例を試してみます。
<script setup lang="ts">
import { PGlite } from '@electric-sql/pglite'
import type { Results } from '@electric-sql/pglite'
import { onMounted, ref } from 'vue'
let db = new PGlite()
onMounted(async () => {
await db.exec(`
CREATE TABLE IF NOT EXISTS todo (
id SERIAL PRIMARY KEY,
task TEXT,
done BOOLEAN DEFAULT false
);
INSERT INTO todo (task, done) VALUES ('Install PGlite from NPM', true);
INSERT INTO todo (task, done) VALUES ('Load PGlite', true);
INSERT INTO todo (task) VALUES ('Update a task');
`)
})
type Todo = {
id: number
task: string
done: boolean
}
const result = ref<Results<Todo>>({
rows: [],
affectedRows: 0,
fields: [],
})
const getAsync = async () => {
result.value = await db.query<Todo>('SELECT * FROM todo')
}
const task = ref('')
const addAsync = async () => {
await db.exec(`INSERT INTO todo (task) VALUES ('${task.value}')`)
await getAsync()
}
</script>
上記の例では以下を3つの処理を実施しています。
- 初回ロード時に、テーブルを作成し、初期データを挿入
- Getボタンを押下することで、データを検索
- Addボタンを押下することで、データを追加
以下のHTMLでは初期データや追加したデータを表示します。
<template>
<main>
<div class="row">
<label for="task" class="col-sm-1 col-form-label fw-bold">Task</label>
<div class="col-sm-4">
<input id="task" type="text" v-model="task" class="form-control" />
</div>
<div class="col-sm-1">
<button class="btn btn-primary" @click="addAsync">Add</button>
</div>
</div>
<div class="row mt-3">
<div class="col-sm-2">
<p class="fw-bold col-form-label">Todo List</p>
</div>
<div class="col-sm-1 offset-sm-3">
<button class="btn btn-primary" @click="getAsync">Get</button>
</div>
</div>
<ul>
<li v-for="todo in result.rows" :key="todo.id">
<input type="checkbox" v-model="todo.done" />
{{ todo.task }}
</li>
</ul>
</main>
</template>

データはメモリ内に保持されているため、ブラウザを更新したり閉じたりするとデータは消えてきまいます。しかし、ファイルにデータを保存する方法もあります。
In-Memoryデータの保存
保存するためには dumpDataDir メソッドを使って、データを tarball 形式で書き出し、それを保存できます。dbインスタンス作成時にtarballを指定することで保存したデータを読み込むことができます。
<script setup lang="ts">
(略)
const url = ref('')
const dumpAsync = async () => {
const file = await db.dumpDataDir()
url.value = URL.createObjectURL(file)
}
const blob = ref<File | null>(null)
const getFile = async () => {
const fileInput = document.getElementById('file') as HTMLInputElement
if (fileInput.files && fileInput.files.length > 0) {
blob.value = fileInput.files[0]
db = new PGlite({ loadDataDir: blob.value })
await getAsync()
}
}
</script>
<template>
<main>
(略)
<div v-if="url !== ''">
<a :href="url" download="pgdata.tar.gz">{{ url }}</a>
</div>
<div>
<input type="file" id="file" v-on:change="getFile" />
</div>
</main>
</template>
Dumpボタンを押下すると、ダウンロード用のURLが画面に表示されるので、クリックしてデータを保存します。(拡張子はデフォルトで .tar.gz )

保存したデータを読み込むと、追加した「o」タスクが確認できます。

保存したデータを展開すると以下のような形式となっています。

IndexedDBの利用
データを永続化するにはブラウザのIndexedDBを活用できます。IndexedDBを利用するためには、PGliteインスタンス作成時に「idb://{DB名}」を指定します。
const db = new PGlite('idb://testdb')
基本的な操作方法は In-Memory の場合と同じですが、「idb://{DB名} 」を指定することで自動的に IndexedDB に保存されます
初回ロード時にデータを挿入しているので、画面を更新するたびに3つのデータが重複して追加されてしまいますが、ロード直前に追加したtestタスクが保存されていることが分かります。

開発者ツールの「Application」からIndexedDBの内容を確認できます。

PGlite REPL
PGliteには、ブラウザ上でインタラクティブにSQLを実行できる REPL(Read-Eval-Print Loop) 機能もあります
インストール
npm install @electric-sql/pglite-repl
設定
main.tsに以下の設定を追加します。
app.config.compilerOptions.isCustomElement = (tag) => {
return tag.startsWith('pglite--')
}
実装
以下のモジュールをインポートして、replコンポーネントを追加するだけで使用できます。
import '@electric-sql/pglite-repl/webcomponent'
<template>
<main>
(略)
<div>
<pglite-repl :pg="db" />
</div>
</main>
</template>
SQLを実行するだけでなく、インテリセンスもききます。以下は、IndexedDBに保存されたデータを確認した結果です。また、テーブル名を入力しようとするときに、候補が表示されていることも分かります。

最後に
PGliteを使うと、ブラウザやNode.js上でPostgreSQLを簡単に動作させることができます。
- In-Memoryでのデータ操作
- IndexedDBによるデータの永続化
- ブラウザ上でSQLを実行できるREPL
設定も簡単ですぐに試すことができました。PGliteには他にも便利な機能があります。ReactやVueのプロジェクトでは専用のライブラリも用意されていますので、次回試してみたいと思います。
コメント