React mit Magento 2

Erweiterung eines bestehenden Projekts mit ReactJS

Einleitung

Als Frontend-Entwickler stößt man heutzutage sehr oft auf die gehypte Javascript Library React. Die extreme Popularität der "Javascript-Bibliothek zum Erstellen von Benutzeroberflächen" (https://reactjs.org/) ist ungebrochen und wächst mit der immer größer werdenden Verbreitung von Web-Apps stetig. So setzt auch das vor kurzem veröffentlichte Magento PWA-Studio zur Erstellung einer Progressive Web App für Magento2 komplett auf die Bibliothek. Allerdings wird React mittlerweile sehr häufig nur noch mit Single-Page-Applikationen (SPA) in Verbindung gebracht, was aber einen großen Vorteil komplett unterschlägt: React wurde von Grund auf dahin konzipiert und optimiert, es als Erweiterung für bestehende Projekte zu verwenden. Hier zeigt sich auch, warum React als Bibliothek und nicht als Framework bezeichnet wird.

Im Entwickler-Alltag ist es oft eben nicht der Fall, dass man ein komplett neues Frontend (als SPA) erstellen soll, sondern ein bestehendes Projekt weiterentwickelt. Hier ist es oft schwierig, kostet zu viele Ressourcen oder ist komplett unnötig die gesamte Applikation zu einer SPA umzubauen. Gleichzeitig möchte man als Entwickler aber die Vorteile, die eine neue Technologie wie z.B. React bietet, nutzen.

Dieser Artikel soll also zeigen, wie React sehr einfach in ein bereits bestehendes Frontend integriert oder einzelne Komponenten ausgetauscht werden können. Im Folgenden werden einige grundlegende React-Kenntnisse vorausgesetzt.

Demo

Das im Folgenden beschriebene Beispiel-Setup und -Projekt ist als Demo-Code unter https://github.com/mothership-gmbh/react-demo verfügbar.

Setup/Installation

In diesem Beispiel wird ein möglichst einfaches Setup ohne Module-Bundler wie Webpack o.ä. gezeigt. Es wird einzig und allein eine Kompilierung von JSX zu Javascript aufgesetzt, hier über den Task Runner Gulp, der in vielen Projekten schon vorhanden sein könnte und entsprechend nur noch erweitert werden müsste.

Voraussetzungen:

Nachdem beides installiert ist, kann im Root-Verzeichnis folgende package.json erzeugt werden.

package.json

{
  "name": "mothership-react-demo",
  "version": "1.0.0",
  "description": "Wir integrieren React in eine bestehende App",
  "main": "index.js",
  "author": "Mothership GmbH",
  "devDependencies": {
    "@babel/core": "^7.1.2",
    "@babel/plugin-transform-react-jsx": "^7.0.0",
    "gulp": "^4.0.0",
    "gulp-babel": "^8.0.0-beta.2"
  }
}

Nach dem Ausführen des Befehls npm install ist das Grundsetup schon fertig. Nun fehlt nur noch die Konfiguration von Gulp, damit die JSX-Syntax in valides Javascript kompiliert wird. Dazu legen wir die Datei gulpfile.js mit folgendem Inhalt an.

gulpfile.js

var gulp = require('gulp');
var babel = require('gulp-babel');

// JSX-Task um JSX in Javascript zu kompilieren
gulp.task('jsx', () => {
    return gulp.src('web/js/react/src/**/*.js')
        .pipe(babel({
            plugins: ['@babel/plugin-transform-react-jsx']
        }))
        .pipe(gulp.dest('web/js/react/dist'));
});

// Watch-Task um Änderungen am JSX automatisch zu kompilieren
gulp.task('watch', function () {
    gulp.watch('web/js/react/src/**/*.js', {ignoreInitial: false}, gulp.series('jsx'));
});

// Default Task von Gulp
gulp.task('default', gulp.parallel(['watch']));

Die Dateistruktur sieht in diesem Beispiel also wie folgt aus: Alle React-spezifischen Dateien befinden sich im Ordner js/react, um eine möglichst einfache Abgrenzung von evtl. bereits existierendem Javascript-Code zu schaffen. Die JSX-Quelldateien werden in web/js/react/src abgelegt, die fertig kompilierten Dateien sind in web/js/react/dist zu finden.

app
├── gulpfile.js
├── package-lock.json
├── package.json
└── web
    ├── css
        ├── mothership.css
        └── styles.css
    ├── index.html
    └── js
        └── react
            ├── dist
            │   └── modal.js
            ├── src
            │   └── modal.js
            └── vendor
                ├── react-dom.js
                └── react.js

Hiermit ist das Setup vollendet. Um die React-Komponenten in valides Javascript zu kompilieren, kann der Befehl gulp jsx ausgeführt werden. Um während der Entwicklung nicht bei jeder Änderung diesen Befehl erneut manuell ausführen zu müssen, kann stattdessen gulp watch verwendet werden. Hier wird ein Watcher gestartet, der bei Änderungen an den Quelldateien automatisch den JSX-Task ausführt.

React Komponente entwickeln und in bestehender Seite verwenden

Um das Beispiel möglichst einfach zu halten, soll eine simple Modal-Komponente entwickelt werden, die sich durch den Klick eines Buttons aufrufen lässt.

Zuerst muss auf der Seite, die die React-Komponente enthalten soll (hier: index.html), die React-Bibliothek eingebunden werden. Dazu braucht es zwei Dateien, react.js und react-dom.js. Diese können z.B. über ein CDN geladen werden, im Beispiel werden sie lokal bereitgestellt. Zu beachten ist, dass diese beiden Dateien vor dem Javascript der späteren Komponente eingebunden werden.
Im Folgenden wird nun die React-Komponente erstellt und in die Seite integriert. Dazu braucht es ein Container-Element im DOM, hier mit der ID react-modal.

index.html

<html>
  <head>...</head>
  <body>
    ...
    <!-- Container-Element für die React-Komponente -->
    <div id="react-modal"></div>
    ...
    <script type="text/javascript" src="js/react/vendor/react.js"></script>
    <script type="text/javascript" src="js/react/vendor/react-dom.js"></script>
    <!-- Einbinden der Modal-Komponente -->
    <script type="text/javascript" src="js/react/dist/modal.js"></script>
  </body>
</html>

Die React-Komponente ist sehr simpel gehalten. Da das Modal zuerst einmal ausgeblendet sein soll, wird der initiale State isOpen auf false gesetzt. Über die Funktion toggleOpen kann dieser Status gewechselt werden.
Gerendert wird das Modal so, dass sowohl bei Klick auf den Button "Modal öffnen" als auch bei Klick auf den Hintergrund (bei geöffnetem Modal) toggleOpen aufgerufen wird, sodass sich das Modal entsprechend öffnet, bzw. schließt.
Zuletzt wird die Komponente in den zuvor beschriebenen DOM-Container mit der ID react-modal eingefügt.

js/react/dist/modal.js

'use strict';

class Modal extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          isOpen: false
        };
        this.toggleOpen = this.toggleOpen.bind(this);
    }

    toggleOpen() {
        this.setState({
            isOpen: !this.state.isOpen
        });
    }

    render() {
      var className = 'modal';
      className += this.state.isOpen ? ' open' : '';
        return <div>
            <button className='button-open' onClick={this.toggleOpen}>Modal öffnen</button>
            <div className={className}>
              <div className='content'>
                <button className='close-button' onClick={this.toggleOpen}>X</button>
                <div>
                  <h2>Ich bin das Modal</h2>
                  <div>Man kann mich über das X schließen, aber auch über einen Klick außerhalb</div>
                  <iframe src="https://giphy.com/embed/xT77XWum9yH7zNkFW0"
                          width="480"
                          height="270"
                          frameBorder="0"
                          className='giphy-embed'
                          allowFullScreen>
                  </iframe>
                  <p>
                      <a href="https://giphy.com/gifs/9jumpin-wow-nice-well-done-xT77XWum9yH7zNkFW0">via GIPHY</a>
                  </p>
                </div>
              </div>
              <button className='background' onClick={this.toggleOpen}/>
            </div>
          </div>
    }
}

const e = React.createElement;
const domContainer = document.querySelector('#react-modal');
ReactDOM.render(e(Modal), domContainer);

Fazit

Obwohl React meist in einem Atemzug mit Single-Page-Applikationen genannt wird, eignet es sich auch hervorragend, um ein bereits bestehendes Frontend mit einigen dynamischen Elementen modular zu erweitern. So müssen Frontend-Entwickler nicht auf den Einsatz dieser modernen Technologie verzichten, ohne einen kompletten Relaunch/Rewrite des Frontends nötig zu machen. React-Neulinge haben des Weiteren so die Möglichkeit, schon jetzt mit wenig Aufwand Erfahrung mit der Bibliothek zu sammeln, um so für zukünftige Aufgaben (z.B. die Umsetzung einer Magento2 PWA-Storefront) gewappnet zu sein.

markiert mit Social Network

Javascript Entwickler Stammtisch München

Der Javascript Entwickler Stammtisch München fand am 10. Juni 2014 und diesmal im Büro von Jetbrains statt. Der Hersteller von populären Web-Entwickler IDEs wie WebStorm, PhpStorm oder IntelliJ hatte zu einem Vortrag über WebStorm mit anschließendem Smalltalk eingeladen.
Javascript in München
Gereicht wurden das obligatorische, aber sehr beliebte Bier und Pizza Gespann. Die aktuelle Entwicklungsversion der IDs kann unter http://eap.jetbrains.com/ heruntergeladen werden, laut Aussage der anwesenden Mitarbeiter von Jetbrains sind diese bereits sehr stabil und können ohne Probleme genutzt werden. Gezeigte wurde bei dem Vortrag vor allem die neuen Debug-Möglichkeiten, viele kleine neue Features und einige Shortcuts.
Münchner JS Entwickler