IndexedDB na prática: armazenamento de arquivos grandes e arquitetura offline no navegador
Por que IndexedDB?
As opções de armazenamento do navegador têm limites claros cada uma:
| Opção | Capacidade | Tipos de dados | API síncrona | Caso de uso |
|---|---|---|---|---|
| Cookie | ~4KB | String | ✅ | Identificadores de sessão |
| localStorage | ~5MB | String | ✅ | Configurações simples |
| sessionStorage | ~5MB | String | ✅ | Estado temporário |
| IndexedDB | Centenas de MB–GB | Quaisquer dados estruturados | ❌ Async | Arquivos grandes, apps offline |
Para sites de ferramentas que precisam armazenar no navegador intermediários de processamento de PDF, módulos WASM ou o histórico de uploads dos usuários, o IndexedDB é a única opção viável.
Conceitos centrais
Banco de dados → Object Store → Registro
Database: "toolsku-cache"
├── ObjectStore: "wasm-modules" (key: moduleName)
├── ObjectStore: "file-cache" (key: fileHash, index: timestamp)
└── ObjectStore: "user-preferences" (key: settingKey)
Transações e concorrência
As transações do IndexedDB são auto-confirmadas, e apenas uma transação de leitura/escrita por Object Store é permitida por vez:
const tx = db.transaction(['file-cache'], 'readwrite');
const store = tx.objectStore('file-cache');
await store.put({ hash: 'abc123', data: arrayBuffer, timestamp: Date.now() });
await tx.done; // Wait for transaction to complete
IndexedDB no ToolsKu
Cache de módulos WASM
O ffmpeg.wasm tem cerca de 30 MB e leva de 3 a 5 segundos para carregar cada vez. Após o cache no IndexedDB, as visitas seguintes são quase instantâneas:
async function getWasmModule(name: string): Promise<ArrayBuffer> {
const cached = await idb.get('wasm-modules', name);
if (cached) return cached;
const response = await fetch(`/wasm/${name}.wasm`);
const buffer = await response.arrayBuffer();
await idb.put('wasm-modules', buffer, name);
return buffer;
}
Armazenamento em fragmentos para arquivos grandes
Armazenar arquivos acima de 50 MB no IndexedDB de uma só vez não é ideal. Uma estratégia de fragmentação:
File (200MB) → split into 4MB chunks → store each in IndexedDB
key: "file:{hash}:chunk:{index}"
Read in order and concatenate → restore full file
Migração de versão
Quando o esquema do banco de dados muda, a migração é tratada em onupgradeneeded:
const request = indexedDB.open('toolsku-cache', 2); // version 2
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (event.oldVersion < 2) {
db.createObjectStore('processing-history', { keyPath: 'id' });
}
};
Boa prática: adicione apenas ObjectStores — nunca os remova. Incremente o número de versão para acionar a migração e evite excluir os dados dos usuários.
IndexedDB vs OPFS
| Característica | IndexedDB | OPFS (Origin Private File System) |
|---|---|---|
| Maturidade da API | Amplo suporte | Chrome 86+ / Safari 15.2+ |
| Modelo de leitura/escrita | Armazenamento chave-valor | Verdadeiro sistema de arquivos |
| Desempenho | Moderado | Maior (especialmente acesso síncrono) |
| Melhor para | Cache estruturado | E/S de arquivos grandes |
O ToolsKu usa principalmente o IndexedDB, com o OPFS como otimização de desempenho no Chrome.
Resumo
O IndexedDB é infraestrutura essencial para ferramentas de navegador offline-first. Um bom design de Object Stores, o cache WASM e as estratégias de armazenamento em fragmentos permitem que o ToolsKu permaneça responsivo mesmo em redes lentas.
Experimente estas ferramentas executadas localmente no navegador — nenhum cadastro necessário →