Qu’est-ce que React ?

React est une bibliothèque / framework JavaScript qui permet de créer des interfaces dynamiques pour le devant des sites. Elle a été crée par Facebook, et est très populaire. C’est même LA bibliothèque la plus populaire pour créer des interfaces. Elle bénéficie d’une excellente documentation, d’un très bon support (Facebook, quoi) et d’un écosystème d’extensions énorme.

Pour schématiser un peu, c’est un outil très puissant qui permet de déclarer des données dynamiques et de les lier à des éléments de la page. Dés que les données changent, les éléments HTML sont rafraîchis et réaffichés avec leur nouvelle valeur. Donc, dés que vous allez interagir avec un élément, comme un bouton par exemple, cela va déclencher une action qui va mettre à jour ou modifier une donnée, qui va donc déclencher une nouvelle mise à jour de tous les éléments concernés par cette action ou utilisant la donnée. Vu que toutes vos données sont gérée en un seul endroit, tout est synchronisé.

C’est quoi le rapport avec WordPress ?

Si je vous parle de React, c’est parce que notre nouvel éditeur (celui depuis la 5.0) est en réalité une application React intégrée à WordPress. Une couche supplémentaire d’abstraction a été développée pour permettre l’intégration du nouvel éditeur mais Gutenberg est “juste” une grosse appli React.

Gutenberg est juste une grosse appli React, intégrée à WordPress.

Et ce qui est cool, c’est que tous les outils et abstractions créés pour le nouvel éditeur sont donc disponibles dans le coeur de WordPress ! En gros, React est dans le coeur de WordPress, tout comme jQuery !

Intégrer React sur le devant du site

La bibliothèque React est donc disponible dans WordPress, et on peut l’utiliser sur le devant du site ou dans l’administration. Cela dit, il y a quelques ajustements à faire et précautions à prendre par rapport au développement d’une application React plus classique, et c’est ce qu’on va voir.

Pour l’exemple, on va simplement intégrer la mini application de liste des tâches qui est donnée en exemple sur la page d’accueil de la documentation de React. Le but du jeu n’est pas d’apprendre React mais juste d’apprendre à tout mettre en place correctement. Apprendre React est un sujet pour un autre article. Ou dix.

Créons une petite extension, que l’on va appeler react-example. Dans votre dossier des extensions, créez donc un dossier react-example et un fichier PHP react-example.php dans ce dossier, avec l’entête qui va bien pour pouvoir activer l’extension.

<?php 
/**
 * Plugin Name: React Example
 */
defined( 'ABSPATH' ) || die();

Vous devriez pouvoir activer votre extension.

Extension React Example est disponible.
L’extension est disponible.

Dans cette extension, on va juste créer un code court qui va permettre de placer un placeholder pour notre application. Dans une application React, tout est géré en JavaScript, même le balisage. Donc tout ce qu’on a à faire en PHP, c’est de créer un conteneur pour notre application.

<?php
// In main plugin file
add_shortcode( 'example_react_app', 'example_react_app' );
/**
 * Registers a shortcode that simply displays a placeholder for our React App.
 */
function example_react_app( $atts = array(), $content = null , $tag = 'example_react_app' ){
    ob_start();
    ?>
        <div id="app">App goes here</div>
    <?php 
    return ob_get_clean();
}

Puis créez une page contenant ce code court. Vous devriez obtenir ceci sur le devant du site.

Conteneur pour notre appli React sur le devant du site.
Notre conteneur est prêt

Installer wp-scripts

React est mis à disposition dans la bibliothèque wp-element. Il suffit donc de charger notre script correctement dans notre code court avec wp_enqueue_script() et de déclarer wp-element comme dépendance.

<?php
// in main plugin file
function example_react_app( $atts = array(), $content = null , $tag = 'example_react_app' ){
    ob_start();
    ?>
        <div id="app">App goes here</div>
        <?php wp_enqueue_script( 'example-app', plugins_url( 'build/index.js', __FILE__ ), array( 'wp-element' ), time(), true ); ?>
    <?php return ob_get_clean();
}

Ici, je charge un fichier index.js situé dans un dossier build. Je lui déclare simplement wp-element comme dépendance. Aussi, je mets time() comme numéro de version pour être sûr d’avoir une nouvelle version fraîche de mon script à chaque rafraîchissement de page. Utile pour le développement, mais à éviter en production !

Pas de panique, vous allez comprendre dans quelques minutes pourquoi le fichier s’appelle index.js, et pourquoi il est dans un dossier build. Pour le moment, créez simplement ce dossier et fichier, et ajoutez-y un bête console.log(wp.element), pour pouvoir voir si tout est bien en place.

Contenu de wp-element
wp-element est bien chargé et logué.

Une application React est une application JavaScript. Ok. Le souci, c’est que souvent, elle est composée de plusieurs fichiers, dans des formats différents.

Avec React, tout est composant. Les applications sont composées de multiples composants nichés les uns dans les autres. Aussi, quasiment toutes les applications React sont écrites en utilisant la syntaxe JSX, qui signifie JavaScript and XML. En gros, c’est de l’HTML augmenté. On n’est pas obligé d’utiliser JSX pour écrire une appli React, mais faire sans c’est un peu l’enfer. Vraiment.

Le souci, c’est que ces formats ne sont pas reconnus par le navigateur, et qu’importer les fichiers modules avec nos composants en utilisant des balises <script>, c’est très pénible, surtout si notre application fait 200 fichiers.

Donc dans 99,99% des cas, les développeurs React vont utiliser un outil de type bundler qui va empaqueter toute l’application dans un seul fichier JavaScript.

Le plus connus de ces outils est Webpack.

Depuis le fichier JavaScript racine de notre application, cet outil va lire tous les import, va créer un arbre de dépendance, va tout rassembler, et à l’aide de Babel il va transpiler tout le JSX en React et JavaScript standards compris par tous les navigateurs. On obtient un seul package qui contient tout notre code à lier dans notre document. Plutôt cool.

On ne va pas apprendre à utiliser Webpack dans cet article. D’ailleurs, beaucoup de développeurs ne s’embêtent pas trop, et utilise create-react-app pour démarrer un projet. Cet outil permet d’échafauder un projet rapidement, et inclut une configuration par défaut de Webpack, optimisée pour les applications React indépendantes. C’est un super outil.

Sauf que nous, dans notre WordPress, on ne peut pas vraiment utiliser create-react-app, car on ne veut pas importer React complètement, mais utiliser la version du coeur de WordPress. Heureusement, l’équipe de développement du nouvel éditeur à mis à notre disposition un outil qui permet de faire plus ou moins la même chose : @wordpress/scripts

Cet outil va nous permettre de bundler notre code en faisant référence à wp-element plutôt qu’en important et bundlant React. Il utilise Webpack et contient une configuration de base très utile. En gros, c’est la version WordPress de create-react-app.

Il faut donc l’installer dans notre extension. Ouvrez un terminal à la racine de notre extension, et initialisez un fichier package.json à l’aide de la commande suivante :

npm init

Il faudra au préalable installer Node si ce n’est pas déjà fait. Vous pourrez le faire simplement en téléchargeant un installeur sur le site.

Ensuite, on va installer wp-scripts.

npm install @wordpress/scripts --save-dev

Cela va télécharger les dépendances dont wp-scripts a besoin pour bundler notre code, et les installer dans le dossier node_modules. Une fois installé, on peut utiliser wp-scripts. Le plus simple est de créer deux scripts-raccourci dans le fichier package.json

Votre fichier package.json devrait ressembler à ça :

// package.json
{
  "name": "react-example",
  "version": "1.0.0",
  "description": "Example of React integration in a plugin",
  "main": "index.js",
  "author": "Vincent Dubroeucq",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "license": "ISC",
  "devDependencies": {
    "@wordpress/scripts": "^6.1.1"
  }
}

La commande npm start va permettre de démarrer le watcher, qui va surveiller nos fichiers à partir de src/index.js, puis de les compiler dans build/index.js dés qu’il y aura des changements. La commande npm run build va faire la même chose, mais en minifiant le fichier JavaScript obtenu pour la production. Les noms et chemins des dossiers et fichiers correspondent simplement aux paramètres par défaut utilisés par Webpack. En utilisant cette structure, il n’y a pas besoin de toucher aux fichiers de configuration. Il est cependant possible de personnaliser les sources et destinations.

Créez donc un dossier src/ avec un fichier index.js, et ajoutez simplement un console.log('index.js is bundled properly') pour voir si tout fonctionne. Vérifiez bien que dans notre code court, c’est le script contenu dans le dossier build/ qui est chargé, puis dans le terminal, utilisez la commande :

npm start
WP-Script est en place.
Nos outils de bundling sont en place.

Intégrer notre application

Tout est en place. wp-scripts est installé et prêt à packager notre code depuis src/index.js vers build/index.js, et on s’est assuré de charger le script du dossier build/.

Maintenant, il reste à code notre application, depuis le fichier racine src/index.js ! Pour l’exemple, je vais copier-coller la todo app donnée en exemple sur la page d’accueil de la documentation de React, mais il faut faire quelques ajustements !

// in src/index.js

// Added lines to use wp.element instead of importing React
const { Component, render } = wp.element;

class TodoApp extends Component {     // instead of: ...extends React.Component
    constructor(props) {
        super(props);
        this.state = { items: [], text: '' };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    render() {
        return (
            <div>
                <h3>À faire</h3>
                <TodoList items={this.state.items} />
                <form onSubmit={this.handleSubmit}>
                    <label htmlFor="new-todo">
                        Que faut-il faire ?
                    </label>
                    <input
                        id="new-todo"
                        onChange={this.handleChange}
                        value={this.state.text}
                    />
                    <button>
                        Ajouter #{this.state.items.length + 1}
                    </button>
                </form>
            </div>
        );
    }

    handleChange(e) {
        this.setState({ text: e.target.value });
    }

    handleSubmit(e) {
        e.preventDefault();
        if (!this.state.text.length) {
            return;
        }
        const newItem = {
            text: this.state.text,
            id: Date.now()
        };
        this.setState(state => ({
            items: state.items.concat(newItem),
            text: ''
        }));
    }
}

class TodoList extends Component {
    render() {
        return (
            <ul>
                {this.props.items.map(item => (
                    <li key={item.id}>{item.text}</li>
                ))}
            </ul>
        );
    }
}


// Render the app inside our shortcode's #app div
render(
    <TodoApp />,
    document.getElementById('app')
);

Je ne vais pas vous expliquer le code propre à React. Par contre, vous remarquerez que tout en haut, on extrait la classe Component et la fonction render de wp.element (précédemment chargé et donc disponible globalement) au lieu d’importer React et de les extraire depuis React. Puis en bas, on utilise render() pour injecter notre application dans la <div id="app"> crée par notre code court.

En sauvegardant, le code est automatiquement re-compilé, et build/index.js mis à jour. Rafraîchissez donc la page du navigateur pour tester.

Notre mini application React fonctionne correctement !
Notre mini application React fonctionne correctement !

Préparer le code pour la production

Pour préparer un bundle optimisé pour la production, arrêtez le script npm start en appyant sur CTRL+C, puis entrez la commande :

npm run build

L’application sera ré-générée et minifiée. C’est ce script qu’il faut livrer et charger en production. Par contre, en production, pas besoin du dossier node_modules/ , car il contient uniquement les dépendances dont on a besoin pour bundler notre code lors du développement.

Si on y réfléchit bien, notre extension n’est composée que de deux fichiers : notre fichier bootstrap PHP et un seul et unique fichier JavaScript !

Voilà ! Vous savez utiliser React dans une extension WordPress ! Dans un thème, le procédé est exactement le même. Les fonctions utilisées pour charger le script vont être différentes, c’est tout.

Maintenant que React est dans le coeur de WordPress, la prochaine étape, c’est d’apprendre React ! La documentation officiel est un très bon point de départ !

Go !