Programmation web - client riche

L'outillage

Ce que nous allons faire aujourd'hui

Utiliser quelques outils pour rendre notre developer experience (DX) plus agréable, être plus productif et professionnel

  • Utiliser une syntaxe récente sans nous soucier du support des navigateurs (Babel)
  • Utiliser un système de modules (Webpack)
  • Analyser notre code à la recherche d'erreurs (ESLint)

Babel

Code ES2018+

Code ES5

Babel : installation

npm install --save-dev babel-cli
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "babel src -d dist"
  },
  "devDependencies": {
    "babel-cli": "^6.0.0"
  }
}
package.json
npm run build

Babel : les presets et les plugins

De base, Babel ne sait rien faire. Il ne transforme pas directement notre code car il ne sait pas ce qu'on souhaite faire.

Pour lui dire ce qu'on souhaite faire, on utilise des plugins et des presets.

Un plugin se focalise sur un seul « bout » de syntaxe. Par exemple, le plugin babel-plugin-transform-es-2015-classes s'occupe uniquement de transformer la syntaxe « class » en bonnes vieilles fonctions

Un preset est un ensemble de plugins. Par exemple le preset babel-preset-es2015 regroupe tous les plugins qui transforment les différentes syntaxes de ES2015

Babel : le preset env

Le preset le plus intéressant est babel-preset-env.

Celui-ci ne s'arrête pas à une année en particulier mais évolue constamment (il est mis à jour à chaque nouvelle spécification).

De plus, on lui dit quels navigateurs on souhaite supporter, et il ne fait que les transformations nécessaires pour ceux-ci.

Babel : le preset env

npm install --save-dev babel-preset-env
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}
.babelrc
npm run build

Babel : le mode watch

Lancer le script build à chaque modification devient vite contre-productif. Pour éviter ça, Babel propose un mode « watch » qui observe les modifications faites sur nos fichiers et les recompile à la volée.

{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "babel src -d dist",
    "watch": "babel src -w -d dist"
  },
  "devDependencies": {
    "babel-cli": "^6.0.0"
  }
}
package.json
npm run watch

Les modules

Dans l'environnement NodeJS, vous avez l'habitude d'écrire des modules :

const add = (a, b) => a + b;

module.exports = add;
const add = require("./add.js");

console.log(add(42, 8000));
add.js
index.js

Les modules

Malheureusement, dans le navigateur...

On aimerait pourtant bien pouvoir écrire notre code de manière modulaire, même pour le navigateur !

Pourquoi ne pas passer par une phase d'analyse des différentes dépendances entre nos modules, et construire un seul fichier JS qui contiendrait tous les modules rassemblés ?

C'est l'idée de

Webpack : installation

npm install --save-dev webpack webpack-cli
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack --mode=development",
    "watch": "babel src -w -d dist"
  },
  "devDependencies": {
    "babel-cli": "^6.0.0",
    "babel-preset-env": "^1.6.1",
    "webpack": "^4.0.1",
    "webpack-cli": "^2.0.10"
  }
}
package.json
npm run build

Par défaut webpack prend src/index.js comme point d'entrée, et écrit le résultat dans build/main.js

Webpack : le mode watch

Webpack propose aussi un mode watch qui relance la compilation à chaque modification :

{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack --mode=development",
    "watch": "webpack --mode=development -w"
  },
  "devDependencies": {
    "babel-cli": "^6.0.0",
    "babel-preset-env": "^1.6.1",
    "webpack": "^4.0.1",
    "webpack-cli": "^2.0.10"
  }
}
package.json
npm run watch

Heu... wait !

On peut écrire des modules, mais où est passé Babel dans l'histoire ?

Il faudrait qu'à chaque fois qu'il tombe sur un module, Webpack passe le fichier dans Babel avant de l'ajouter au bundle...

Webpack : les loaders

Webpack intègre un tel système, on appelle ça des loaders

Le concept est simple : dans un fichier de configuration, on définit une liste de règles. À chaque fois que Webpack rencontre un module, il le confronte à ces règles. Lorsqu'une règle correspond au module, alors il passe le module dans les loaders que nous avons associés à cette règle.

Ainsi, nous allons pouvoir écrire une règle qui va passer tous les fichiers dont l'extension est « .js » dans un loader Babel.

Webpack : les loaders

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          { loader: "babel-loader" }
        ]
      }
    ]
  }
};
webpack.config.js
npm install --save-dev babel-loader babel-core
npm run watch

Webpack : les loaders

Ce système de loaders permet de faire énormément de chose. Des loaders pour quasiment tous les types de fichiers existent : css, images, fonts, json...

Les modules ES2015

const add = (a, b) => a + b;

export default add;
import add from "./add.js";

console.log(add(42, 8000));
add.js
index.js

Webpack reconnait cette syntaxe par défaut et fonctionne très bien avec. C'est donc devenu la syntaxe utilisée partout et par tout le monde

Le but de cet outil est de confronter notre code à un certain nombre de règles, et soulever une erreur ou un avertissement lorsqu'une règle n'est pas respectée

ESLint embarque un bon nombre de règles. Par défaut celles-ci sont toutes désactivées. C'est à nous de dire à ESLint les règles que nous souhaitons activer.

Un système de plugins permet d'y ajouter de nouvelles règles.

ESLint : installation

npm install --save-dev eslint
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack --mode=development",
    "watch": "webpack --mode=development -w",
    "lint": "eslint src/*"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.3",
    "babel-preset-env": "^1.6.1",
    "eslint": "^4.18.2",
    "webpack": "^4.0.1",
    "webpack-cli": "^2.0.10"
  }
}
package.json
npm run lint

ESLint : créer un fichier de configuration

Au premier lancement, ESLint renvoie une erreur expliquant qu'il n'a pas trouvé de configuration.

Il nous propose de créer un fichier de configuration avec la commande :

eslint --init

ESLint nous pose quelques questions et crée un fichier de configuration selon nos réponses.

ESLint : afficher les erreurs dans son éditeur

Il est pratique d'afficher les erreurs directement dans son éditeur de code.

 

Des plugins existent pour la plupart des éditeurs.

ESLint : interfaçage avec Webpack

npm install --save-dev eslint-loader
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack --mode=development",
    "watch": "webpack --mode=development -w",
    "lint": "eslint src/**/*"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.3",
    "babel-preset-env": "^1.6.1",
    "eslint": "^4.18.2",
    "eslint-loader": "^2.0.0",
    "webpack": "^4.0.1",
    "webpack-cli": "^2.0.10"
  }
}
package.json
npm run watch

ESLint : interfaçage avec Webpack

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        enforce: 'pre',
        use: [
          {
            loader: 'eslint-loader',
            options: {
              failOnError: true,
              fix: true
            },
          },
        ],
      },
      {
        test: /\.js$/,
        use: [
          { loader: 'babel-loader' },
        ],
      },
    ],
  },
};
webpack.config.js

Eh ben voilà.

Vous savez maintenant...

  • Écrire du JS
  • Manipuler le DOM et son style
  • Réagir à des événements
  • Faire des choses asynchrones (dont des requêtes AJAX)
  • Mixer tout ça pour faire une requête AJAX à la soumission d'un formulaire, créer des éléments à partir des données reçues et les insérer dans le document
  • Qu'il faut écrire des composants (avec React ou autre)
  • Mettre en place des outils pour automatiser votre workflow

Des questions ?

Programmation web - client riche - L'outillage

By Cyrille Perois

Programmation web - client riche - L'outillage

  • 677