SQLite Wasm dans le navigateur reposant sur le système de fichiers privé d'origine

Utilisez SQLite pour gérer efficacement tous vos besoins de stockage sur le Web.

SQLite est un système de gestion de base de données relationnelle intégré, léger, Open Source et populaire. De nombreux développeurs l'utilisent pour stocker des données de manière structurée et facile à utiliser. En raison de sa petite taille et de ses faibles besoins en mémoire, SQLite est souvent utilisé comme moteur de base de données dans les appareils mobiles, les applications de bureau et les navigateurs Web.

L'une des principales caractéristiques de SQLite est qu'il s'agit d'une base de données sans serveur, ce qui signifie qu'il ne nécessite pas de processus de serveur distinct pour fonctionner. Au lieu de cela, la base de données est stockée dans un seul fichier sur l'appareil de l'utilisateur, ce qui facilite son intégration dans les applications.

Logo SQLite.

SQLite basé sur Web Assembly

Il existe plusieurs versions non officielles de SQLite basées sur WebAssembly (Wasm), qui permettent de l'utiliser dans les navigateurs Web, par exemple sql.js. Le sous-projet sqlite3 WASM/JS est la première initiative officiellement associée au projet SQLite visant à faire des versions Wasm de la bibliothèque des membres établis de la famille des livrables SQLite compatibles. Les objectifs concrets de ce projet sont les suivants :

  • Liaison d'une API sqlite3 de bas niveau aussi proche que possible de celle de C en termes d'utilisation.
  • Une API orientée objet de niveau supérieur, plus proche de sql.js et des implémentations de style Node.js, qui communique directement avec l'API de bas niveau. Cette API doit être utilisée à partir du même thread que l'API de bas niveau.
  • Une API basée sur les workers qui communique avec les API précédentes via des messages de worker. Celle-ci est destinée à être utilisée dans le thread principal, avec les API de niveau inférieur installées dans un thread Worker et communiquant avec elles via des messages Worker.
  • Variante basée sur les promesses de l'API Worker, qui masque entièrement les aspects de communication multithread à l'utilisateur.
  • Prise en charge du stockage persistant côté client à l'aide des API JavaScript disponibles, y compris le système de fichiers privés d'origine (OPFS).

Utiliser SQLite Wasm avec le backend de persistance Origin Private File System

Installer la bibliothèque à partir de npm

Installez le package @sqlite.org/sqlite-wasm depuis npm avec la commande suivante :

npm install @sqlite.org/sqlite-wasm

Système de fichiers privés d'origine

Le système de fichiers privés d'origine (OPFS, qui fait partie de l'API File System Access) est complété par une surface spéciale qui permet d'accéder aux données de manière très performante. Cette nouvelle surface diffère des surfaces existantes en offrant un accès en écriture exclusif et sur place au contenu d'un fichier. Ce changement, associé à la possibilité de lire de manière cohérente les modifications non vidées et à la disponibilité d'une variante synchrone sur des workers dédiés, améliore considérablement les performances et débloque de nouveaux cas d'utilisation.

Comme vous pouvez l'imaginer, le dernier point des objectifs du projet, "Prise en charge du stockage persistant côté client à l'aide des API JavaScript disponibles", s'accompagne d'exigences strictes en termes de performances concernant la persistance des données dans le fichier de base de données. C'est là que le système de fichiers privés d'origine, et plus précisément la méthode createSyncAccessHandle() des objets FileSystemFileHandle, entrent en jeu. Cette méthode renvoie une promesse qui se résout en un objet FileSystemSyncAccessHandle pouvant être utilisé pour lire et écrire dans un fichier de manière synchrone. La nature synchrone de cette méthode présente des avantages en termes de performances, mais elle n'est donc utilisable que dans des Web Workers dédiés pour les fichiers du système de fichiers privé d'origine, afin que le thread principal ne puisse pas être bloqué.

Définir les en-têtes requis

Parmi d'autres fichiers, l'archive SQLite Wasm téléchargée contient les fichiers sqlite3.js et sqlite3.wasm, qui constituent la compilation sqlite3 WASM/JS. Le répertoire jswasm contient les livrables sqlite3 de base, et le répertoire de premier niveau contient des applications de démonstration et de test. Les navigateurs ne diffusent pas les fichiers Wasm à partir des URL file://. Par conséquent, toutes les applications que vous créez avec cette fonctionnalité nécessitent un serveur Web. Ce serveur doit inclure les en-têtes suivants dans sa réponse lors de la diffusion des fichiers :

  • Cross-Origin-Opener-Policy défini sur l'instruction same-origin, qui isole le contexte de navigation exclusivement aux documents de même origine. Les documents d'origine croisée ne sont pas chargés dans le même contexte de navigation.
  • Cross-Origin-Embedder-Policy est défini sur la directive require-corp. Par conséquent, un document ne peut charger que des ressources provenant de la même origine ou des ressources explicitement marquées comme pouvant être chargées à partir d'une autre origine.

Ces en-têtes sont nécessaires, car SQLite Wasm dépend de SharedArrayBuffer. La définition de ces en-têtes fait partie de ses exigences de sécurité.

Si vous inspectez le trafic avec les outils de développement, vous devriez trouver les informations suivantes :

Les deux en-têtes mentionnés ci-dessus, Cross-Origin-Embedder-Policy et Cross-Origin-Opener-Policy, mis en évidence dans les outils pour les développeurs Chrome.

Test de débit

L'équipe SQLite a effectué des benchmarks sur son implémentation WebAssembly par rapport à Web SQL, qui est obsolète. Ces benchmarks montrent que SQLite Wasm est généralement aussi rapide que Web SQL. Parfois, c'est un peu plus lent, parfois un peu plus rapide. Pour en savoir plus, consultez la page des résultats.

Exemple de code pour commencer

Comme indiqué précédemment, SQLite Wasm avec le backend de persistance Origin Private File System doit s'exécuter à partir d'un contexte Worker. La bonne nouvelle est que la bibliothèque s'occupe automatiquement de tout cela pour vous et que vous pouvez l'utiliser directement à partir du thread 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);
  }
})();

Démo

Consultez la démonstration pour voir le code ci-dessus en action. N'oubliez pas de consulter le code source sur GitHub. Notez que la version intégrée ci-dessous n'utilise pas le backend OPFS, mais que c'est le cas lorsque vous ouvrez la démo dans un onglet distinct.

Déboguer le système de fichiers privés d'origine

Pour déboguer la sortie du système de fichiers privés d'origine de SQLite Wasm, utilisez l'extension Chrome OPFS Explorer.

Explorateur OPFS dans le Chrome Web Store.

Après avoir installé l'extension, ouvrez les outils pour les développeurs Chrome, sélectionnez l'onglet Explorateur OPFS, puis vous êtes prêt à inspecter ce que SQLite Wasm écrit dans le système de fichiers privés d'origine.

Extension Chrome OPFS Explorer affichant la structure du système de fichiers privés d&#39;origine de l&#39;application de démonstration.

Si vous sélectionnez l'un des fichiers dans la fenêtre de l'explorateur OPFS des outils de développement, vous pouvez l'enregistrer sur le disque local. Vous pouvez ensuite utiliser une application telle que SQLite Viewer pour inspecter la base de données et vous assurer que SQLite Wasm fonctionne comme prévu.

Application SQLite Viewer utilisée pour ouvrir un fichier de base de données à partir de la démo SQLite Wasm.

Obtenir de l'aide et envoyer des commentaires

SQLite Wasm est développé et géré par la communauté SQLite. Obtenez de l'aide et envoyez des commentaires en effectuant des recherches et en publiant des messages sur le forum d'assistance. La documentation complète est disponible sur le site SQLite.