Présentation

ReactJs est un framework JavaScript qui a été concu par les équipes de Facebook. Il permet de développer des applications web modernes en utilisant la notion de composants. Plus précisément, il correspond à la partie vue du modèle MVC.

Il existe beaucoup d’articles et de tutoriels qui permettent de prendre en main cette technologie. Et comme beaucoup de monde, après en avoir fait un certain nombre, j’ai voulu mettre en place ReactJs dans un projet.

C’est à ce moment que les choses se sont un peu compliquées. En effet, cela n’est pas un secret, l’écosystème JavaScript est très dense, trop dense si vous voulez mon avis… et il existe plusieurs façons d’arriver au même résultat. Ne voulant pas récupérer « à l’aveugle » la configuration d’un projet « clé en main », j’ai commencé à chercher une configuration minimale pour pouvoir débuter avec ReactJs dans de bonnes conditions.

Le but de ce tutoriel est de créer un projet « from scratch » utilisant ReactJS.

Comme souvent en JavaScript, le premier obstacle est le manque de documentation des différents outils et le second est de s’orienter parmis les possibilités qui nous sont offertes. En effet, bien que ReactJs puisse fonctionner en « stand alone », il existe beaucoup d’outils pour vous simplifier la vie. Par exemple, il serait dommage de s’en priver du hot-reload qui permet de mettre à jours automatiquement votre application dans un navigateur quand le code est modifié !

En plus de ReactJs nous allons donc utiliser quelques outils et technologies qui simplifieront le développement. Si comme moi vous ne maîtrisez pas tous ces outils, ne vous inquiétez pas, nous allons les passer en revue et identifier ce qu’il est nécessaire de savoir !

Nous utiliserons la configuration suivante pour créer le projet :

  • es6
  • jsx
  • babel
  • webpack
  • webpack-dev-server

Si tout se passe bien, dans 30 minutes, le projet devrait ressembler à cela :

Environnement ReactJs

Et comme annoncé plus tôt, la cerise sur le gâteau, le live reload :

ReactJs live reload

Contexte

ES6

ECMAScript 6 (ou ES6) est un standard d’implémentation pour JavaScript qui ajoute de nouvelles syntaxes au JavaScript actuel.

Nous utiliserons les éléments d’ES6 suivants :

Il faut savoir que la syntaxe ES6 n’est pas supportée par les navigateurs actuels. Heureusement pour nous, il existe des outils qui transpilent (transforment) automatiquement le code ES6 en code JavaScript standard qui lui est supporté. Dans notre cas, c’est Babel qui s’occupera du sale boulot.

Plus de détails sur ES6

JSX

JSX est une extention de la syntaxe JavaScript qui permet d’écrire du code sous forme de balises directement dans un JavaScript. Par exemple avec JSX nous pouvons écrire :

var element = <div id="main-element" class="title" >Hello, world!</div>;

Il s’agit simplement d’un sucre syntaxique qui doit être transformé en code JavaScript pour pouvoir être compréhensible par un navigateur. Dans notre cas, c’est Babel qui va transformer ce code JSX en composant JS utilisant ReactJS. L’exemple précédent serait donc transformé comme suit :

var element = React.createElement(
  "div",
  {id: 'main-element', className: "title"},
  "Hello, world!"
)

Il est tout à fait possible d’écrire directement ce code, pour éviter une phase de compilation. Mais ce genre de code est moins lisible et donc moins maintenable quand on commence à imbriquer les composants.

Notez que l’attribut HTML class s’écrit className en JSX, cela vient du fait que le mot class est protégé en JS.

Plus de détails sur JSX

Babel

Babel est un compilateur JavaScript qui a pour rôle de transformer du code JavaScript « moderne » (ES6, ReactJs ou autre) en une version compréhensible par tous les navigateurs.

Plus de détails sur Babel

Webpack

Webpack est un constructeur de modules que nous utiliserons pour notre application, il se charge de découvrir vos modules et toutes leurs dépendances, de les transformer en utilisant des loaders, puis de les packager dans des fichiers statiques contenant la totalité du code prêt à être utilisé.

Fonctionnement de Webpack

Il délégue la transformation du code JavaScript à Babel. La configuration de webpack est définie dans webpack.config.js. Pour en savoir plus sur la configuration de Webpack, je vous invite à lire Configuration de développement versus configuration de production avec Webpack.

Plus de détails sur Webpack

webpack-dev-server

Enfin, nous utiliserons webpack-dev-server pour héberger notre application. C’est un serveur de développement en NodeJs dont le rôle est de servir les fichiers statiques et de gérer le live reload.

Le live reload fonctionne de la manière suivante :

  1. Le serveur écoute les modifications dans le code source JavaScript
  2. Il fait appel à Webpack pour recompiler le code modifié
  3. Il notifie le client de la modification pour mettre à jour uniquement ce qui à changé, pas besoin de recharger complètement la page.

Plus de détails sur webpack-dev-server

Mise en place de l’environment

Nous considèrerons que NodeJs et npm sont déjà installés, si ce n’est pas le cas, voici la marche à suivre.

La première chose à faire est d’installer les outils que nous allons utiliser pendant le projet. Pour rappel, nous avons besoin de babel, webpack et webpack-dev-server.

Etant donné qu’ils peuvent vous être utiles dans d’autres projets, vous pouvez les installer globalement (-g) :

$ npm install babel webpack webpack-dev-server -g

Initialisation du projet

Nous pouvons maintenant rentrer dans le vif du sujet : créer une application utilisant ReactJs « from scratch ». Nous partons ici d’un répertoire vide, mais vous pouvez également ajouter ces éléments dans un projet existant.

Dans votre terminal, mettez vous à la racine de votre projet. Nous allons commencer par initialiser un projet NodeJs :

$ npm init

Le terminal va alors vous poser un certain nombre de questions, vous pouvez y passez du temps pour bien faire les choses… ou appuyer sans réfléchir une bonne dizaine de fois sur la touche « Entrée » pour vous débarasser de cela rapidement (vous pourrez modifier ces informations après) !

name: (myproject)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/gbe/Development/myproject/package.json:

{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes

La commande npm init vient de créer un fichier package.json dans notre répertoire. Ce dernier va contenir entre autre tous les modules NodeJs dont nous aurons besoin pour le projet.

Nous pouvons maintenant importer les modules, ces derniers seront alors automatiquement ajoutés dans le package.json.

Ainsi, si une autre personne récupère le projet il aurra simplement à exécuter la commande npm install pour importer automatiquement tous les éléments nécessaires :

Les modules nécessaires pour utiliser ReactJs sont react et react-dom :

$ npm install react react-dom --save

Il faut également importer les modules qui seront nécéssaires à Babel pour compiler le code JavaScript :

$ npm install babel-loader babel-core babel-preset-es2015 babel-preset-react webpack --save-dev

Création de la structure du projet

Notre HelloWorld est un projet simple, nous avons donc besoin de très peu de choses pour le faire fonctionner. Les fichiers nécessaires sont les suivants :

  • webpack.config.js : le fichier de configuration de webpack
  • index.html : la page web qui va acceuillir notre application.
  • main.js : le fichier JavaScript qui sert à injecter l’application dans la page.
  • App.js : l’application à proprement parler
$ mkdir app 
$ touch index.html app/App.js app/main.js webpack.config.js 

webpack.config.js

Il s’agit du fichier de configuration de webpack, c’est grâce à lui que nous allors pouvoir transformer notre code en Javascript classique. Nous allons donc lui spécifier les actions et les modules à mettre en place.

Il doit contenir les éléments suivants :

module.exports = {
    entry: "./app/main.js",
    output: { 
        path: "./",
        filename: "index.js"
    },
    devServer: { // configuration du server permettant le live-reload
        inline: true,
        port: 8080
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                    presets: ['es2015','react']
                }
            }
        ]
    }
}

Voici le détail de la configuration :

  • nous spécifions le point d’entrée de l’application, dans notre cas main.js
        entry: "./app/main.js",
  • nous indiquons le chemin où le bundle final sera généré par webpack, c’est ce fichier qui devra être importé dans la page web
        output: { 
            path: "./",
            filename: "index.js"
        },
    
  • nous définissons les loaders qui seront lancés pendant la compilation et leur ordre d’application
        module: {
            loaders: [
                {
                    test: /\.js$/, // On ne considère que les fichiers *.js
                    exclude: /node_modules/, // On ne s'occupe pas des fichiers présents dans node_modules
                    loader: 'babel', // On lance Babel pour gérer es2015 et react
                    query: {
                        presets: ['es2015','react'] //On utilise les presets de gestion de la syntaxe ES6 et de ReactJs
                    }
                }
            ]
        }
    
  • nous configurons le serveur sur le port 8080 en mode inline. C’est ici que la magie opère, il n’y a rien de plus à faire, le code qui sert au live reload est automatiquement incorporé par webpack dans le bundle
        devServer: { // configuration du server permettant le live-reload
            inline: true,
            port: 8080
        },
    

index.html

Le fichier html est ici volontairement léger, mais une application ReactJs peut être ajoutée dans n’importe quelle page. Il suffit de créer une balise pour contenir l’application et d’ajouter le script qui va s’occuper du reste.

  <!DOCTYPE html>
  <html>
  <head>
      <meta charset="UTF-8">
      <title>React 101</title>
  </head>
  <body>
  <div id="app"></div>
  <script type="text/javascript" src="index.js"></script>
  </body>
  </html>

La conteneur dans lequel nous allons injecter l’application a pour id app, et seul le bundle généré par webpack (index.js) est nécessaire.

App.js

Nous allons maintenant réaliser notre application HelloWorld avec ReactJs en utilisant les syntaxes ES6 et JSX.

Comme dans beaucoup de lanquages, il existe une convention qui consiste à commencer le nom des composants React par une majuscule.

Voici donc l’implementation de notre HelloWorld :

    import React from "react";

    class App extends React.Component {
      render() {
        return <div id="main-element" className="title">Hello World !</div>
      }
    }
    
    export default App;

La première chose qui est faite est l’import de la librairie react en utilisant la syntaxe ES6.

    import React from "react";

Ensuite nous déclarons notre composant React, il s’agit ni plus ni moins d’une classe étendant la classe Component de ReactJs. Encore une fois, nous utilisons la syntaxe ES6 :

    class App extends React.Component {
    }

Pour que notre composant soit fonctionnel, il est obligatoire d’implémenter la méthode render() qui doit retourner un composant. Avec JSX, nous pouvons facilement décrire la div qui contiendra « HelloWorld »

    render() {
        return <div id="main-element" className="title">Hello World !</div>
    }

Comprenez bien que nous n’avons pas écrit du code HTML dans notre fichier JavaScript, nous utilisons simplement une syntaxe (JSX) proche du HTML qui sera transformé en code JavaScript standard. D’ailleurs, si nous n’avions pas utilisé JSX, nous aurions dû écrire :

    render() {
        return React.createElement(
                 "div",
                 {id: 'main-element', className: "title"},
                 "Hello, world!"
               )
    }

Enfin, nous devons exporter notre composant pour qu’il puisse être utilisé à l’extérieur du module App, tout comme l’import, nous utilisons la syntaxe ES6.

  export default App;

Si vous trouvez qu’un composant aussi simple ne devrait pas prendre 7 lignes à définir, sachez que vous pouvez également l’écrire de la manière suivante :

  import React from "react";

  export default const App = () => <div id="main-element" className="title">Hello World !</div>;

Par défaut, si un composant ne contient qu’une méthode, il s’agit de la méthode render(). Cette écriture est très pratique pour tous les composants simples qui ne contiennent pas d’état interne.

main.js

C’est le point d’entrée de l’application, c’est à dire le code qui va injecter notre composant App dans la page HTML. Comme il ne s’agit pas d’une classe, son nom commence par une minuscule.

  import React from "react";
  import ReactDom from "react-dom";

  import App from "./App";

  ReactDom.render(<App />, document.getElementById('app'));

Comme précédemment, nous avons besoin du module react. Nous aurons également besoin de react-dom qui contient les méthodes permettant d’injecter notre application. Finalement, nous importons notre App.

  import React from "react"; // qui se trouve dans node_module
  import ReactDom from "react-dom"; // qui se trouve dans node_module
  import App from "./App"; // qui ne se trouve pas dans node_module, nous devons donc spécifier le chemin

Nous allons alors utiliser react-dom pour injecter App dans la balise HTML dont l’id est « app » :

  ReactDom.render(<App />, document.getElementById('app'));

Vue d’ensemble

Si tout s’est bien passé, voici à quoi ressemble le répertoire du projet:

.
├── app
│   ├── App.js
│   └── main.js
├── index.html
├── index.js
├── node_modules
│   └── ... 
│ 
├── package.json
└── webpack.config.js

Compiler le projet

Nous pouvons maintenant transpiler notre projet en un code exécutable par un navigateur :

$ webpack

Lancer le server avec hot-reload

Pour démarrer webpack-dev-server, il faut lancer :

$ webpack-dev-server

Nous pouvons aussi utiliser les scripts de npm pour démarrer le serveur en ajoutant dans package.json :

  "scripts": {
    "server": "webpack-dev-server"
  },

Nous lancerons alors le serveur avec :

$ npm run server

L’application est maintenant accessible sur le port 8080 de notre locahost.

That's all Folks !