Dans cet article, nous explorerons comment utiliser OPFS pour stocker des fichiers directement sur l’appareil de l’utilisateur et pourquoi il est idéal pour la confidentialité et de bonnes expériences hors ligne sur les sites Web.
Aux débuts du Web, les cookies étaient le seul moyen permettant aux sites Web de stocker des données sur l’appareil d’un utilisateur. Ils étaient principalement conçus pour une utilisation côté serveur, plafonnés à 4 Ko par cookie, et étaient automatiquement envoyés avec chaque requête HTTP.
Avec l’augmentation des besoins de stockage et les sites Web devenant plus interactifs, l’API Web Storage a été créée. L’API Web Storage, via les objets localStorage et sessionStorage, permettait aux sites Web de stocker davantage de données localement sur les navigateurs des utilisateurs (jusqu’à 5 Mo). Mais contrairement aux cookies, les données ne sont pas incluses dans chaque requête HTTP, ce qui signifie que les données stockées sont plus sécurisées et que le site Web aura de meilleures performances. Même si l’API Web Storage est excellente, elle ne peut stocker que des chaînes, ne dispose pas d’un système d’accès aux fichiers structuré et n’est pas conçue pour les données volumineuses, en particulier avec la récente explosion des données.
Puis vint Base de données indexéequi permet aux applications Web de stocker de grandes quantités de données structurées (plus de 100 Mo), comme des objets, des tableaux et même des fichiers directement sur l’appareil de l’utilisateur à l’aide d’une base de données système clé-valeur. Il est encore largement utilisé, mais il n’est pas adapté aux débutants et son API est longue et répétitive, et le stockage des fichiers réels n’est pas simple.
Pour résoudre ces problèmes, nous disposons désormais d’Origin Private File System (OPFS), un système simple basé sur des fichiers exposé via une API qui permet aux applications Web d’accéder à un système d’accès aux fichiers structuré directement sur l’appareil de l’utilisateur. Il permet d’écrire et de lire des fichiers volumineux (300+ Mo) de toutes sortes et même des dossiers sans jamais avoir besoin de les envoyer à un serveur.
Dans cet article, nous explorerons comment utiliser OPFS pour stocker des fichiers directement sur l’appareil de l’utilisateur et pourquoi c’est idéal pour la confidentialité et de bonnes expériences hors ligne sur les sites Web.
Qu’est-ce qu’OPFS ?
OPFS est un type spécial de stockage qui réside dans le navigateur et fait partie de l’API d’accès au système de fichiers. Ce qui rend OPFS unique, c’est qu’il est privé par rapport à l’origine de votre site Web, un peu comme un dossier caché que seul votre site peut voir et utiliser.
Contrairement au système de fichiers habituel sur nos ordinateurs, OPFS est virtuel. L’utilisateur ne voit pas et n’interagit pas directement avec les fichiers.
OPFS fonctionne uniquement dans des contextes sécurisés (c’est-à-dire via HTTPS) et lors de tests sur localhost. Les données stockées persistent lors des redémarrages du navigateur, tout comme l’enregistrement d’un fichier sur un disque dur.
Vous n’avez pas non plus besoin de demander l’autorisation d’utiliser OPFS, car aucun sélecteur de fichier ni fenêtre contextuelle n’est impliqué. Votre application peut lire et écrire librement sur OPFS en arrière-plan. Tout comme les autres API de stockage du navigateur, OPFS est soumis aux restrictions de quota de stockage du navigateur. La limite n’est pas un nombre fixe, mais selon l’appareil et le navigateur, elle se situe généralement entre 300 Mo et plusieurs gigaoctets. Le navigateur allouera dynamiquement un quota de stockage en fonction de la capacité de stockage de l’appareil, de l’espace utilisé, de la fréquence de visite du site, etc. Vous pouvez vérifier l’espace de stockage utilisé par OPFS via navigator.storage.estimate().
Avantages de l’OPFS
- Invisible pour l’utilisateur – Agit comme un dossier virtuel auquel seule votre application peut accéder
- Aucune autorisation requise – Vous n’avez pas besoin de demander l’accès à l’utilisateur
- Portée d’origine – Seul votre site Web (sur votre domaine) peut voir ses fichiers
- Persistant – Les données restent même après la fermeture ou le redémarrage du navigateur
- Structuré comme un vrai système de fichiers – Vous pouvez créer des dossiers, lire/écrire des fichiers et stocker du texte et des données binaires
Cas d’utilisation d’OPFS
- Créer des applications hors ligne qui fonctionnent correctement hors ligne et se synchronisent plus tard en ligne
- Jeux par navigateur qui doivent stocker des fichiers d’état de jeu volumineux pour une lecture hors ligne
- Gestion de documents personnels comme les applications de prise de notes
- Optimisation des applications de montage vidéo/audio basées sur le Web
- Optimisation des éditeurs de fichiers Web
Comment accéder à l’OPFS
Pour accéder à OPFS, nous devons accéder au répertoire racine. Pour ce faire, nous devons appeler navigator.storage.getDirectory()qui est une fonction qui renvoie un objet appelé FileSystemDirectoryHandle. Cet objet représente le répertoire racine de votre OPFS.
L’objet FileSystemDirectoryHandle
Alors que le FileSystemDirectoryHandle L’objet représente le répertoire racine au sein de l’OPFS dans ce contexte, sa signification n’est pas exclusive à OPFS. Le FileSystemDirectoryHandle L’objet fait partie de l’API d’accès au système de fichiers plus large et peut représenter n’importe quel répertoire en fonction de la manière dont vous l’obtenez.
Les deux principales façons d’obtenir un FileSystemDirectoryHandle l’objet comprend :
- Via
navigator.storage.getDirectory()– où il représenterait désormais la racine de votre OPFS - Via le sélecteur de fichiers
window.showDirectoryPicker()– où il représenterait désormais un véritable répertoire sur l’appareil local de l’utilisateur
Par tous les autres moyens, nous pouvons obtenir un FileSystemDirectoryHandle représenterait un sous-répertoire (enfant ou racine) de l’une ou l’autre des deux méthodes principales. Dans le contexte où le FileSystemDirectoryHandle l’objet représente la racine de notre OPFS, le FileSystemDirectoryHandle L’objet expose des méthodes qui nous permettent d’effectuer des opérations telles que :
- Création ou accès à des fichiers :
getFileHandle(fileName, options) - Création ou accès à des sous-répertoires :
getDirectoryHandle() - Suppression de fichiers ou de répertoires :
removeEntry() - Contenu de la liste : pour wait (entrée const de dirHandle.values())
Conditions préalables
Pour suivre ce didacticiel, vous devez être familier avec les bases du HTML, du CSS et du JavaScript.
Prise en charge du navigateur OPFS
Bien que le système de fichiers privés Origin puisse être pris en charge par la plupart des navigateurs modernes, il fonctionne principalement dans les navigateurs basés sur Chromium (comme Chrome et Edge).
Ce que nous construisons
Dans cet article, nous allons créer une application de bloc-notes simple qui stocke les fichiers de notes texte (.txt) dans l’OPFS et les conserve même après l’actualisation de la page ou lorsque le navigateur se ferme.
L’application Bloc-notes aura une entrée pour le titre, qui deviendra le nom du fichier, un corps pour la note elle-même, un bouton « Enregistrer la note » et un bouton « Actualiser les notes ».
Toutes les notes enregistrées dans l’OPFS seront également répertoriées afin que nous puissions voir ce que nous enregistrons. Chaque note enregistrée aura également un bouton « Charger la note » qui lit la note depuis l’OPFS et un bouton « Supprimer la note » qui supprime le fichier de l’OPFS.
Configuration du projet
- Tout d’abord, créez un dossier dans lequel cette application vivra. j’appellerai mon dossier
notesApp. - Lancez ensuite votre éditeur de code et ouvrez ce dossier créé.
- Créez un fichier vide appelé
app.html. - Ouvrir
app.htmldans un contexte de domaine sécurisé ou testez avec localhost comme nous le ferons dans ce guide en utilisant le VS Code Live Server.
Construire une interface utilisateur de base
Commençons par créer une interface utilisateur. Ajoutez ce qui suit à votre app.html déposer:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Mini Notepad (OPFS)</title>
<style>
body {
font-family: sans-serif;
padding: 2rem;
max-width: 600px;
margin: auto;
}
input,
textarea {
width: 100%;
margin-bottom: 1rem;
padding: 0.5rem;
}
button {
margin-right: 0.5rem;
margin-top: 0.5rem;
padding: 0.5rem 1rem;
}
.status {
margin-top: 1rem;
color: green;
}
ul {
list-style: none;
padding: 0;
}
li {
margin-bottom: 0.5rem;
}
</style>
</head>
<body>
<h1>Mini Notepad (OPFS)</h1>
<input type="text" id="title" placeholder="Enter note title..." />
<textarea id="note" placeholder="Compose your note here..."></textarea>
<button>Save Note</button>
<button>Refresh Notes List</button>
<section>
<h2>Saved Notes</h2>
<ul id="notes-list"></ul>
</section>
<div class="status" id="status"></div>
<script>
const notesListEl = document.getElementById("notes-list");
const statusEl = document.getElementById("status");
const titleEl = document.getElementById("title");
const noteEl = document.getElementById("note");
function showStatus(msg) {
statusEl.textContent = msg;
}
</script>
</body>
</html>
Nous avons créé une page Web standard HTML et CSS de base. Nous avons également une section de notes enregistrées qui affichera tous les fichiers de notes enregistrés dans OPFS et un statut div élément qui contiendra tous les messages de réussite ou d’erreur afin que nous n’ayons pas à utiliser la console.
Dans notre script, nous avons référencé par ID tous les éléments de notre application pouvant être mis à jour ou copiés dynamiquement via notre script. Et enfin, nous avons créé un showStatus fonction qui met à jour notre status élément avec le message que nous produisons.
Maintenant, lancez app.html avec VS Code Live Server et vous devriez avoir une interface qui ressemble à ceci :
Accès au répertoire racine OPFS
Ajoutez ce qui suit à votre app.html déposer:
async function getOPFSRoot() {
if (!("storage" in navigator && "getDirectory" in navigator.storage)) {
alert("OPFS is not supported in this browser.");
throw new Error("OPFS not supported");
}
return await navigator.storage.getDirectory();
}
Pour accéder au répertoire racine OPFS, nous avons créé une fonction asynchrone appelée getOPFSRoot().
La fonction vérifie d’abord si OPFS est pris en charge dans le navigateur que vous utilisez, puis appelle navigator.storage.getDirectory()qui obtient les OPFS FileSystemDirectoryHandle et le renvoie.
En faisant cela, chaque fois que nous appelons getOPFSRoot() n’importe où dans app.htmlnous avons accès au répertoire racine OPFS.
Comment stocker un fichier dans OPFS
Ajoutez ce qui suit à votre app.html déposer:
async function saveNote() {
const title = titleEl.value.trim();
const content = noteEl.value;
if (!title) return showStatus("Please enter a title.");
try {
const root = await getOPFSRoot();
const handle = await root.getFileHandle(`${title}.txt`, { create: true });
const writable = await handle.createWritable();
await writable.write(content);
await writable.close();
showStatus(`Note '${title}' saved.`);
loadNotesList();
} catch (err) {
console.error(err);
showStatus("Error saving note.");
}
}
Pour stocker un fichier de notes, nous avons créé une fonction appelée saveNote() qui contient la logique afin que nous puissions appeler le saveNote() fonctionner quand nous le voulons. La fonction nettoiera d’abord le title valeur d’entrée car le titre que nous fournissons deviendra le nom du fichier texte que nous enregistrerons.
Notre fonction renverra un statut d’erreur si l’entrée du titre est vide car chaque fichier doit avoir un nom pour être enregistré. Ensuite, nous appelons notre getOPFSRoot() fonction qui, grâce à FileSystemDirectoryHandlenous donne accès au getFileHandle(fileName, options) fonction.
Le getFileHandle() peut obtenir un handle sur un fichier existant ou, comme dans ce cas create: truecréez un nouveau fichier appelé {title}.txt.
Ensuite, nous ouvrons le {title}.txt fichier avec handle.createWritable()tout en utilisant toujours la même poignée.
Cela revient à ouvrir un fichier normal sur votre PC lorsque vous souhaitez le modifier. Nous écrivons ensuite le contenu de notre note dans le fichier avec wait writable.write(content). Ici, content est une référence à la valeur du <textarea> élément, qui est le corps de notre note.
Enfin, nous appelons wait writable.close()qui ferme le fichier et finalise par conséquent l’édition/écriture du fichier.
Il est important de noter que l’ouverture d’un fichier ne modifie pas le fichier jusqu’à ce que vous appeliez .close(). Cela évite que les fichiers soient à moitié écrits.
Liste de tous les fichiers enregistrés dans OPFS
Ajoutez ce qui suit à votre app.html déposer:
async function loadNotesList() {
try {
const root = await getOPFSRoot();
notesListEl.innerHTML = "";
for await (const [name, handle] of root.entries()) {
const li = document.createElement("li");
li.innerHTML = `
<strong>${name}</strong>
<button onclick="loadNote('${name}')">Load</button>
<button onclick="deleteNote('${name}')">Delete</button>
`;
notesListEl.appendChild(li);
}
showStatus("Notes list updated.");
} catch (err) {
console.error(err);
showStatus("Error loading notes list.");
}
}
Pour lister tous les fichiers enregistrés dans OPFS, il faut à nouveau accéder au répertoire racine d’OPFS via notre fonction getOPFSRoot()où sont stockés tous les fichiers. Ensuite, nous parcourons tous les fichiers et dossiers du répertoire racine, et chaque entrée de la boucle a un name et un handle. Le handle est l’objet que vous pouvez utiliser pour lire/charger ou écrire dans le fichier.
À ce stade, nous parcourons simplement chaque fichier du répertoire OPFS et les affichons tous sur notre Saved Notes section.
Je vais maintenant tenter de sauvegarder deux notes dans l’OPFS.
Lire un fichier depuis OPFS
Ajoutez ce qui suit à votre app.html déposer:
async function loadNote(title) {
try {
const root = await getOPFSRoot();
const handle = await root.getFileHandle(`${title}`);
const file = await handle.getFile();
const content = await file.text();
titleEl.value = title.replace(".txt", "");
noteEl.value = content;
showStatus(`Note '${title}' loaded.`);
} catch (err) {
console.error(err);
showStatus("Error loading note.");
}
}
Lire un fichier signifie charger le fichier et accéder à son contenu, généralement pour l’afficher ou le modifier. Dans notre cas, nous faisons cela en utilisant une fonction d’assistance appelée loadNote(title)où titre est le nom de la note (c’est-à-dire le nom du fichier).
Nous procédons à l’obtention à nouveau du handle du répertoire racine en utilisant getOPFSRoot() et obtenez la référence du descripteur de fichier du fichier avec lequel nous voulons lire getFileHandle(title)où title est le nom de la note.
Nous ouvrons le fichier avec getFile() puis utilisez file.text() pour analyser la note enregistrée sous forme de chaîne afin que nous puissions copier ce contenu dans une variable.
Nous remplissons enfin le correspondant value champ afin que l’utilisateur puisse afficher ou modifier la note.
Allons-y et lisons les deux fichiers que nous avons créés dans l’interface utilisateur.
Suppression d’un fichier d’OPFS
Ajoutez ce qui suit à votre app.html déposer:
async function deleteNote(title) {
if (!confirm(`Delete note '${title}'?`)) return;
try {
const root = await getOPFSRoot();
await root.removeEntry(`${title}`);
showStatus(`Note '${title}' deleted.`);
loadNotesList();
} catch (err) {
console.error(err);
showStatus("Error deleting note.");
}
}
Supprimer un fichier d’OPFS signifie supprimer complètement le fichier d’OPFS. Pour ce faire, nous avons créé une fonction d’assistance nommée deleteNote(title). La fonction d’assistance implémente d’abord une invite de reconfirmation standard à l’aide du navigateur confirm() fonction pour éviter toute suppression involontaire, car sans elle, OPFS supprimera le fichier sans avertissement.
Nous accédons à notre répertoire racine et utilisons le handle de référence pour appeler removeEntry(title)ce qui supprime le fichier fourni en paramètre.
Essayons de supprimer les deux fichiers enregistrés d’OPFS.
Rassembler tout cela
Actualisez les notes enregistrées affichées en appelant loadNotesList() chaque fois qu’une manipulation arrive à l’OPFS. Cela permet d’éviter la duplication des fichiers.
Ton app.html le fichier devrait ressembler à ceci :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Mini Notepad (OPFS)</title>
<style>
body {
font-family: sans-serif;
padding: 2rem;
max-width: 600px;
margin: auto;
}
input,
textarea {
width: 100%;
margin-bottom: 1rem;
padding: 0.5rem;
}
button {
margin-right: 0.5rem;
margin-top: 0.5rem;
padding: 0.5rem 1rem;
}
.status {
margin-top: 1rem;
color: green;
}
ul {
list-style: none;
padding: 0;
}
li {
margin-bottom: 0.5rem;
}
</style>
</head>
<body>
<h1>Mini Notepad (OPFS)</h1>
<input type="text" id="title" placeholder="Enter note title..." />
<textarea id="note" placeholder="Compose your note here..."></textarea>
<button onclick="saveNote()">Save Note</button>
<button onclick="loadNotesList()">Refresh Notes List</button>
<section>
<h2>Saved Notes</h2>
<ul id="notes-list"></ul>
</section>
<div class="status" id="status"></div>
<script>
const notesListEl = document.getElementById("notes-list");
const statusEl = document.getElementById("status");
const titleEl = document.getElementById("title");
const noteEl = document.getElementById("note");
async function getOPFSRoot() {
if (!("storage" in navigator && "getDirectory" in navigator.storage)) {
alert("OPFS is not supported in this browser.");
throw new Error("OPFS not supported");
}
return await navigator.storage.getDirectory();
}
async function saveNote() {
const title = titleEl.value.trim();
const content = noteEl.value;
if (!title) return showStatus("Please enter a title.");
try {
const root = await getOPFSRoot();
const handle = await root.getFileHandle(`${title}.txt`, {
create: true,
});
const writable = await handle.createWritable();
await writable.write(content);
await writable.close();
showStatus(`Note '${title}' saved.`);
loadNotesList();
} catch (err) {
console.error(err);
showStatus("Error saving note.");
}
}
async function loadNotesList() {
try {
const root = await getOPFSRoot();
notesListEl.innerHTML = "";
for await (const [name, handle] of root.entries()) {
const li = document.createElement("li");
li.innerHTML = `
<strong>${name}</strong>
<button onclick="loadNote('${name}')">Load</button>
<button onclick="deleteNote('${name}')">Delete</button>
`;
notesListEl.appendChild(li);
}
showStatus("Notes list updated.");
} catch (err) {
console.error(err);
showStatus("Error loading notes list.");
}
}
async function loadNote(title) {
try {
const root = await getOPFSRoot();
const handle = await root.getFileHandle(`${title}`);
const file = await handle.getFile();
const content = await file.text();
titleEl.value = title.replace(".txt", "");
noteEl.value = content;
showStatus(`Note '${title}' loaded.`);
} catch (err) {
console.error(err);
showStatus("Error loading note.");
}
}
async function deleteNote(title) {
if (!confirm(`Delete note '${title}'?`)) return;
try {
const root = await getOPFSRoot();
await root.removeEntry(`${title}`);
showStatus(`Note '${title}' deleted.`);
loadNotesList();
} catch (err) {
console.error(err);
showStatus("Error deleting note.");
}
}
function showStatus(msg) {
statusEl.textContent = msg;
}
loadNotesList();
</script>
</body>
</html>
Problèmes de stockage
Il est important de noter que même si OPFS peut être généreux avec ses limites de stockage, vous ne devez stocker que ce dont vous avez besoin, car le navigateur peut lancer un message. QuotaExceededError si votre application se rapproche du quota de stockage dynamique.
Conclusion
Le système de fichiers privés Origin représente un progrès significatif dans la technologie de stockage structuré par navigateur. Il donne aux développeurs Web la possibilité de créer, lire, écrire et gérer des fichiers volumineux de différents types directement sur l’appareil d’un utilisateur sans dépendre du stockage du serveur.
Comme nous l’avons vu dans cet article, OPFS est la solution pour toute application Web que vous créez et qui nécessite un accès aux fichiers structuré, persistant, sécurisé, limité à l’origine et hors ligne.
Source link

