Une web app en ligne en un week-end sans (trop) d’effort

Quelques outils modernes à utiliser pour créer et mettre en ligne une app rapidement, facilement et en s’amusant !

Le week-end dernier (80% du code a été écrit dans cette période), j’ai eu une idée d’application très simple mais qui me permettrait de tester plusieurs technos que j’avais repérées depuis environ deux ans, mais que je n’avais encore jamais eu l’occasion de mettre en pratique — comme beaucoup de développeurs j’imagine... Parmi celles-ci :

L’idée est de proposer une liste participative d’alternatives écologiques et durables à nos actes et objets du quotidien. Chaque alternative est définie par un nom, une description, une image, une source et une ou plusieurs catégories qui permettent de les filtrer. Enfin, elle possède une difficulté qui permet, en plus du tri, d’ajouter un aspect gamification que l’on coche “fait !” pour gagner un nombre de point équivalent à sa difficulté. En bref une idée qui me paraît à la fois utile et un bon terrain de jeu pour mettre en pratique toutes ces technologies.


Vue

Voilà bien longtemps que j’avais envie de jouer avec Vue (puisque je n’aime pas JSX :D), et c’était enfin l’occasion. J’ai démarré grâce à des templates de base (puisque je n’aime pas bidouiller Webpack :D) : https://github.com/vuejs-templates/webpack

$ npm install -g vue-cli
$ vue init webpack my-project
$ cd my-project
$ npm install
$ npm run dev

Le processus de création vous donne plusieurs choix quant aux outils à utiliser tels que Vuex ou Vue-router. Comme il est très simple de les ajouter après coup, je préconiserais de les zapper si c’est votre première fois, afin de partir d’un code le plus simple possible et ainsi ne pas se sentir submerger (c’est l’erreur que j’avais faite avec Angular 2, ça m’avait largement refroidi).

Cela dit, dès que vous vous sentez à l’aise (avec Vue ce moment peut arriver après quelques heures de bidouillage si vous avez déjà développé côté front), n’hésitez pas à franchir le pas, notamment pour Vuex, car l’aide avec les Vue Developer Tools notamment sont très (très) utiles, autant pour débuguer que pour comprendre le fonctionnement de Vue :

Démo des Vue Devtools

Airtable (+ API)

Airtable est au croisement de Google Sheets et d’un CMS. Extrêmement souple et puissant, il peut remplacer des bases de données, des CRM, des feuilles Excel, et quasiment tout ce qui contient des données qu’on voudra enrichir et croiser de manière simple et ergonomique, en plus de pouvoir les présenter de plusieurs façons (liste, grille, calendrier, …). Bref, une image valant mille mots :

Aperçu de la table qui servira de base de données de l’app

Ici je m’en suis servi pour lister les différentes alternatives, avec un formulaire public qui permet de proposer de nouveaux éléments (fonctionnalité de base d’Airtable). Côté app, on peut soit faire des appels GET simples, soit utiliser le package JS proposé par Airtable eux-mêmes ; ce que j’ai fait puisqu’il est plus simple de gérer la pagination (dans mon cas je veux tous les éléments de toute façon), bien que ça représente un certain poids dans le bundle compilé.

import Airtable from 'airtable'
const base = new Airtable({apiKey: '...'}).base('...')
base('BaseName').select({
filterByFormula: '{Validé} = 1' // Only manually validated items
}).eachPage((datas, fetchNextPage) => {
// Store items, then...
fetchNextPage()
}, (err) => {
// All items fetched
console.log(err)
})

Pour aller au plus simple dans mon cas, je charge toutes les données via l’API au chargement de l’app. J’en profite d’ailleurs pour n’appeler que les éléments modérés manuellement en filtrant `filterByFormula: ‘{Validé} = 1’`, ce champ n’étant pas disponible dans le formulaire public.

L’avantage de ce système est d’avoir gratuitement et facilement une sorte de backoffice très user-friendly. On peut par exemple récupérer des images d’internet directement depuis la page d’édition d’un élément. L’app mobile permet aussi de mettre à jour rapidement les données.

L’inconvénient, c’est l’aspect tout public, puisque mon installation ne me permet pas de sécuriser les clés (il faudrait faire un appel à un serveur intermédiaire qui se chargerait d’appeler l’API avec les bonnes clés, pour les cacher au client).

LocalStorage

Avec son frère sessionStorage, il s’agit du moyen le plus simple de stocker des données côté navigateur : la principale différence réside dans le fait que ce dernier se remet à zéro une fois l’onglet fermé. Deux usages différents donc, à utiliser avec précaution notamment s’il s’agit de données sensibles bien sûr. Le support navigateur est excellent, et le code est on ne peut plus simple (si vous avez déjà bossé avec les cookies en JS, c’est le jour et la nuit) :

localStorage.setItem("username", "John");
localStorage.getItem("username") // "John"
Visualiser les données dans les Devtools de Chrome

À noter un bug chez Safari ≤ 10 qui bloque son utilisation en navigation privée, tout en assurant qu’il en est capable et sans avertir l’utilisateur (erreur dans la console uniquement), bien joué ! Voici un fix si besoin : https://gist.github.com/philfreo/68ea3cd980d72383c951

J’ai commencé à jouer avec manuellement, pour ensuite passer par un plugin Vue qui permet de stocker l’état de l’app via localStorage : https://github.com/robinvdvleuten/vuex-persistedstate. Déconcertant de facilité… Ça me permet notamment d’afficher mes données (stockée dans Vuex) tout de suite à partir du deuxième affichage, et de mettre à jour de manière transparente en arrière-plan.

Animations

Mo.js

Mo.js est une librairie pour créer des animations complexes sur le web. Il existe une myriade d’alternatives, et je ne les connais pas toutes, mais en quelques lignes, ses forces sont :

  • syntaxe extrêmement concise
  • effets percutants faciles à créer
  • génération d’éléments à la volée (burst pour les explosions, éléments géométriques, etc.)

En revanche, ses inconvénients sont :

C’est donc une librairie qui est plus pensée pour la génération de petits courts métrages plutôt qu’un utilitaire pour animer des parties d’une app ; contrairement à GSAP entre autre. Pour ma part je l’ai utilisée pour ajouter une simple “micro-interaction” (ou “micro-gratification”) pour ajouter une couche visuelle au peu de gamification que j’ai mis en place : un compteur de points en mode check-list.

Exemple de l’effet Burst de Mo.js

C’est plutôt amusant de jouer avec les options, l’effet est quasiment toujours réussi et le plus compliqué est de se restreindre pour ne pas trop en faire :) Mauvais point tout de même, le poids de la librairie qui n’est pas négligeable… Surtout pour une simple animation comme dans mon cas.

Stat size ~346kb, Parsed size ~130kb, Gzipped size ~35kb

Pourtant je n’utilise qu’une partie des possibilités, et Webpack n’a pas l’air de vouloir n’inclure que cette partie. J’ai ouvert une issue pour en savoir un peu plus. Si quelqu’un a plus d’expérience en tree-shaking via Webpack 2, je suis preneur !

En tout cas je n’ai trouvé aucun autre outil permettant d’arriver à ce genre de résultat facilement (si ce n’est Lottie mais je ne connais pas After Effects), dommage.

WAAPI (Web Animations API)

Il s’agit d’un nouveau standard permettant d’utiliser ce qu’on fait déjà avec les @keyframes en CSS. L’avantage est la simplicité d’utilisation et l’absence de librairie à importer puisque c’est une fonctionnalité native (pas encore très bien supportée), mais aussi les performances puisque c’est la seule technique d’animation en JS permettant de dépasser les 60 fps (utile pour les écrans 120hz comme celui de l’iPad Pro). L’API se présente de cette façon :

$el.animate([{
transform: 'translateY(0%)',
opacity: 1
}, {
transform: 'translateY(100%)',
opacity: 0
}], {
duration: 100,
easing: 'ease-in'
})

On retrouve en partie le schéma de l’équivalent en CSS, plus de détails dans cet article bien expliqué. En utilisant la méthode watch (c’est un peu plus compliqué que ça en fait, mais passons) de Vue et la callback onfinish de l’animation, j’anime, puis change, puis anime à nouveau la nouvelle valeur (uniquement si l’API est supportée) :

watch: {
score(newValue, oldValue) {
// Animation not supported
if ('animate' in this.$el === false) {
this.newScore = newValue
return false
}
// Out animation
this.$el.animate([{...}], {...})
.onfinish = () => {
this.newScore = newValue // Update value
// In animation
this.$el.animate([{...}], {...})
}
}
}

Ce qui donne ce résultat, en jouant un peu avec les cubic-bezier pour ajouter un effet de “bounce”.

Exemple d’usage de Web Animation API

Netlify

Netlify est un service permettant d’héberger des sites statiques de manière simple et gratuite, un peu comme le propose Github Pages. Voici une liste non exhaustive des fonctionnalités :

  • Déploiement via Git (surveille une branche, compile puis met en ligne automatiquement)
  • Gestion des DNS (pas obligatoire mais nécessaire pour certaines fonctionnalités), HTTPS automatique avec Let’s Encrypt, CDN par défaut
  • Prerendering (basé sur une ancienne version de Prerender.io)

Des fonctionnalités supplémentaires bienvenues sont aussi présentes (certaines encore en beta) :

  • Sous-domaines automatiques par branche (par exemple pour un environnement de test/validation)
  • Tests A/B par branche (pas testé mais prometteur)
  • Gestion de formulaires (pas testé non plus), ainsi que de fonctions lambdas et d’identités similaires au système d’Amazon Web Services

Le support est très réactif, transparent (autant techniquement que commercialement) et d’une manière générale le service est excellent. En parallèle est proposé un CMS as a Service que je n’ai pas encore eu l’occasion de tester. En tout cas je recommande chaleureusement leur service !

Bugsnag

Aperçu de l’interface de Bugsnag

Bugsnag est un service de surveillance et de rapport d’erreurs, aussi bien côté serveur (pas utile en l’occurrence) que côté client. Parmi les différentes alternatives que j’ai pu lister, ça me paraît le meilleur rapport qualité, prix et compatibilité : le service est assez connu et souvent intégré aux écosystèmes. Par exemple, j’ai pu facilement utiliser un plugin Webpack pour déployer les sourcemaps lors d’une mise en ligne ; c’est crucial car sans ce système, les erreurs seront liées à leur position dans les fichiers compilés plutôt que dans les fichiers sources, et seront donc d’aucune utilité.

Voilà comment utiliser le plugin webpack-bugsnag-plugin :

const {
BugsnagDeployPlugin,
BugsnagSourceMapPlugin
} = require('webpack-bugsnag-plugin');
// Webpack config
{
plugins: [
new BugsnagDeployPlugin({
apiKey: '...',
releaseStage: 'production',
repository: 'git@github.com:username/project.git',
branch: 'prod'
}),
new BugsnagSourceMapPlugin({
apiKey: '..',
publicPath: 'http*://*domain.fr/dist',
}),
]
}

La première partie permet de notifier une nouvelle version de votre app à Bugsnag et ainsi pouvoir filtrer les erreurs : le hash du dernier commit et la version semver depuis votre fichier package.json . La deuxième partie envoie les fameux fichiers sourcemaps directement à Bugsnag. Ce qui donne ce genre de rapport :

Détail d’une erreur récupérée par Bugsnag

Je n’avais encore jamais utilisé de tel service, et posséder autant d’informations aussi détaillées est une vraie révélation ! Le service est gratuit jusqu’à 250 erreurs par mois avant de passer à 29$/mois.


Conclusion

La myriade d’outils et les écosystèmes de services qui s’intègrent les uns aux autres permettent vraiment une productivité incroyable, et très souvent gratuitement (15€/an pour le nom de domaine en fait). En prenant un peu de recul on se dit qu’on travaille dans un micro-monde vraiment détaché de certaines réalités économiques... Bref, pour rester plus terre à terre, c’est réellement plaisant d’arriver à un projet de cette qualité aussi rapidement. Ce n’est bien sûr jamais aussi simples pour des projets plus anciens ou plus conséquents, mais pour des side-projects, des hackathons ou encore l’apprentissage, quel plaisir !

Parmi les technos encore sur la wishlist que je n’ai pas eu le temps de tester pour ce projet, il reste :

  • Tests unitaires et E2E que j’ai procrastinés comme un vrai développeur
  • Service Workers pour mieux gérer la persistence des données et la mise en cache des fichiers
  • Firebase pour avoir une application plus complète et à terme remplacer Netlify et Airtable

Le code source est dispo sur Github bien sûr ! Avis, commentaires et PR bienvenus comme toujours. Enfin, si vous avez des alternatives à proposer, vous pouvez le faire via le formulaire ! ♻️

Like what you read? Give Nico Prat a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.