SQLite Wasm no navegador com suporte do sistema de arquivos particulares de origem

Use o SQLite para lidar com todas as suas necessidades de armazenamento de maneira eficiente na Web.

O SQLite é um sistema de gerenciamento de banco de dados relacional de código aberto, leve e incorporado. Muitos desenvolvedores usam o SQLite para armazenar dados de maneira estruturada e fácil de usar. Devido ao tamanho pequeno e aos requisitos de memória baixos, o SQLite é usado com frequência como um mecanismo de banco de dados em dispositivos móveis, aplicativos para computador e navegadores da Web.

Uma das principais características do SQLite é que ele é um banco de dados sem servidor, o que significa que não exige um processo de servidor separado para operar. Em vez disso, o banco de dados é armazenado em um único arquivo no dispositivo do usuário, facilitando a integração em aplicativos.

Logotipo do SQLite.

SQLite baseado em WebAssembly

Há várias versões não oficiais do SQLite baseadas em Web Assembly (Wasm), permitindo que ele seja usado em navegadores da Web, por exemplo, sql.js. O subprojeto sqlite3 WASM/JS é o primeiro esforço oficialmente associado ao projeto SQLite, tornando os builds Wasm da biblioteca membros estabelecidos da família de entregáveis compatíveis do SQLite. As metas concretas deste projeto incluem:

  • Vinculação de uma API sqlite3 de baixo nível que é o mais próxima possível da API C em termos de uso.
  • Uma API orientada a objetos de nível superior, mais parecida com sql.js e implementações no estilo Node.js, que se comunica diretamente com a API de baixo nível. Essa API precisa ser usada na mesma thread da API de baixo nível.
  • Uma API baseada em worker que se comunica com as APIs anteriores por mensagens do worker. Este é destinado ao uso na linha de execução principal, com as APIs de nível inferior instaladas em uma linha de execução de worker e se comunicando com elas por mensagens de worker.
  • Uma variante baseada em promessas da API Worker que oculta totalmente os aspectos de comunicação entre linhas de execução do usuário.
  • Suporte para armazenamento persistente do lado do cliente usando APIs JavaScript disponíveis, incluindo o Origin Private File System (OPFS).

Como usar o SQLite Wasm com o back-end de persistência do Origin Private File System

Instalar a biblioteca do npm

Instale o pacote @sqlite.org/sqlite-wasm do npm com o seguinte comando:

npm install @sqlite.org/sqlite-wasm

O sistema de arquivos privado da origem

O Origin Private File System (OPFS, parte da API File System Access) é aumentado com uma superfície especial que oferece acesso a dados de alto desempenho. Essa nova superfície difere das atuais por oferecer acesso de gravação exclusivo e no local ao conteúdo de um arquivo. Essa mudança, junto com a capacidade de ler consistentemente modificações não liberadas e a disponibilidade de uma variante síncrona em workers dedicados, melhora significativamente a performance e desbloqueia novos casos de uso.

Como você pode imaginar, o último ponto das metas do projeto, suporte para armazenamento persistente do lado do cliente usando APIs JavaScript disponíveis, vem com requisitos de desempenho rigorosos em relação à persistência de dados no arquivo de banco de dados. É aqui que entra o sistema de arquivos privado de origem e, mais especificamente, o método createSyncAccessHandle() de objetos FileSystemFileHandle. Esse método retorna uma promessa que é resolvida em um objeto FileSystemSyncAccessHandle que pode ser usado para ler e gravar em um arquivo de forma síncrona. A natureza síncrona desse método traz vantagens de desempenho, mas, portanto, ele só pode ser usado em Web Workers dedicados para arquivos no Origin Private File System (OPFS) para que a linha de execução principal não seja bloqueada.

Como definir os cabeçalhos obrigatórios

Entre outros arquivos, o arquivo SQLite Wasm baixado contém os arquivos sqlite3.js e sqlite3.wasm, que compõem o build sqlite3 WASM/JS. O diretório jswasm contém os principais elementos do sqlite3, e o diretório de nível superior contém apps de demonstração e teste. Os navegadores não veiculam arquivos Wasm de URLs file://. Portanto, todos os apps criados com isso exigem um servidor da Web, e esse servidor precisa incluir os seguintes cabeçalhos na resposta ao veicular os arquivos:

O motivo desses cabeçalhos é que o SQLite Wasm depende de SharedArrayBuffer, e a definição deles faz parte dos requisitos de segurança.

Se você inspecionar o tráfego com o DevTools, vai encontrar as seguintes informações:

Os dois cabeçalhos mencionados acima, Cross-Origin-Embedder-Policy e Cross-Origin-Opener-Policy, destacados no Chrome DevTools.

Speedtest

A equipe do SQLite executou alguns comparativos de mercado na implementação do WebAssembly em comparação com o SQL da Web descontinuado. Esses comparativos mostram que o SQLite Wasm é geralmente tão rápido quanto o Web SQL. Às vezes, é um pouco mais lento, às vezes, um pouco mais rápido. Confira todos os detalhes na página de resultados.

Exemplo de código para começar

Como mencionado anteriormente, o SQLite Wasm com o back-end de persistência do Origin Private File System precisa ser executado em um contexto de worker. A boa notícia é que a biblioteca cuida de tudo isso automaticamente, e você pode usá-la diretamente da linha de execução principal.

import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';

(async () => {
  try {
    console.log('Loading and initializing SQLite3 module...');

    const promiser = await new Promise((resolve) => {
      const _promiser = sqlite3Worker1Promiser({
        onready: () => {
          resolve(_promiser);
        },
      });
    });

    console.log('Done initializing. Running demo...');

    let response;

    response = await promiser('config-get', {});
    console.log('Running SQLite3 version', response.result.version.libVersion);

    response = await promiser('open', {
      filename: 'file:worker-promiser.sqlite3?vfs=opfs',
    });
    const { dbId } = response;
    console.log(
      'OPFS is available, created persisted database at',
      response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'),
    );

    await promiser('exec', { dbId, sql: 'CREATE TABLE IF NOT EXISTS t(a,b)' });
    console.log('Creating a table...');

    console.log('Insert some data using exec()...');
    for (let i = 20; i <= 25; ++i) {
      await promiser('exec', {
        dbId,
        sql: 'INSERT INTO t(a,b) VALUES (?,?)',
        bind: [i, i * 2],
      });
    }

    console.log('Query data with exec()');
    await promiser('exec', {
      dbId,
      sql: 'SELECT a FROM t ORDER BY a LIMIT 3',
      callback: (result) => {
        if (!result.row) {
          return;
        }
        console.log(result.row);
      },
    });

    await promiser('close', { dbId });
  } catch (err) {
    if (!(err instanceof Error)) {
      err = new Error(err.result.message);
    }
    console.error(err.name, err.message);
  }
})();

Demonstração

Confira o código acima em ação na demonstração. Confira o código-fonte no GitHub. Observe como a versão incorporada abaixo não usa o back-end OPFS, mas quando você abre a demonstração em uma guia separada, ela usa.

Depurar o sistema de arquivos privados de origem

Para depurar a saída do sistema de arquivos privado de origem do SQLite Wasm, use a extensão do Chrome OPFS Explorer.

OPFS Explorer na Chrome Web Store.

Depois de instalar a extensão, abra o Chrome DevTools, selecione a guia OPFS Explorer e inspecione o que o SQLite Wasm grava no Origin Private File System.

Extensão do Chrome OPFS Explorer mostrando a estrutura do sistema de arquivos privado da origem do app de demonstração.

Se você selecionar qualquer um dos arquivos na janela do OPFS Explorer nas DevTools, poderá salvá-lo no disco local. Em seguida, use um app como o SQLite Viewer para inspecionar o banco de dados e garantir que o SQLite Wasm funciona conforme o esperado.

App SQLite Viewer usado para abrir um arquivo de banco de dados da demonstração do SQLite Wasm.

Receber ajuda e enviar feedback

O SQLite Wasm é desenvolvido e mantido pela comunidade SQLite. Receba ajuda e envie feedback pesquisando e postando no fórum de suporte. A documentação completa está disponível no site do SQLite.