Безумные штуки иногда можно найти в интернете. Листая 2024 JavaScript rising stars (https://risingstars.js.org/2024/en#section-all) обнаружил там удивительного зверя — Postgres скомпилированный через emcc в WASM версию, и допиленный до состояния, когда его можно запустить внутри JS-процесса (браузер/Node.js/Bun/etc).
PGlite уже упоминался на Хабре (https://habr.com/ru/companies/postgrespro/articles/828950/), но я решил, что он так крут, что заслуживает отдельной небольшой статьи.
TL;DR: Представьте себе полноценный PostgreSQL, работающий в браузере (или в Node.js, Bun, Deno) без необходимости поднимать отдельный сервер или встраивать Linux-образ. Проект PGlite реализует эту идею — всего лишь 3 МБ (в сжатом виде), и причем, с поддержкой дефолтных популярных расширений, типа pgvector.
Что это такое?
PGlite — это PostgreSQL скомпилированный в WebAssembly и упакованный в простую TypeScript/JavaScript-библиотеку. Его ключевая фишка — отсутствие «линуксового» виртуального окружения, то есть вы не тянете за собой целый образ OS. В результате получаем:
-
Минимальный размер — около 3 МБ в сжатом виде.
-
Удобный API — просто импортируете библиотеку и вызываете методы для работы с базой. Можно подключить вашу любимую ORMку типа Drizzle/TypeORM.
-
Поддержку расширений — в поставку уже входят некоторые популярные плагины, вроде pgvector.
Можно использовать PGlite как обычную in-memory базу (данные хранятся в памяти и пропадают при перезапуске), а можно включить постоянное хранение — IndexedDB в браузере или файловую систему в Node.js/Bun/Deno.
Как это всё вообще работает?
Обычно PostgreSQL работает в многопоточном режиме помощью процессов: при новом подключении форкается отдельный процесс, чтобы обрабатывать запросы. Но в Emscripten (C->WASM) и в JavaScript у нас нет возможности делать fork().
Однако у Postgres есть single user mode. Он изначально задумывался для рекавери, восстановления БД, но отлично подошёл как раз для PGlite: чтобы не плодить процессы и просто работать в одном потоке. Эту часть и взяли за основу, адаптировав ввод-вывод и окружение под WebAssembly.
В результате PGlite запускается как обычная библиотека, а дальше вы пользуетесь SQL так же, как и в «настоящем» Postgres. Разница лишь в том, что доступен только один коннект и один юзер.
Как пользоваться этим чудом в браузере?
Для начала, надо поставить пакет:
npm install @electric-sql/pglite
или импортировать, если вы в браузере:
import { PGlite } from "https://cdn.jsdelivr.net/npm/@electric-sql/pglite/dist/index.js";
Далее — классический пример in-memory базы:
import { PGlite } from "@electric-sql/pglite"; const db = new PGlite(); const result = await db.query("SELECT 'Привет Хабр!' AS message;"); console.log(result); // -> { rows: [ { message: "Привет Хабр!" } ] }
Чтобы сохранять данные между перезагрузками (в IndexedDB), нужно при инициализации указать путь:
const db = new PGlite("idb://my-pgdata"); // Данные останутся в IndexedDB
Как пользоваться в Node/Bun/Deno?
Тут всё схоже: ставим пакет и подключаем:
npm install @electric-sql/pglite
или (для любителей булочек):
bun install @electric-sql/pglite
или (для любителей секьюрных сред):
deno add npm:@electric-sql/pglite
базовое использование точно такое же, как и в браузере:
import { PGlite } from "@electric-sql/pglite"; const db = new PGlite(); // in-memory await db.query("SELECT 'Привет, Хабр!' AS message;");
но на сервере у нас есть возможность указать путь к файлу, чтобы сохранять данные:
const db = new PGlite("./path/to/pgdata");
Теперь ваши таблицы и записи будут лежать в локальной файловой системе и не потеряются после перезапуска.
Зачем оно вообще нужно?
-
Быстрое тестирование и прототипирование. Не всегда хочется тащить громоздкий Postgres-сервер ради пары тестовых запросов. Идеально, чтобы гонять тесты — не надо громоздить docker-Postgres ради того, чтобы прогнать юнит-тесты — PGlite идеально подойдёт для мокинга реальной базы (потому что он и есть реальная база 🙂
-
Демо и учебные проекты. Отлично подходит, когда нужно показать работу базы данных без установки дополнительного ПО.
-
«Local-first» приложения. Можно хранить данные прямо в браузере, а потом синхронизировать их, когда появится соединение с внешней СУБД.
-
Песочницы и эксперименты. Удобно запускать SQL-скрипты и эксперименты в изолированной среде, не трогая основную базу данных.
Примеры кода
Ниже несколько коротких демок:
// Создаём таблицу await db.query(` CREATE TABLE users ( id SERIAL PRIMARY KEY, name TEXT NOT NULL ); `); // Вставляем данные await db.query("INSERT INTO users (name) VALUES ('Васян'), ('Лёха')"); // Смотрим, сколько записей const { rows } = await db.query("SELECT COUNT(*) AS total FROM users"); console.log(rows); // -> [ { total: "2" } ] // А теперь вернём сами записи const { rows: allUsers } = await db.query("SELECT * FROM users"); console.log(allUsers); // -> [ { id: 1, name: "Васян" }, { id: 2, name: "Лёха" } ]
И всё это работает прямо в вашем браузере или Node.js. Да, я сказал это уже раз 100, но блин, это же реально просто офигенно 🙂
Итого
PGlite — это простой и клёвый способ получить всю мощь Postgres в одну строчку кода. Подходит для быстрых экспериментов, учебных задач, легковесных демо и «офлайн-приложений». Если вам нужен «настоящий PostgreSQL», но без виртуальных машин, докеров, и прочих обвесок — это именно оно.
P.S. Сборка Postgres в WebAssembly во многом основана на работе Stas Kelvich из Neon. Заходите в репозиторий, если интересно, как «под капотом» выглядит форк PostgreSQL под WASM.
P.P.S. 2025 год на дворе, как же без рекламы канала? собсна, я тоже сделал тг-канал. там я отвратительно себя веду, много матерюсь, но часто пишу всякое полезное про техно-фаундерство, AI, и прочее: как про мои opensource-либы, так и про то, как я укус за укусом прогрызаю свой путь в этом вашем медиа-пространстве. Подписывайтесь!
ссылка на оригинал статьи https://habr.com/ru/articles/873112/
Добавить комментарий