Версионирование схемы в Dexie.js является центральным механизмом управления эволюцией структуры данных в браузерных приложениях, особенно в условиях командной разработки, где изменения модели данных происходят параллельно несколькими разработчиками и должны оставаться согласованными между окружениями.
Браузерное хранилище IndexedDB предоставляет ограниченный низкоуровневый API, в котором изменение структуры базы данных требует явного увеличения версии базы. Dexie.js абстрагирует этот механизм через декларативное описание схемы и цепочку версий.
Ключевой принцип:
В командной разработке это означает, что схема становится частью контрактного API между фронтенд-модулями и должна рассматриваться как критически важный элемент версионного контроля.
В Dexie схема задаётся через последовательность версий:
const db = new Dexie("app-db");
db.version(1).stores({
users: "++id, email",
});
db.version(2).stores({
users: "++id, email, createdAt",
});
Каждое изменение структуры таблицы требует новой версии. Это ключевой момент: нельзя изменять старую версию, только добавлять новую.
При переходе между версиями Dexie позволяет определить миграционную логику:
db.version(2).upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
user.createdAt = Date.now();
});
});
В командной разработке миграции выполняют сразу несколько функций:
Наиболее безопасная операция:
db.version(3).stores({
users: "++id, email, createdAt, role",
});
Особенности:
undefined в новом полеОпасная операция, требующая миграции:
db.version(4).stores({
users: "++id, email, role",
});
db.version(4).upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
delete user.createdAt;
});
});
Фактически это комбинация удаления и добавления:
db.version(5).stores({
users: "++id, email, registeredAt",
});
db.version(5).upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
user.registeredAt = user.createdAt;
delete user.createdAt;
});
});
В распределённой разработке несколько разработчиков могут одновременно создавать разные ветки, каждая из которых добавляет свою версию схемы:
Dexie не умеет автоматически разрешать такие конфликты, поэтому схема версий должна рассматриваться как линейная история, аналогичная миграциям в серверных ORM.
Используется централизованный подход:
schema.jsНаиболее устойчивый подход:
db.version(1)
db.version(2)
db.version(3)
db.version(4)
Каждая версия:
В крупных приложениях схема часто разбивается:
db/
schema/
users.js
orders.js
migrations/
1_to_2.js
2_to_3.js
Каждый модуль отвечает за свою часть данных, но версии остаются глобальными. Это создаёт ключевую сложность: локальная модульность vs глобальная версия базы.
Типичные конфликты:
db.version(7) // в двух ветках разные изменения
Решение: ручное перенумерование с анализом зависимостей.
Одна ветка:
orders: "++id, userId, total"
Другая:
orders: "++id, userId, status"
При слиянии требуется объединение:
orders: "++id, userId, total, status"
и миграция для заполнения новых данных.
Если обе ветки изменяют одни и те же данные, требуется:
Миграции должны быть безопасны при повторном запуске логики:
db.version(8).upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
if (!("role" in user)) {
user.role = "user";
}
});
});
Dexie гарантирует последовательное применение версий, но разработческая логика должна учитывать:
Это означает, что версия 10 должна учитывать последствия версий 1–9, даже если они были добавлены разными разработчиками.
В командной разработке критично внедрение автоматических проверок:
При изменении схемы важно учитывать:
Стратегия:
Dexie выполняет миграции в транзакционном контексте, однако:
db.version(9).upgrade(async tx => {
const users = tx.table("users");
await users.toCollection().modify(user => {
user.normalizedEmail = user.email.toLowerCase();
});
});
Версионирование становится архитектурным инструментом:
В зрелых проектах схема Dexie рассматривается как аналог миграций серверной базы данных, с той разницей, что выполняется в клиентской среде и требует более строгой дисциплины из-за отсутствия централизованного контроля над обновлениями клиента.