Développer pour les navigateurs modernes et améliorer progressivement ses performances, comme en 2003
En mars 2003, Nick Finck et Steve Champeon a stupéfié le monde de la conception Web avec le concept de amélioration progressive, une stratégie de conception web qui met l'accent sur le chargement du contenu principal de la page web en premier, puis ajoute progressivement des nuanciers et techniquement rigoureuses de présentation et de fonctionnalités en plus du contenu. Alors qu'en 2003, l'amélioration progressive consistait à utiliser, à l'époque, l'utilisation des fonctionnalités CSS, un code JavaScript discret et même simplement des graphiques vectoriels évolutifs. En 2020 et au-delà, l'amélioration progressive concerne l'utilisation des fonctionnalités récentes du navigateur.
<ph type="x-smartling-placeholder">JavaScript moderne
Concernant JavaScript, voici comment fonctionne la compatibilité des navigateurs avec le dernier code JavaScript principal d'ES 2015.
les caractéristiques.
La nouvelle norme inclut les promesses, les modules, les classes, les littéraux de modèle, les fonctions fléchées, let
et const
,
les paramètres par défaut, les générateurs, l'attribution de déstructuration, le repos et les écarts, Map
/Set
,
WeakMap
/WeakSet
, et bien d'autres.
Tous les types d'appareils sont acceptés.
Les fonctions asynchrones, une fonctionnalité d'ES 2017 et l'une de mes préférées,
peuvent être utilisés
dans tous les principaux navigateurs.
Les mots clés async
et await
permettent un comportement asynchrone basé sur des promesses
soit rédigé dans un style plus épuré, en évitant de configurer explicitement des chaînes de promesses.
Même les tout derniers ajouts de langues en ES 2020, comme chaînage facultatif et coalesçage nulliste ont rapidement contacté le service d'assistance. Vous trouverez un exemple de code ci-dessous. Concernant les fonctionnalités JavaScript essentielles, l'herbe est purement verte a lieu aujourd'hui.
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah',
},
};
console.log(adventurer.dog?.name);
// Expected output: undefined
console.log(0 ?? 42);
// Expected output: 0
Application exemple: Fugu Greetings
Pour cet article, je travaille avec une PWA simple, appelée Salutations Fugu (GitHub). Le nom de cette application est un bravo pour Project Fugu 🐡, une initiative visant à offrir tout le Web la puissance des applications Android/iOS/de bureau. Pour en savoir plus sur le projet, consultez son page de destination.
Fugu Greetings est une application de dessin qui vous permet de créer des cartes de vœux virtuelles et d'envoyer à vos proches. Il illustre parfaitement Concepts fondamentaux des PWA. Il est fiable et entièrement hors connexion. Ainsi, même si vous ne si vous disposez d'un réseau, vous pouvez toujours l'utiliser. Elle est également Installable à l'écran d'accueil d'un appareil et s'intègre parfaitement au système d'exploitation en tant qu'application autonome.
<ph type="x-smartling-placeholder">Amélioration progressive
Maintenant que tout cela est terminé, intéressons-nous à l'amélioration progressive. Le glossaire MDN Web Docs définit le concept comme suit:
L'amélioration progressive est une philosophie de conception qui fournit une base de le contenu et les fonctionnalités essentiels au plus grand nombre d'utilisateurs possible, tandis que fournir la meilleure expérience possible uniquement aux utilisateurs de la version la plus récente qui peuvent exécuter tout le code requis.
Détection de caractéristiques sert généralement à déterminer si les navigateurs acceptent des fonctionnalités plus modernes, tandis que les polyfills sont souvent utilisés pour ajouter des caractéristiques manquantes avec JavaScript.
[…]
L'amélioration progressive est une technique utile qui permet aux développeurs Web de se concentrer à développer les meilleurs sites Web possibles tout en faisant fonctionner ces sites Web sur plusieurs user-agents inconnus. Dégradation progressive est liée, mais n'est pas la même chose et est souvent considérée comme allant dans la direction opposée. à l'amélioration progressive. En réalité, les deux approches sont valables et peuvent souvent se compléter.
Contributeurs MMD
Commencer chaque carte de vœux à partir de zéro peut être très fastidieux.
Alors pourquoi ne pas proposer une fonctionnalité qui permet aux utilisateurs d'importer une image et de partir de là ?
Avec une approche traditionnelle, vous auriez utilisé un
<input type=file>
pour y parvenir.
Tout d'abord, vous devez créer l'élément, définir sa propriété type
sur 'file'
et ajouter des types MIME à la propriété accept
,
puis "cliquez" de façon programmatique et écouter les changements.
Lorsque vous sélectionnez une image, elle est importée directement dans le canevas.
const importImage = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
Lorsqu'il existe une fonctionnalité d'importation, une fonctionnalité d'exportation devrait être disponible
afin que les utilisateurs puissent enregistrer
leurs cartes de vœux localement.
La méthode traditionnelle d'enregistrement des fichiers consiste à créer un lien d'ancrage.
avec un download
et avec une URL blob comme href
.
Par programmation, vous pouvez aussi "cliquer" pour déclencher le téléchargement,
et, pour éviter les fuites de mémoire, pensez à révoquer l'URL de l'objet blob.
const exportImage = async (blob) => {
const a = document.createElement('a');
a.download = 'fugu-greeting.png';
a.href = URL.createObjectURL(blob);
a.addEventListener('click', (e) => {
setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
});
a.click();
};
Attendez une minute. Mentalement, vous n'avez pas « téléchargé » une carte de vœux, vous avez "enregistré" Plutôt que d'afficher un bouton "Enregistrer" qui vous permet de choisir où placer le fichier, Le navigateur a téléchargé directement la carte de vœux sans intervention de l'utilisateur. et l'a placé directement dans le dossier Téléchargements. Ce n'est pas génial.
Et s'il existait une meilleure solution ? Et si vous pouviez simplement ouvrir un fichier local, le modifier, puis enregistrer les modifications, dans un nouveau fichier ou au fichier d'origine que vous aviez initialement ouvert ? Il s’avère que c’est le cas. L'API File System Access vous permet d'ouvrir et de créer des fichiers et des répertoires, et les modifier et les enregistrer .
Comment détecter une API ?
L'API File System Access expose une nouvelle méthode window.chooseFileSystemEntries()
.
Par conséquent, je dois charger de manière conditionnelle différents modules d'importation et d'exportation selon que cette méthode est disponible ou non. Vous trouverez ci-dessous la procédure à suivre.
const loadImportAndExport = () => {
if ('chooseFileSystemEntries' in window) {
Promise.all([
import('./import_image.mjs'),
import('./export_image.mjs'),
]);
} else {
Promise.all([
import('./import_image_legacy.mjs'),
import('./export_image_legacy.mjs'),
]);
}
};
Mais avant de plonger dans les détails de l'API File System Access, permettez-moi de souligner rapidement le modèle d'amélioration progressive. Dans les navigateurs qui ne sont actuellement pas compatibles avec l'API File System Access, je charge les anciens scripts. Vous trouverez ci-dessous les onglets réseau de Firefox et Safari.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Toutefois, dans Chrome, un navigateur qui prend en charge l'API, seuls les nouveaux scripts sont chargés.
Tout cela est possible avec élégance grâce à
import()
dynamique, compatible avec tous les navigateurs récents
assistance.
Comme je l'ai dit tout à l'heure, l'herbe est plutôt verte ces jours-ci.
API File System Access
Maintenant que nous avons résolu ce problème, il est temps d'examiner l'implémentation effective basée sur l'API File System Access.
Pour importer une image, j'appelle window.chooseFileSystemEntries()
.
et lui transmettre une propriété accepts
où je veux des fichiers image.
Les extensions de fichier et les types MIME sont acceptés.
Il en résulte un handle de fichier à partir duquel je peux obtenir le fichier réel en appelant getFile()
.
const importImage = async () => {
try {
const handle = await window.chooseFileSystemEntries({
accepts: [
{
description: 'Image files',
mimeTypes: ['image/*'],
extensions: ['jpg', 'jpeg', 'png', 'webp', 'svg'],
},
],
});
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};
L'exportation d'une image est presque la même, mais cette fois
Je dois transmettre un paramètre de type 'save-file'
à la méthode chooseFileSystemEntries()
.
J'obtiens alors une boîte de dialogue
pour enregistrer un fichier.
Lorsque le fichier est ouvert, cela n'était pas nécessaire puisque 'open-file'
est le paramètre par défaut.
J'ai défini le paramètre accepts
comme précédemment, mais cette fois-ci en me limitant aux images PNG.
Encore une fois, je récupère un handle
de fichier, mais au lieu d’obtenir le fichier,
cette fois, je crée un flux accessible en écriture en appelant createWritable()
.
Ensuite, j'écris le blob, qui est l'image de ma carte de vœux, dans le fichier.
Enfin, je ferme le flux accessible en écriture.
Tout peut toujours échouer: le disque peut manquer d'espace,
il se peut qu'il y ait une erreur d'écriture ou de lecture, ou
peut-être simplement que l'utilisateur annule la boîte de dialogue du fichier.
C'est pourquoi j'encapsule toujours les appels dans une instruction try...catch
.
const exportImage = async (blob) => {
try {
const handle = await window.chooseFileSystemEntries({
type: 'save-file',
accepts: [
{
description: 'Image file',
extensions: ['png'],
mimeTypes: ['image/png'],
},
],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
} catch (err) {
console.error(err.name, err.message);
}
};
En utilisant l'amélioration progressive avec l'API File System Access, je peux ouvrir un fichier comme avant. Le fichier importé est dessiné directement sur le canevas. Je peux apporter mes modifications, puis les enregistrer avec une boîte de dialogue d'enregistrement réelle. où je peux choisir le nom et l’emplacement de stockage du fichier. Le fichier est maintenant prêt à être conservé pour l'éternité.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">API Web Share et Web Share Target
En plus du stockage pour l'éternité, je veux peut-être partager ma carte de vœux. C'est un aspect que l'API Web Share et API Web Share Target me permettent de le faire. Les systèmes d'exploitation pour mobile, et plus récemment, pour les ordinateurs de bureau, ont développé le partage intégré ces mécanismes. Par exemple, vous trouverez ci-dessous la feuille de partage de bureau de Safari sur macOS déclenchée à partir d'un article sur mon blog. Lorsque vous cliquez sur le bouton Partager l'article, vous pouvez partager un lien vers l'article avec un ami, par par exemple via l'application Messages de macOS.
<ph type="x-smartling-placeholder">Pour ce faire, le code est assez simple. J'appelle navigator.share()
et
transmettez-lui des éléments facultatifs title
, text
et url
dans un objet.
Comment joindre une image ? Le niveau 1 de l'API Web Share n'est pas encore compatible.
La bonne nouvelle, c'est que Web Share niveau 2 dispose de fonctionnalités de partage de fichiers supplémentaires.
try {
await navigator.share({
title: 'Check out this article:',
text: `"${document.title}" by @tomayac:`,
url: document.querySelector('link[rel=canonical]').href,
});
} catch (err) {
console.warn(err.name, err.message);
}
Laissez-moi vous montrer comment faire fonctionner cela avec l'application de carte de vœux Fugu.
Tout d'abord, je dois préparer un objet data
avec un tableau files
composé d'un blob, puis
un title
et un text
. Ensuite, nous vous recommandons d'utiliser la nouvelle méthode navigator.canShare()
, qui
comme son nom l'indique:
Il m'indique si le navigateur peut techniquement partager l'objet data
que j'essaie de partager.
Si navigator.canShare()
m'indique que les données peuvent être partagées, je suis prêt à
appelez navigator.share()
comme précédemment.
Comme tout peut échouer, j'utilise à nouveau un bloc try...catch
.
const share = async (title, text, blob) => {
const data = {
files: [
new File([blob], 'fugu-greeting.png', {
type: blob.type,
}),
],
title: title,
text: text,
};
try {
if (!(navigator.canShare(data))) {
throw new Error("Can't share data.", data);
}
await navigator.share(data);
} catch (err) {
console.error(err.name, err.message);
}
};
Comme précédemment, j'utilise l'amélioration progressive.
Si 'share'
et 'canShare'
existent tous les deux sur l'objet navigator
, c'est seulement que j'avance et
charger share.mjs
via une import()
dynamique.
Dans les navigateurs comme Safari pour mobile qui ne remplissent que l'une des deux conditions, je ne charge pas
la fonctionnalité.
const loadShare = () => {
if ('share' in navigator && 'canShare' in navigator) {
import('./share.mjs');
}
};
Dans Fugu Greetings, si j'appuie sur le bouton Partager dans un navigateur compatible comme Chrome sur Android, la feuille de partage intégrée s'ouvre. Je peux, par exemple, choisir Gmail pour que le widget de rédaction d'e-mails s'affiche avec le image jointe.
API Contact Picker
Ensuite, je veux parler des contacts, c'est-à-dire du carnet d'adresses d'un appareil, ou de gestion de contacts. Lorsque vous écrivez une carte de vœux, il n'est pas toujours facile d'écrire correctement le nom de quelqu'un. Par exemple, j'ai un ami Sergey qui préfère que son nom soit orthographié en lettres cyrilliques. Je suis utilisant un clavier QWERTZ allemand et vous n'avez aucune idée de la façon de taper leur nom. L'API Contact Picker peut résoudre ce problème. Étant donné que mon ami est stocké dans l'application de contacts de mon téléphone, via l'API Contacts Picker, je peux accéder à mes contacts sur le Web.
Tout d'abord, je dois spécifier la liste des propriétés auxquelles je souhaite accéder.
Dans ce cas, je ne veux
que les noms,
Mais pour d'autres cas d'utilisation, je pourrais m'intéresser aux numéros de téléphone, aux adresses e-mail, aux avatars
des icônes ou
des adresses physiques.
Ensuite, je configure un objet options
et je définis multiple
sur true
afin de pouvoir en sélectionner davantage.
plusieurs entrées.
Enfin, je peux appeler navigator.contacts.select()
, qui renvoie les propriétés souhaitées
pour les contacts sélectionnés par l'utilisateur.
const getContacts = async () => {
const properties = ['name'];
const options = { multiple: true };
try {
return await navigator.contacts.select(properties, options);
} catch (err) {
console.error(err.name, err.message);
}
};
À ce stade, vous avez probablement appris le modèle: Je ne charge le fichier que lorsque l'API est réellement prise en charge.
if ('contacts' in navigator) {
import('./contacts.mjs');
}
Dans Fugu Greeting, lorsque j'appuie sur le bouton Contacts et que je sélectionne mes deux meilleurs amis, Radio Po vous pouvez voir comment le sélecteur de contacts est limité à afficher uniquement leur nom, mais pas leurs adresses e-mail, ni d’autres informations comme leurs numéros de téléphone. Leurs noms sont ensuite dessinés sur ma carte de vœux.
API Asynchronous Clipboard
L'étape suivante consiste à copier et coller. L'une de nos opérations préférées en tant que développeurs logiciels est le copier-coller. En tant qu'auteur de cartes de vœux, je peux parfois vouloir faire de même. Je veux peut-être coller une image dans une carte de vœux sur laquelle je travaille, ou copier ma carte de vœux pour que je puisse continuer à la modifier ailleurs. l'API Async Clipboard ; prend en charge à la fois du texte et des images. Laissez-moi vous expliquer comment j'ai ajouté la prise en charge du copier-coller dans Fugu Application d'accueil.
Pour copier un élément dans le presse-papiers du système, je dois y écrire.
La méthode navigator.clipboard.write()
utilise un tableau d'éléments du presse-papiers en tant que
.
Chaque élément du presse-papiers est essentiellement un objet avec un blob comme valeur et le type de l'objet blob.
comme clé.
const copy = async (blob) => {
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
console.error(err.name, err.message);
}
};
Pour coller, je dois effectuer une boucle sur les éléments du presse-papiers que j'obtiens en appelant
navigator.clipboard.read()
La raison est que plusieurs éléments du presse-papiers
peuvent se trouver dans le presse-papiers dans
différentes représentations.
Chaque élément du presse-papiers comporte un champ types
qui indique les types MIME des types de fichiers
ressources.
J'appelle la méthode getType()
de l'élément du presse-papiers, en transmettant
Type MIME obtenu précédemment.
const paste = async () => {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
return blob;
}
} catch (err) {
console.error(err.name, err.message);
}
}
} catch (err) {
console.error(err.name, err.message);
}
};
Et c'est presque inutile de le dire à présent. Je le fais uniquement sur les navigateurs pris en charge.
if ('clipboard' in navigator && 'write' in navigator.clipboard) {
import('./clipboard.mjs');
}
Comment cela fonctionne-t-il concrètement ? J'ai une image ouverte dans l'application Preview de macOS et le copier dans le presse-papiers. Lorsque je clique sur Coller, l'application Fugu Greetings me demande alors si je veux autoriser l'application à voir le texte et les images du presse-papiers.
<ph type="x-smartling-placeholder">Enfin, après avoir accepté l'autorisation, l'image est collée dans l'application. L'inverse fonctionne également. Je copie une carte de vœux dans le presse-papiers. Lorsque j'ouvre l'aperçu et que je clique sur Fichier, puis sur Nouveau depuis le presse-papiers, la carte de vœux est collée dans une nouvelle image sans titre.
<ph type="x-smartling-placeholder">.API Badging
L'API Badging est également utile.
Fugu Greetings est bien sûr associée à une icône d'application, car il s'agit d'une PWA installable.
que les utilisateurs peuvent placer
sur la barre d'applications ou l'écran d'accueil.
Un moyen simple et amusant de présenter l'API consiste à l'utiliser (ou de l'utiliser de manière abusive) dans Fugu Greetings.
en tant que compteur de coups de stylo.
J'ai ajouté un écouteur d'événements qui incrémente le compteur de traits de crayon à chaque fois que l'événement pointerdown
se produit.
puis définit le nouveau badge d'icône.
Dès que la toile est effacée, le compteur est réinitialisé et le badge est supprimé.
let strokes = 0;
canvas.addEventListener('pointerdown', () => {
navigator.setAppBadge(++strokes);
});
clearButton.addEventListener('click', () => {
strokes = 0;
navigator.setAppBadge(strokes);
});
Comme il s'agit d'une amélioration progressive, la logique de chargement reste la même.
if ('setAppBadge' in navigator) {
import('./badge.mjs');
}
Dans cet exemple, j'ai dessiné les chiffres de un à sept en un trait de crayon. par numéro. Le nombre de badges sur l'icône est désormais de sept.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">API Periodic Background Sync
Vous voulez prendre un nouveau départ chaque journée avec quelque chose de nouveau ? L'application Fugu Greetings offre une fonctionnalité intéressante : elle peut vous inspirer chaque matin. avec une nouvelle image de fond pour commencer votre carte de vœux. L'application utilise l'API Periodic Background Sync. pour y parvenir.
La première étape consiste à enregistrer un événement de synchronisation périodique dans l'enregistrement du service worker.
Il écoute un tag de synchronisation appelé 'image-of-the-day'
.
et a un intervalle minimal
d'un jour,
afin que l'utilisateur puisse obtenir
une nouvelle image de fond toutes les 24 heures.
const registerPeriodicBackgroundSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
registration.periodicSync.register('image-of-the-day-sync', {
// An interval of one day.
minInterval: 24 * 60 * 60 * 1000,
});
} catch (err) {
console.error(err.name, err.message);
}
};
La deuxième étape consiste à écouter l'événement periodicsync
dans le service worker.
Si le tag d'événement est 'image-of-the-day'
(c'est-à-dire celui qui a été enregistré auparavant),
l'image du jour est récupérée via la fonction getImageOfTheDay()
,
Le résultat est propagé à tous les clients, pour qu'ils puissent mettre à jour leurs canevas et
caches.
self.addEventListener('periodicsync', (syncEvent) => {
if (syncEvent.tag === 'image-of-the-day-sync') {
syncEvent.waitUntil(
(async () => {
const blob = await getImageOfTheDay();
const clients = await self.clients.matchAll();
clients.forEach((client) => {
client.postMessage({
image: blob,
});
});
})()
);
}
});
Encore une fois, il s'agit d'une amélioration progressive. Le code n'est chargé que lorsque le
est compatible avec le navigateur.
Cela s'applique à la fois au code client et au code du service worker.
Sur les navigateurs non compatibles, aucun des deux n'est chargé.
Notez que dans le service worker, au lieu d'un import()
dynamique
(non disponible dans le contexte d'un service worker,
encore),
J'utilise la version classique
importScripts()
// In the client:
const registration = await navigator.serviceWorker.ready;
if (registration && 'periodicSync' in registration) {
import('./periodic_background_sync.mjs');
}
// In the service worker:
if ('periodicSync' in self.registration) {
importScripts('./image_of_the_day.mjs');
}
Dans Fugu Greetings, appuyer sur le bouton Fond d'écran permet d'afficher l'image de la carte de vœux du jour. mis à jour quotidiennement via l'API Periodic Background Sync.
<ph type="x-smartling-placeholder">API Notification Triggers
Parfois, même avec beaucoup d'inspiration, vous avez besoin d'un coup de pouce pour terminer une salutation qui a commencé . Cette fonctionnalité est activée par l'API Notification Triggers. En tant qu'utilisateur, je peux saisir un moment auquel je souhaite être invité à terminer ma carte de vœux. À ce moment-là, je recevrai une notification indiquant que ma carte de vœux sera disponible.
Après avoir demandé l'heure cible,
l'application planifie la notification avec un showTrigger
.
Il peut s'agir d'un TimestampTrigger
avec la date cible précédemment sélectionnée.
La notification de rappel sera déclenchée localement. Aucun côté réseau ou serveur n'est nécessaire.
const targetDate = promptTargetDate();
if (targetDate) {
const registration = await navigator.serviceWorker.ready;
registration.showNotification('Reminder', {
tag: 'reminder',
body: "It's time to finish your greeting card!",
showTrigger: new TimestampTrigger(targetDate),
});
}
Comme pour tout ce que j'ai montré jusqu'à présent, c'est une amélioration progressive, Le code n'est donc chargé que de manière conditionnelle.
if ('Notification' in window && 'showTrigger' in Notification.prototype) {
import('./notification_triggers.mjs');
}
Lorsque je coche la case Rappel dans Fugu Greetings, une invite me demande moi quand je veux qu'on me rappelle de terminer ma carte de vœux.
<ph type="x-smartling-placeholder">Lorsqu'une notification programmée se déclenche dans Fugu Greetings, elle s’affiche comme n’importe quelle autre notification, mais comme je l’ai écrit auparavant, il n’avait pas besoin d’une connexion réseau.
<ph type="x-smartling-placeholder">API Wake Lock
Je souhaite également inclure l'API Wake Lock. Parfois, il suffit de regarder l'écran suffisamment longtemps pour trouver l'inspiration t'embrasse. Dans le pire des cas, c’est alors que l’écran s’éteint. L'API Wake Lock peut empêcher cette situation.
La première étape consiste à obtenir un wakelock avec le navigator.wakelock.request method()
.
Je lui transmets la chaîne 'screen'
pour obtenir un wakelock de l'écran.
J'ajoute ensuite un écouteur d'événements pour être informé du lancement du wakelock.
Cela peut se produire, par exemple, lorsque la visibilité des onglets change.
Si cela se produit, lorsque l'onglet redevient visible, activer de nouveau le wakelock.
let wakeLock = null;
const requestWakeLock = async () => {
wakeLock = await navigator.wakeLock.request('screen');
wakeLock.addEventListener('release', () => {
console.log('Wake Lock was released');
});
console.log('Wake Lock is active');
};
const handleVisibilityChange = () => {
if (wakeLock !== null && document.visibilityState === 'visible') {
requestWakeLock();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener('fullscreenchange', handleVisibilityChange);
Oui, il s'agit d'une amélioration progressive. Je n'ai donc besoin de la charger que lorsque le navigateur est compatible avec l'API.
if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
import('./wake_lock.mjs');
}
Dans Fugu Greetings, il existe une case à cocher Insomnia qui, lorsqu'elle est cochée, permet de conserver écran activé.
<ph type="x-smartling-placeholder">API Idle Detection
Parfois, même si vous regardez l’écran pendant des heures, elle est tout simplement inutile et vous ne pouvez pas trouver la moindre idée de ce qu'il faut faire avec votre carte de vœux. L'API Idle Detection permet à l'application de détecter le temps d'inactivité des utilisateurs. Si l'utilisateur reste inactif trop longtemps, l'application est réinitialisée à son état initial. et efface le canevas. Cette API est actuellement contrôlée par l'équipe autorisation de notification, puisque de nombreux cas d'utilisation en production de la détection d'inactivité sont liés aux notifications, (par exemple, pour n'envoyer une notification qu'à un appareil en cours d'utilisation).
Après m'assurer que l'autorisation de notification est accordée, j'instancie ensuite détecteur d'inactivité. J'enregistre un écouteur d'événements qui écoute les modifications apportées à l'inactivité, qui inclut l'utilisateur l'état de l'écran. L'utilisateur peut être actif ou inactif, et l'écran peut être déverrouillé ou verrouillé. Si l'utilisateur est inactif, le canevas est effacé. Je définis un seuil de 60 secondes pour le détecteur d'inactivité.
const idleDetector = new IdleDetector();
idleDetector.addEventListener('change', () => {
const userState = idleDetector.userState;
const screenState = idleDetector.screenState;
console.log(`Idle change: ${userState}, ${screenState}.`);
if (userState === 'idle') {
clearCanvas();
}
});
await idleDetector.start({
threshold: 60000,
signal,
});
Comme toujours, je ne charge ce code que lorsque le navigateur le prend en charge.
if ('IdleDetector' in window) {
import('./idle_detection.mjs');
}
Dans l'application Fugu Greetings, le canevas est effacé lorsque la case Ephemeral (Éphémère) est cochée. cochée et l'utilisateur est inactif pendant trop longtemps.
<ph type="x-smartling-placeholder">Conclusion
Quel bolide ! Un grand nombre d'API dans une seule application exemple. Et n'oubliez pas que je n'oblige jamais l'utilisateur à payer le coût du téléchargement. d'une fonctionnalité non prise en charge par leur navigateur. Grâce à l'amélioration progressive, je m'assure que seul le code approprié est chargé. Étant donné qu'avec le protocole HTTP/2, les requêtes sont économiques, ce modèle devrait fonctionner applications, même si vous pouvez envisager d'utiliser un bundler pour les applications très volumineuses.
<ph type="x-smartling-placeholder">L'application peut s'afficher un peu différemment sur chaque navigateur, car toutes les plateformes ne prennent pas en charge toutes les fonctionnalités, mais la fonctionnalité de base est toujours présente et s'améliore progressivement en fonction des capacités du navigateur. Notez que ces fonctionnalités peuvent changer même dans un seul et même navigateur, selon que l'application s'exécute en tant qu'application installée ou dans un onglet du navigateur.
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">Si l'application Fugu Greetings vous intéresse, recherchez-le et dupliquez-le sur GitHub.
<ph type="x-smartling-placeholder">L'équipe Chromium met tout en œuvre pour rendre l'herbe plus verte en ce qui concerne les API Fugu avancées. En appliquant une amélioration progressive au développement de mon application, Je m'assure que tout le monde bénéficie d'une bonne et solide expérience de base, mais que les personnes utilisant des navigateurs qui prennent en charge davantage d'API de plateforme Web bénéficient d'une expérience encore meilleure. J'ai hâte de découvrir ce que vous allez faire avec l'amélioration progressive de vos applications.
Remerciements
Je suis reconnaissant à Christian Liebel et
Hemanth HM, tous deux ayant contribué à l'émission "Fugu Greetings".
Cet article a été lu par Joe Medley et
Kayce Basques.
Jake Archibal m'a aidé à comprendre la situation
avec une import()
dynamique dans un contexte de service worker.