Cyrille Perois
Lead front-end developer @ Wandi Teaches front-end development @ IUT Paris Descartes
Programmation web - client riche
L'outillage
Utiliser quelques outils pour rendre notre developer experience (DX) plus agréable, être plus productif et professionnel
Code ES2018+
Code ES5
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
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
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.
npm install --save-dev babel-preset-env
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}]
]
}
.babelrc
npm run build
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
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
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
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 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
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 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.
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{ loader: "babel-loader" }
]
}
]
}
};
webpack.config.js
npm install --save-dev babel-loader babel-core
npm run watch
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...
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.
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
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.
Il est pratique d'afficher les erreurs directement dans son éditeur de code.
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
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
Vous savez maintenant...
By Cyrille Perois