SQLite Wasm en el navegador respaldado por el sistema de archivos privados de origen

Usa SQLite para controlar todas tus necesidades de almacenamiento de manera eficiente en la Web.

SQLite es un sistema de administración de bases de datos relacionales integrado, ligero, de código abierto y popular. Muchos desarrolladores lo usan para almacenar datos de una manera estructurada y fácil de usar. Debido a su tamaño pequeño y a sus bajos requisitos de memoria, SQLite se suele utilizar como motor de base de datos en dispositivos móviles, aplicaciones para computadoras y navegadores web.

Una de las características clave de SQLite es que es una base de datos sin servidor, lo que significa que no requiere un proceso de servidor independiente para operar. En cambio, la base de datos se almacena en un solo archivo en el dispositivo del usuario, lo que facilita su integración en las aplicaciones.

Logotipo de SQLite.

SQLite basado en WebAssembly

Existen varias versiones no oficiales de SQLite basadas en WebAssembly (Wasm), que permiten usarlo en navegadores web, por ejemplo, sql.js. El subproyecto sqlite3 de WASM/JS es el primer esfuerzo asociado oficialmente con el proyecto SQLite para hacer que las compilaciones de Wasm de la biblioteca sean miembros establecidos de la familia de entregables compatibles de SQLite. Los objetivos concretos de este proyecto incluyen lo siguiente:

  • Vincula una API de sqlite3 de bajo nivel que sea lo más parecida posible a la de C en términos de uso.
  • Una API orientada a objetos de nivel superior, más parecida a sql.js y a las implementaciones de estilo Node.js, que se comunica directamente con la API de nivel inferior. Esta API se debe usar desde el mismo subproceso que la API de bajo nivel.
  • Es una API basada en Worker que se comunica con las APIs anteriores a través de mensajes de Worker. Este está diseñado para usarse en el subproceso principal, con las APIs de nivel inferior instaladas en un subproceso de Worker y comunicándose con ellas a través de mensajes de Worker.
  • Es una variante basada en promesas de la API de Worker que oculta por completo los aspectos de la comunicación entre subprocesos al usuario.
  • Compatibilidad con el almacenamiento persistente del cliente a través de las APIs de JavaScript disponibles, incluido el Origin Private File System (OPFS).

Cómo usar SQLite Wasm con el backend de persistencia del sistema de archivos privado del origen

Cómo instalar la biblioteca desde npm

Instala el paquete @sqlite.org/sqlite-wasm desde npm con el siguiente comando:

npm install @sqlite.org/sqlite-wasm

El sistema de archivos privado del origen

El Origin Private File System (OPFS, parte de la API de File System Access) se complementa con una superficie especial que brinda acceso a los datos con un rendimiento muy alto. Esta nueva superficie se diferencia de las existentes porque ofrece acceso de escritura exclusivo y en el lugar al contenido de un archivo. Este cambio, junto con la capacidad de leer de forma coherente las modificaciones no vaciadas y la disponibilidad de una variante síncrona en los trabajadores dedicados, mejora significativamente el rendimiento y desbloquea nuevos casos de uso.

Como puedes imaginar, el último punto de los objetivos del proyecto, la compatibilidad con el almacenamiento persistente del cliente a través de las APIs de JavaScript disponibles, incluye requisitos de rendimiento estrictos con respecto a la persistencia de los datos en el archivo de la base de datos. Aquí es donde entra en juego el Origin Private File System y, más específicamente, el método createSyncAccessHandle() de los objetos FileSystemFileHandle. Este método devuelve una promesa que se resuelve en un objeto FileSystemSyncAccessHandle que se puede usar para leer y escribir en un archivo de forma síncrona. La naturaleza síncrona de este método aporta ventajas de rendimiento, pero, por lo tanto, solo se puede usar dentro de Web Workers dedicados para archivos dentro del Origin Private File System, de modo que no se pueda bloquear el subproceso principal.

Cómo configurar los encabezados obligatorios

Entre otros archivos, el archivo SQLite Wasm descargado contiene los archivos sqlite3.js y sqlite3.wasm, que componen la compilación de sqlite3 WASM/JS. El directorio jswasm contiene los elementos principales de sqlite3, y el directorio de nivel superior contiene apps de demostración y prueba. Los navegadores no entregarán archivos Wasm desde URLs de file://, por lo que cualquier app que compiles con esto requerirá un servidor web, y ese servidor debe incluir los siguientes encabezados en su respuesta cuando entregue los archivos:

El motivo de estos encabezados es que SQLite Wasm depende de SharedArrayBuffer, y establecer estos encabezados forma parte de sus requisitos de seguridad.

Si inspeccionas el tráfico con las Herramientas para desarrolladores, deberías encontrar la siguiente información:

Los dos encabezados mencionados anteriormente, Cross-Origin-Embedder-Policy y Cross-Origin-Opener-Policy, destacados en las Herramientas para desarrolladores de Chrome.

Prueba de velocidad

El equipo de SQLite ejecutó algunas comparativas de su implementación de WebAssembly en comparación con Web SQL, que dejó de estar disponible. Estas comparativas muestran que, en general, SQLite Wasm es casi tan rápido como Web SQL. A veces es un poco más lento y otras, un poco más rápido. Consulta todos los detalles en la página de resultados.

Muestra de código para comenzar

Como se mencionó anteriormente, SQLite Wasm con el backend de persistencia del sistema de archivos privado del origen debe ejecutarse desde un contexto de Worker. La buena noticia es que la biblioteca se encarga automáticamente de todo esto por ti, y puedes usarla directamente desde el subproceso 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);
  }
})();

Demostración

Consulta el código anterior en acción en la demostración. No olvides consultar el código fuente en GitHub. Ten en cuenta que la versión incorporada que se muestra a continuación no usa el backend de OPFS, pero sí lo hace cuando abres la demostración en una pestaña separada.

Depura el sistema de archivos privado del origen

Para depurar el resultado del sistema de archivos privado del origen de SQLite Wasm, usa la extensión de Chrome OPFS Explorer.

OPFS Explorer en Chrome Web Store.

Después de instalar la extensión, abre las Herramientas para desarrolladores de Chrome, selecciona la pestaña OPFS Explorer y podrás inspeccionar lo que SQLite Wasm escribe en el sistema de archivos privado del origen.

Extensión de Chrome de OPFS Explorer que muestra la estructura del sistema de archivos privado del origen de la app de demostración.

Si seleccionas cualquiera de los archivos en la ventana del Explorador de OPFS en Herramientas para desarrolladores, puedes guardarlo en el disco local. Luego, puedes usar una app como SQLite Viewer para inspeccionar la base de datos y asegurarte de que SQLite Wasm realmente funciona como se prometió.

App de SQLite Viewer que se usa para abrir un archivo de base de datos de la demostración de SQLite Wasm.

Obtén ayuda y proporciona comentarios

La comunidad de SQLite desarrolla y mantiene SQLite Wasm. Obtén ayuda y proporciona comentarios buscando y publicando en el foro de asistencia. La documentación completa está disponible en el sitio de SQLite.