Le blog

Quand un développeur PHP teste TailwindCSS v2

Publié le 21 novembre 2020

J'ai récemment voulu tester la version 2 de TailwindCSS. Avant de commencer cet article, je préfère vous prévenir : je n’aime pas le front ! Je suis un pur développeur PHP, j'aime la console et les appels curl.

Pour remettre dans le contexte, dans le cadre d'un cours que je donnais à des étudiants en 4e année d'informatique, nous avons réalisé un petit système de matchmaking entre amis. Pour rendre le tout un peu joli, je me suis dit d’essayer tailwindCSS vu que tout le monde en parle. Résultat des courses – et cela n'engage que moi – je suis moyennement convaincu et j'aime autant écrire mon CSS. Laissez moi vous expliquer pourquoi.

En tant que développeur back, j'ai déjà travaillé avec Jquery, Babel, Backbone, Angular, React, Vuejs, Vanillajs, Bootstrap, Yeti-css, Bulma-css, Foundation, MaterialUi et j'en passe. Même si le front n'est absolument pas mon domaine d'expertise, le temps m'a appris à déceler ce que j'aime de ce que je n'aime pas quand je dois intervenir sur un projet dans ces parties. Le projet sur lequel je me suis amusé était une composition Symfony/Twig des plus classiques.

Pour commencer, on fait l'installation avec Symfony et je choisis d'utiliser Webpack Encore :

symfony composer require symfony/webpack-encore-bundle

J'installe ensuite les dépendances de Tailwind :

yarn add --dev @symfony/webpack-encore tailwindcss postcss-loader autoprefixer 

Avec ces deux commandes, je dispose d'un répertoire `assets` et `node_modules` à la racine de mon projet. Il contient mes images, CSS et JS. J'ai également le package.json pour les dépendances et le webpack.config.js pour configurer la compilation. Je vais devoir ajouter dans tout ce fatras le style de Tailwind. Je crée alors le fichier `assets/styles/tailwind.css` :

@tailwind base;
@tailwind components;
@tailwind utilities;

Je vois également que je peux créer un fichier de configuration `tailwind.config.js` à la racine du projet pour venir personnaliser la configuration de base. Je ne sais pas encore ce que je vais en faire, mais allons-y :

module.exports = {
  theme: {
    extend: {}
  },
  variants: {},
  plugins: [],
  prefix: '',
}

Pour charger tout ça, la doc m'indique que je dois utiliser l'outil `postcss` si je travaille avec Webpack. Hop hop hop ! Par contre, la doc n'indique pas son usage, j'ai dû fouiner sur internet. Je crée le fichier `postcss.config.js` à la racine du projet : 

const tailwindcss = require('tailwindcss');
module.exports = {
    plugins: [
        tailwindcss('./tailwind.config.js'),
        require('autoprefixer'),
        require('postcss-import')
    ]
}

Je n'ai pas encore compilé mais, je suis confiant (mais si naïf !). Au tour de Webpack : je modifie la configuration pour lui donner les plugins et CSS à manger.

Le CSS :

    .addStyleEntry('tailwind', './assets/styles/tailwind.css')

Suivi de l’activation de `postcss` :

.enablePostCssLoader((options) => {
    options.config = {
        path: './postcss.config.js'
    };
})
yarn encore dev

BOOM Error, le naïf... J'ai 2 problèmes, j'ai besoin de `postcss-import`. Qu'à cela ne tienne :

yarn add postcss-import
yarn encore dev

BOOM Error, le naïf...

Tailwind utilise le très récent `postcss` dans sa version 8, mais mon Webpack l'utilise dans sa version 7. J'ai un petit problème de compatibilité, je fouine, je fouine et ouf ! Dans la doc de Tailwind, ils ont anticipé ce problème et ça, j’apprécie :

yarn remove tailwindcss postcss-import postcss-loader autoprefixer
yarn add tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
yarn add postcss-loader@^3.0.0 postcss-import@^12.0

Dès que mes autres dépendances auront fait la mise à jour je pourrais supprimer la couche de compatibilité :

yarn remove tailwindcss @tailwindcss/postcss7-compat
yarn add tailwindcss@latest postcss@latest autoprefixer@latest
yarn encore dev

Joie ! Naïf Niveau 2 !

Il ne me reste plus qu'à parcourir la doc, les paradigmes et exemples d'intégration pour tenter de rendre quelque chose. Des colonnes, des boutons, un menu, du responsive, des tableaux, un login, de quoi créer un compte. Voilà la somme des éléments que j'ai intégrés durant ma soirée, avec Independence Day en fond (le 2 n’existe pas à mes yeux). Après 2h33 minutes, voici un aperçu du résultat : 

Le résultat" title="Le résultat

Je ne suis pas fan dans l'immédiat de Tailwind. Oui, ça marche, ça compile et fait un plus petit fichier CSS. Par contre, si je l'utilise tel quel j'obtiens du HTML pas très appétissant à lire :

<div class="relative z-10 pb-8 bg-white sm:pb-16 md:pb-20 lg:w-full lg:pb-28 xl:pb-32">
    <div class="relative pt-6 px-4 sm:px-6 lg:px-8">
        <nav class="relative flex items-center justify-between sm:h-10 lg:justify-start" aria-label="Global">
            <div class="flex items-center flex-grow flex-shrink-0 lg:flex-grow-0">

Ou encore : 

<div role="menu" aria-orientation="vertical" aria-labelledby="main-menu">
    <div class="px-2 pt-2 pb-3 space-y-1" role="none">
        {% if is_granted('ROLE_ADMIN') %}
            <a href="{{ path('lobby') }}"
               class="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
               role="menuitem">Rejoindre le lobby</a>
            <a href="{{ path('lobbyPending') }}"
               class="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
               role="menuitem">Visualiser le lobby</a>
        {% else %}
            <a href="{{ path('lobby') }}"
               class="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
               role="menuitem">Rejoindre le lobby</a>
            <a href="{{ path('match_maker_index') }}"
               class="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
               role="menuitem">Consulter mes matchs</a>
        {% endif %}
    </div>
    <div role="none">
        <a href="{{ path('app_logout') }}"
           class="block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100"
           role="menuitem">
            Se déconnecter
        </a>
    </div>
</div>

Pour faire propre, il faut passer un temps monstrueux à faire des agrégations :

.menu__link {
    @apply block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100;
}

Le `@apply` permettant la détection par Tailwind dans le CSS.

Au final, si je dois passer tout ce temps à apprendre leur nomenclature pour traduire dans ma tête ce que ça fait en vrai CSS et l'appliquer à nouveau, le vieux que je suis n'est pas convaincu.

À ce compte-là j'aime autant la satisfaction de peaufiner mon CSS en l'écrivant sans surcouche : j'aurais le même résultat et de la frustration de phase de découverte en moins. En début d'année, j'ai passé un peu (c'est faux, des heures) de temps sur la chaîne Youtube de Kevin Powell. Ses vidéos sont de vraies pépites pour ceux qui, comme moi, ne sont pas super super forts en intégration CSS mais qui veulent se débrouiller et découvrir comment réaliser des intégrations de pages complètes en partant du mobile-first vers le full-desktop.

Je vois vraiment Tailwind comme un assistant sous stéroïdes de l'intégrateur indécis. Selon moi, on va aussi vite – voire plus vite – à intégrer une maquette passée entre les mains d'un bon webdesigner que de peaufiner la configuration de Tailwind et de nos classes intermédiaires. Bien entendu, je ne suis pas fermé aux réflexions et approches plus modernes. En lisant l'article de Adam Wathan, je comprends bien qu'il y a les 2 écoles mais à titre personnel, je n'aime pas avoir 27 classes sur mon HTML. Un "Hardcore" intégrateur en accord avec l'article de Adam trouvera des choses à reprocher à mon point de vue mais comme je ne suis pas un développeur front, je n'ai pas la même sensibilité.

Petit point intéressant à suivre pour Tailwind, c'est qu'en cas de "pas le choix" et "faut aller vite" ils ont un site de snippets avec des cas d'usage : https://tailwindui.com/. Il y a quelques snippets offerts (une vingtaine je dirais, je n'ai pas compté, et je viens de fermer l'onglet ^^') et pour les autres il faut payer. À côté de ça, AlpineJS ça marche aussi. Je n’ai pas fait grand chose avec (juste des transitions et de l'affichage #jQueryNextGen) mais on trouve la même approche que React/Vue : des attributs dans les balises HTML, des directives, quelques variables d'état, un peu de réactivité... Ça fait le job quand on n’a pas grand-chose à faire. On a la possibilité de "bind" une directive avec une fonction JS pour ajouter du comportement. Ça peut s'avérer utile, mais sachant à l'avance que le projet va grandir, j'aime autant mettre directement Vuejs ou React. Quitte à choisir un entre-deux, ce serait SvelteJS. Mais je ne m’étendrai pas plus sur le sujet, ce n’est pas le but de cet article.

Pour conclure, certains y trouveront leur compte, ce qui n'est pas mon cas, mais je peux comprendre l'engouement dont je soupçonne l'habile campagne marketing de Tailwind d'y être pour quelque chose.

Merci de m'avoir lu, et à bientôt !

Grégoire Hébert

Grégoire Hébert

Principal developer

Mots-clésCSS, jQueryNextGen, Tailwind

Le blog

Pour aller plus loin