Appliquer les principes de programmation des mini-applications à un exemple de projet

Pour montrer comment la programmation par mini-application s'applique à une application Web, j'avais besoin d'une idée d'application petite, mais suffisamment complète. L'entraînement par intervalles haute intensité (HIIT) est une stratégie d'exercice cardiovasculaire qui consiste à alterner des séries de courtes périodes d'exercice anaérobie intense avec des périodes de récupération moins intenses. De nombreux entraînements HIIT utilisent des minuteurs HIIT, comme cette session en ligne de 30 minutes de la chaîne YouTube The Body Coach TV.

Séance d'entraînement HIIT en ligne avec un minuteur vert haute intensité.
Période d'activité.
Séance d'entraînement HIIT en ligne avec un minuteur rouge à faible intensité.
Période de repos.

Exemple d'application HIIT Time

Pour ce chapitre, j'ai créé un exemple de base d'une telle application de minuteur HIIT, baptisée "HIIT Time", qui permet à l'utilisateur de définir et de gérer différents minuteurs, toujours composés d'un intervalle à haute et basse intensité, puis de sélectionner l'un d'eux pour une séance d'entraînement. Il s'agit d'une application responsive avec une barre de navigation, une barre d'onglets et trois pages:

  • Entraînement : page active pendant un entraînement. Il permet à l'utilisateur de sélectionner l'un des minuteurs et comporte trois anneaux de progression: le nombre d'ensembles, la période active et la période de repos.
  • Minuteurs : permet de gérer les minuteurs existants et de créer des minuteurs.
  • Préférences : permet d'activer ou de désactiver les effets sonores et la sortie vocale, et de sélectionner la langue et le thème.

Les captures d'écran suivantes vous donnent une idée de l'application.

Exemple d'application HIIT Time en mode Portrait.
HIIT Time, onglet "Entraînement" en mode portrait.
Exemple d'application HIIT Time en mode Paysage.
Onglet "Entraînement" Entraînement HIIT en mode Paysage.
Exemple d'application HIIT Time montrant la gestion d'un minuteur.
Gestion des minuteurs HIIT.

Structure de l'application

Comme indiqué ci-dessus, l'application se compose d'une barre de navigation, d'une barre d'onglets et de trois pages, disposées en grille. La barre de navigation et la barre d'onglets sont implémentées en tant qu'iFrames avec un conteneur <div> entre elles et trois autres iFrames pour les pages, dont l'un est toujours visible et dépend de la sélection active dans la barre d'onglets. Une iFrame finale pointant vers about:blank sert aux pages créées dynamiquement dans l'application, qui sont nécessaires pour modifier les minuteurs existants ou en créer. Je nomme ce modèle "application monopage multipage" (MPSPA, Multi Page Single Page Application).

Vue des outils de développement Chrome de la structure HTML de l&#39;application, qui montre qu&#39;elle se compose de six iframes : un pour la barre de navigation, un pour la barre d&#39;onglets et trois regroupés pour chaque page de l&#39;application, avec un dernier iframe d&#39;espace réservé pour les pages dynamiques.
Elle se compose de six iFrames.

Balisage lit-html basé sur des composants

La structure de chaque page est réalisée sous la forme d'un échafaudage lit-html évalué dynamiquement au moment de l'exécution. Pour en savoir plus sur lit-html, il s'agit d'une bibliothèque de modèles HTML efficace, expressive et extensible pour JavaScript. En l'utilisant directement dans les fichiers HTML, le modèle de programmation mentale est directement orienté vers la sortie. En tant que programmeur, vous écrivez un modèle de sortie finale. Lit-html remplit ensuite les espaces vides de manière dynamique en fonction de vos données et connecte les écouteurs d'événements. L'application utilise des éléments personnalisés tiers tels que <sl-progress-ring> de Shoelace ou un élément personnalisé auto-implémenté appelé <human-duration>. Étant donné que les éléments personnalisés disposent d'une API déclarative (par exemple, l'attribut percentage de l'anneau de progression), ils fonctionnent bien avec lit-html, comme vous pouvez le voir dans la liste ci-dessous.

<div>
 
<button class="start" @click="${eventHandlers.start}" type="button">
    ${strings.START}
 
</button>
 
<button class="pause" @click="${eventHandlers.pause}" type="button">
    ${strings.PAUSE}
 
</button>
 
<button class="reset" @click="${eventHandlers.reset}" type="button">
    ${strings.RESET}
 
</button>
</div>

<div class="progress-rings">
 
<sl-progress-ring
   
class="sets"
   
percentage="${Math.floor(data.sets/data.activeTimer.sets*100)}"
 
>
   
<div class="progress-ring-caption">
     
<span>${strings.SETS}</span>
     
<span>${data.sets}</span>
   
</div>
 
</sl-progress-ring>
</div>
Trois boutons et un anneau de progression.
Section de la page affichée correspondant à la balise ci-dessus.

Modèle de programmation

Chaque page possède une classe Page correspondante qui remplit le balisage lit-html de vie en fournissant des implémentations de gestionnaires d'événements et les données de chaque page. Cette classe accepte également les méthodes de cycle de vie telles que onShow(), onHide(), onLoad() et onUnload(). Les pages ont accès à un data store qui permet de partager l'état global et l'état par page (facultatif). Toutes les chaînes sont gérées de manière centralisée. L'internationalisation est donc intégrée. Le routage est géré par le navigateur essentiellement sans frais, car l'application ne fait que basculer la visibilité de l'iFrame et, pour les pages créées dynamiquement, modifier l'attribut src de l'iFrame d'espace réservé. L'exemple ci-dessous illustre le code permettant de fermer une page créée de façon dynamique.

import Page from '../page.js';

const page = new Page({
  eventHandlers
: {
    back
: (e) => {
      e
.preventDefault();
      window
.top.history.back();
   
},
 
},
});
Page intégrée à l&#39;application réalisée sous forme d&#39;iFrame.
La navigation se fait d'un iFrame à un autre.

Attribuer un style

Le style des pages est défini par page dans son propre fichier CSS. Cela signifie que les éléments peuvent généralement être directement adressés par leur nom, car aucun conflit ne peut se produire avec d'autres pages. Les styles globaux sont ajoutés à chaque page. Par conséquent, les paramètres centraux tels que font-family ou box-sizing n'ont pas besoin d'être déclarés de manière répétée. C'est également là que les thèmes et les options de mode sombre sont définis. La liste ci-dessous présente les règles de la page "Préférences" qui organise les différents éléments de formulaire sur une grille.

main {
 
max-width: 600px;
}

form
{
 
display: grid;
 
grid-template-columns: auto 1fr;
 
grid-gap: 0.5rem;
 
margin-block-end: 1rem;
}

label
{
 
text-align: end;
 
grid-column: 1 / 2;
}

input
,
select
{
 
grid-column: 2 / 3;
}
Page des préférences de l&#39;application HIIT Time affichant un formulaire dans une mise en page en grille.
Chaque page est un monde à part. Le style est appliqué directement aux noms des éléments.

Verrouillage de l'écran

Pendant un entraînement, l'écran ne doit pas s'éteindre. Sur les navigateurs compatibles, HIIT Time s'en charge à l'aide d'un verrouillage de l'écran. L'extrait de code ci-dessous montre comment procéder.

if ('wakeLock' in navigator) {
 
const requestWakeLock = async () => {
   
try {
      page
.shared.wakeLock = await navigator.wakeLock.request('screen');
      page
.shared.wakeLock.addEventListener('release', () => {
       
// Nothing.
     
});
   
} catch (err) {
      console
.error(`${err.name}, ${err.message}`);
   
}
 
};
 
// Request a screen wake lock…
  await requestWakeLock
();
 
// …and re-request it when the page becomes visible.
  document
.addEventListener('visibilitychange', async () => {
   
if (
      page
.shared.wakeLock !== null &&
      document
.visibilityState === 'visible'
   
) {
      await requestWakeLock
();
   
}
 
});
}

Tester l'application

L'application HIIT Time est disponible sur GitHub. Vous pouvez tester la démo dans une nouvelle fenêtre ou directement dans l'iframe intégré ci-dessous, qui simule un appareil mobile.

Remerciements

Cet article a été relu par Joe Medley, Kayce Basques, Milica Mihajlija, Alan Kent et Keith Gu.