Naomi Hauret, 26/01/2018

Workflow front-end : un nouvel espoir (partie 2)

10 minutes de lecture

Cet article est issu d'une réflexion postée à l'origine sur notre Discourse en décembre 2017.

Présentant les problèmes de notre workflow actuel plus en détails et des solutions concrètes pour résoudre ceux-ci, il est le deuxième d'une série consacrée à sa refonte, ainsi qu'à celle de nos outils et pratiques front-end.


TL;DR : npm | Webpack | ES6 + Inferno/Vue + Cerebral | FelaJS + atomic CSS + PostCSS | faire des tests | mettre des linters
illustration d'un développeur étudiant le paysage du front-end
La liseuse - Jean-Honoré Fragonard
Développeur étudiant le paysage front-end actuel - illustration

Gestion des dépendances


yarn, npm, bower

Les problèmes

  • Trop d'outils
  • Outil dépassé (Bower)
  • Outils qui font la même chose (et pas forcément de la façon la plus optimale)
  • Conflits entre les fichiers

La techno

npm, le seul, l'unique

Ce qui peut être contraignant

Cela exige que chaque membre de l'équipe mette à jour sa version de Node et de npm, pour des raisons de performance et de disponibilité de certains outils (npx, package-lock.json) et de placer un petit avertissement sur le repo de chaque projet pour préciser la version minimale de ces 2 outils.


Task running


gulp, assetic, maba:webpack

Les problèmes

  • Trop d'outils qui font plus ou moins la même chose plus ou moins bien
  • C'est lourd
  • C'est lent (vraiment très lent)
  • Parfois on ne sait pas trop ce qui se passe sous le capot
Illustration d'un développeur devant composer avec ses outils de build
Les remords d'Oreste - Jean-Honoré Fragonard
Développeur fuyant son workflow - illustration

La techno

Webpack à la rescousse !

Pourquoi c'est bien

  • transpile, compile, bundle tout ce qu'on veut
  • on peut créer des configurations qui traiteront nos fichiers de façons à répondre aux besoins d'un environnement de développement (automatisation des tâches de transpilage/compilation rapide, hot module replacement, live-reload, sourcemaps, remote testing) et de production (minification et concaténation des fichiers, élimination du code mort, ajout des polyfills et préfixes pour le cross-browser/cross-platform)
  • code splitting (pratique permettant l'import dynamique de fichier, ce qui permet de réduire la taille finale du bundle)
  • tree shaking (élimination du code mort)
  • one config to run them all
  • doc facile à appréhender, communauté au top (Sean Thomas Larkin en est le parfait exemple)

Pourquoi ça peut être contraignant

  • La création des fichiers de configuration peut être extrêmement longue et/ou complexe. Quoique, cette tendance semble vouée à disparaître avec la version 4 de Webpack qui cherche à réduire cette complexité (#0CJS)
  • Il faut avoir une bonne connaissance de ce que peut offrir l'environnement Webpack ainsi que celui des autres outils qu'on souhaite utiliser (comme Babel par exemple)

Les fichiers

  • un ou plusieurs webpack.config.js (typiquement, webpack.dev.jspour les tâches spécifiques au développement, webpack.prod.js pour celles propre à la production, et enfinwebpack.common.js pour les tâches communes aux 2 environnements)
  • un .babelrc (fichier de configuration de Babel non obligatoire, on peut préciser cette configuration directement dans Webpack mais recommandé)

Front


Framework JS


Angular 1, jQuery (en plusieurs versions), jQuery UI, Vue 0.x, React 15.x

Les problèmes

  • Versions lourdes et dépréciées
  • Frameworks/librairies non adaptées à la façon dont on travaille côté front aujourd'hui (approche par composant).

Technos sûres

Syntaxe ES6+, la seule qui nous convienne

Proposition de technos aditionnelles Inferno possède une syntaxe identique à React, compatible avec des components écrits en React, mais plus léger et plus performant. Cette librairie permet d'appliquer les lifecycles hooks (componentDidMount(), componentShouldUpdate() ...) sur les function components (contrairement à React qui exige lui de créer une classe dès qu'on veut plus qu'un render(), ce qui impacte sur les performances de l'application). Inferno présente un écosystème complet avec un router et plusieurs state manager.

Vue présente une syntaxe similaire à Angular 1 (paraît-il), une lib que j'ai trouvée très facile à prendre en main en plus d'un écosystème complet (router, state manager), une grosse communauté et des documentations à tomber par terre.

illustration d'un développeur tenté par deux frameworks Javascript
L'Assaut - William-Adolphe Bouguereau
Développeur devant choisir un framework Javascript - illustration

Toutefois, à force de travailler avec React, j'ai fini par apprécier sa syntaxe autant que celle de Vue. C'est par ailleurs le framework que nous utilisons pour tous nos projets les plus récents. Inferno semble donc être une alternative intéressante.

Quant à jQuery, j'espère que nous ne l'utiliserons plus jamais. Non pas que ce soit un mauvais outil, mais aujourd'hui, on peut faire tout ce que proposait jQuery en ES5 tout aussi facilement (et sans importer toute une librairie!).

Par ailleurs, de nos jours, on trouve toujours un portage ES6/ES5, React, Vue ... de quasi tout ce qu'on veut, donc plus d'excuse pour les projets qui seront basés sur la stack 2.0 !


State manager


Redux

A l'heure actuelle, nous avons seulement utilisé Redux. C'est un très bon outil, la réflexion derrière est géniale, mais je trouve à l'outil quelques défauts:

  • la courbe d'apprentissage, assez élevée
  • la quantité de code à écrire
  • les reducers qui sont parfois vraiment incompréhensibles
  • on peut vite faire n'importe quoi sans s'en rendre compte

En alternative, j'ai pu tester Cerebral. C'est un outil intéressant qui, à la différence de Redux nous fait travailler avec des structures mutables. Son écosystème rappelle celui de Redux (formulaires, requêtes http, router, firebase....). Le principal défaut est le manque de retours d'expérience et de ressources, ce à quoi la communauté (par ailleurs très réactive) travaille activement grâce à des vidéos et à d'avantage d'exemples dans la documentation.

Je ne parle pas de Mobx, que je n'ai jamais testé, mais si vous avez une expérience dessus (ou sur tout autre state manager), n'hésitez pas à en faire part (dans les commentaires) !


CSS


Sass, Bootstrap, BEM, Trowel, PostCSS (un peu)

Les problèmes

Le CSS lui-même pose les problèmes suivants :

  • la spécificité
  • le global namespace
  • le code mort
  • le nommage.

Que signifient ces problèmes plus exactement ? Tout d'abord, il faut avoir connaissance d'absolument toutes les classes utilisées au sein d'un projet (même celles des librairies externes), au risque de voir le style que l'on souhaite appliquer ne pas l'être à cause d'autres règles de style définies ailleurs dans le projet et présentant une spécificité plus importante (car exécutée après notre règle ou avec un sélecteur plus puissant), ce qui inclut un temps de débuggage parfois long... On a aussi énormément de code mort, même en utilisant un styleguide (notamment venant des librairies externes), ce qui impacte:

  1. la lisibilité
  2. la performance


Pandemonium - John Martin
Développeur face à du CSS - illustration

Sass/SCSS, quant à lui, est un peu comme une version OGM de CSS : ce n'est pas du CSS, mais un autre langage qu'on doit compiler pour obtenir du CSS. Les features CSS4 (qui sont pour certaines déjà dispo, comme les variables), ne sont donc pas disponibles dans Sass, ou prennent une toute autre syntaxe. Ce préprocesseur embarque par ailleurs une panoplie de fonctionnalités dont nous ne nous servons pas forcément.

PostCSS lui, est CSS en version cyborg : c'est une version augmentée qui ne dénature pas CSS et respecte sa syntaxe ; en gros c'est toujours du CSS, en version Iron Man (ou Batman). A la différence de Sass, PostCSS est modulaire. Si vous utilisez Autoprefixer, vous utilisez PostCSS.

BEM est une convention de nommage (Block Element Modifier). Seulement voilà, nommer les choses, c'est dur. On a aussi des conventions de nommage différentes selon les librairies, qui, additionnées à nos propres conventions, rendent le code inconsistant.

Trowel est cool mais est jeune, n'a pas de communauté forte et on ne sait pas vraiment quel chemin le projet va prendre (ou si il va continuer son chemin). Il repose par ailleurs sur SCSS/Sass, un outil que j'aimerais que nous arrêtions d'utiliser, pour les raisons citées plus haut.

Bootstrap, la célèbre librairie nous donne trop ou pas assez de thèmes, embarque jQuery, des composants inutilisés mais quand même chargés, ajoute des règles dont nous n'avons pas besoin sur une classe (la classe btn, utilisée -normalement- pour les boutons ajoute plus de 450 règles de style à l'élément auquel elle est appliquée dans la version 3 de Bootstrap). Un autre problème reste la "patte" Bootstrap : vous oubliez de customiser un élément et un visiteur se dira aussitôt "tiens, ça me fait penser à un autre site !".

Propositions de technos

  • FelaJS, une librairie permettant de faire du CSS-in-JS qui permet entre autres:
    • du theming
    • la génération de classes CSS atomiques (une propriété = une classe)
    • namespace local au composant (et non plus global), donc élimination du code mort (un composant qui n'apparaît pas dans l'UI ne voit pas son style injecté dans la page)
    • du style dynamique. Voilà à quoi ressemble un composant stylisé grâce à Fela :


import { createComponent, Provider } from 'inferno-fela'
import { render } from 'inferno'

const rule = state => ({
  textAlign: 'center',
  padding: '5px 10px',
  background: state.primary ? 'green' : 'blue',
  fontSize: '18pt',
  borderRadius: 5,
  ':hover': {
    background: state.primary ? 'chartreuse' : 'dodgerblue',
    boxShadow: '0 0 2px rgb(70, 70, 70)'
  }
})

const Button = createComponent(rule, 'button')

render(
  <Provider renderer={renderer}>
    <Button primary>Primary</Button>
    <Button>Default</Button>
  </Provider>,
  document.body
)


  • PostCSS, pour du post-processing si besoin (autoprefixer, fallback pour certaines règles non reconnues, génération des règles @font-face, optimisation...)

  • Tailwind CSS, une librairie de classes utilitaires et atomiques. A la différence d'un framework en kit comme Bootstrap ou Foundation, une classe = une règle CSS. Au début je n'approuvais pas du tout cette approche, mais au final, elle permet de résoudre un bon nombre de problèmes, dont le nommage, la spécificité, le theming et le code mort. On a aussi un CSS plus léger puisqu'on ne déclare pas plusieurs fois la même règle dans plusieurs classes différentes et on sait ce qui est appliqué à un élément et à quoi il va ressembler, ce qui permet également, quand on teste la structure d'un composant, de tester également s'il y a régression visuelle. En outre, Tailwind nous permet de générer exactement toutes les classes utilitaires que nous souhaitons, ni plus, ni moins.

  • Les CSS-Modules, qui comme Fela, scopent le style à leur composant et éliminent donc les problèmes de spécificité et de namespace.


Tests


A l'heure actuelle, nous n'avons rien en place pour tester le front. Or, parfois, quand un fix CSS (ou JS) est fait, ça casse quelque chose quelque part ailleurs sur le site (notamment à cause des problèmes de spécificité et du namespace global pour ce qui est question du CSS). Et on ne s'en rend pas forcément compte.

Je n'ai personnellement jamais écrit de tests, mais voici quelques librairies qui ont l'air intéressantes :


Consistance du code


scsslint

Actuellement, nous ne lintons que le CSS/SCSS (le lint est la vérification par un outil appelé linter de la bonne application de certaines règles d'écriture pour du code, par exemple ne pas laisser de variable non utilisé ou encore ne pas nommer 2 variables avec le même nom).

Le problème, c'est que pour voir si son code suit bien ces règles, un développeur doit soit :

  • lancer la commande pour linter son code et ainsi lever des warnings/erreurs (ce qui n'arrive jamais)
  • avoir le linter installé dans son IDE (ce qui est rarement le cas)

Mais à ce jour, que le code de nos feuilles de style respecte ces règles ou pas, il est quand versionné sans même qu'aucune vérification ne soit faite.

Par ailleurs, la core team de Sass étant en train de réécrire le langage en Dart et non plus en Ruby, il est recommandé de changer d'outil pour linter son SCSS.

illustration de développeurs s'apercevant que tous leurs outils sont obsolètes
Le rendez-vous - Jean-Honoré Fragonard
Développeurs se rendant compte que leur stack front est obsolète du gestionnaire de dépendances jusqu'au linter

Proposition de technos

  • Linter JS: ESLint
  • Linter style: Stylelint
  • Formateur: Prettier, qui va s'attarder sur la forme du code et non le fond, indépendamment de s'il s'agit de Javascript ou de CSS
  • Git hook: Husky, un outil qui permet, avant chaque commit ou chaque push, d'exécuter des scripts. Par exemple, formater puis linter notre code avant de le tester. Si les tests ne passent pas ou si le code ne respecte pas les règles de conduite définies, alors il ne sera pas commité ou pushé.

Cette cartographie de notre workflow et nos outils front-end ont permis de mettre en relief tous les problèmes que nous pouvions rencontrer, que ce soit en période de développement ou de maintenance.

Cette étape est cruciale car elle permet de bien souligner nos besoins et nous indique le genre d'outil et de méthodologie qui pourrait nous convenir.

Prochaine étape: la mise en place de notre nouvelle stack et de notre nouveau workflow !


comments powered by Disqus

Nos derniers articles