Voyagez dans le temps avec Babel

Chaque année de nouvelles fonctionnalités sont ajoutées au langage JavaScript. Certaines sont si sexy qu'on aimerait les utiliser dès aujourd'hui !

Parmi elles, on trouve l'object spread ou les class properties qui arriveront dans ES2018 ou ES2019.

// Object spread
const coords = { x: 1, y: 2 }
const clonedCoords = { ...coords }

// Class properties
class Car {
  color = 'red'
}

Avant de passer dans le langage, les nouvelles fonctionnalités de JavaScript sont implémentéees sur les dernières versions Chrome, Firefox ou Edge. Le hic c'est que vos utilisateurs n'utilisent pas tous les dernières versions des meilleurs navigateurs... ça serait trop facile !

Plus généralement, la sortie de JavaScript ES6 en 2015 a apporté beaucoup de nouveautés mais les utilisateurs ne sont pas équipés pour lire du code ES6, ES2016, ES2017 et encore moins ES2018.

Alors comment faire ?

Babel à la rescousse !

Babel autrefois appelé 6to5 est arrivé en même temps qu'ES6 avec une seule mission: convertir notre code moderne en code lisible et compréhensible par tous les navigateurs, même les plus anciens.

Plus généralement, on appelle "transpiler" le fait de passer d'un langage à un autre sans pour autant rendre le code illisible.

Babel est open-source, il est largement adopté par la communauté JavaScript et compte plus de 24000 stars sur GitHub. Il a su faire ses preuves et sa fiabilité n'est plus à remettre en cause.

Babel exemple

Génial, mais comment l'utiliser ?

Installation de Babel

Comme tous les outils de l'écosystème JavaScript, Babel s'installe via "npm" en ligne de commande. Il est conseillé d'installer Babel dans le répertoire de votre projet afin d'avoir une version fixe par projet. Ça vous évitera des mauvaises surprises lors des mises à jour.

Il vous suffit de taper la ligne de commande suivante :

npm i babel-cli

Une fois installé, il faut choisir les "presets" (ie: ensemble de plugins) à utiliser selon les fonctionnalités et les navigateurs que vous voulez couvrir.

Le plus simple pour configurer Babel est d'utiliser la preset "babel-env". C'est une preset magique qui détermine automatiquement les transformations que Babel doit appliquer, en fonction des navigateurs que vous souhaitez supporter. Pour les plus curieux, "babel-preset-env" croise les données du tableaux de compatibilité Kangax avec le système de ciblage de navigateurs Browserlist.

Il vous suffit d'installer la preset Babel :

npm i babel-preset-env

Et d'ajouter un fichier .babelrc à la racine de votre projet avec les navigateurs que vous souhaitez cibler :

// .babelrc
{
  "presets": [
    ["env", {
      "targets": {
        // les 2 dernières versions des navigateurs + Internet Explorer >= 7
        "browsers": ["last 2 versions", "ie >= 7"]
      }
    }]
  ]
}

"babel-preset-env" supporte uniquement les fonctionnalités disponibles dans la dernière spécification JavaScript (ES2017). Si vous souhaitez utiliser d'autres fonctionnalités, il vous faut les installer séparément via des plugins Babel.

Par exemple si vous souhaitez ajouter les class properties et l'object rest spread, vous installerez deux plugins :

npm i babel-plugin-transform-class-properties babel-plugin-transform-object-rest-spread

Il faut également les ajouter à votre configuration :

// .babelrc
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "ie >= 7"]
      }
    }]
  ],
  "plugins": [
    "transform-class-properties",
    "transform-object-rest-spread"
  ]
}

Babel n'ajoute pas de script à votre page. Une fois le code transpilé, vous envoyez le code généré sur le serveur.

Voilà la commande pour transpiler le fichier "my-modern-js-file.js" et obtenir un code compatible avec toutes les versions de navigateurs ciblées.

./node_modules/.bin/babel my-modern-js-file.js

Babel + Webpack

Si vous souhaitez utiliser Babel avec Webpack, vous devez installer le loader Wepack.

Tapez la ligne de commande suivante :

npm i babel-loader

Et modifiez votre fichier de configuration Webpack :

// webpack.config.js
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['babel-preset-env']
        }
      }
    }
  ]
}

Les limites de Babel

Babel est un transpileur qui supprime le sucre syntaxique. Il arrive que les nouvelles fonctionnalités du langage aillent plus loin que simplement introduire une nouvelle syntaxe.

Prenons le cas de la méthode Array.prototype.includes, ajoutée dans ES2017, qui permet de tester si un élément est inclus ou non dans un tableau.

Voici un exemple de code ES2017 :

const books = ['Harry Potter', 'Lord of the Rings']
console.log(books.includes('Harry Potter')) // true

Voilà le même code, une fois transpilé par Babel :

'use strict';

var books = ['Harry Potter', 'Lord of the Rings'];
console.log(books.includes('Harry Potter')); // true

La fonction includes est toujours présente alors qu'elle fait partie de ES2017 et le code transpilé par Babel n'est pas compatible avec tous les navigateurs. Mais alors comment faire ?

Pour combler les fonctions manquantes il existe une solution plus ancienne que Babel et elle est toujours d'actualité : les polyfills.

Qu'est-ce qu'un polyfill ?

Un polyfill est un code JavaScript qui permet de simuler une fonction ou un objet s'il n'est pas disponible dans le navigateur.

Un exemple de polyfill pour includes :

if (!Array.prototype.includes) {
  Array.prototype.includes = function (value) {
    return this.indexOf(value) !== -1
  }
}

Babel vous propose un set de polyfills, il comporte les polyfills pour toutes les fonctionnalités apparues entre ES5 et ES2017.

Pour l'installer :

npm i babel-polyfill

Et pour l'utiliser, il vous suffit de l'importer dans le code de votre application :

import 'babel-polyfill'

Le polyfill s'applique uniquement si la fonctionnalité n'est pas présente. Par contre, le code du polyfill, est chargé par tous les navigateurs, et ça, même s'ils n'en ont pas besoin. Ça a pour conséquence d'alourdir le code et de dégrader les performances. Pour éviter cela, il existe un service : polyfill.io.

Polyfill.io est intelligent, il détecte la version du navigateur et charge uniquement les polyfills nécessaires pour ce navigateur : un gros fichier pour IE9 et un petit fichier pour Chrome 60.


Il reste néanmoins certains problèmes que Babel et les Polyfills ne peuvent pas résoudre. Certaines fonctionnalités ne sont ni "transpilables", ni "polyfillables". C'est le cas par exemple des Proxy ES2015 et de la plupart des fonctionnalités CSS.

Il est donc important de bien vérifier le support de toutes les fonctionnalités que vous souhaitez utiliser. Pour cela vous pouvez vous aider du site caniuse et aller voir s'il existe une solution via Babel ou les Polyfills. Si aucune solution n'existe, il vous faudra faire preuve de patience et attendre que vos utilisateurs se mettent à jour !