In diesem und den folgenden Beiträgen geht es um den Aufbau einer Vorlage für moderne Web-Anwendungen. Da drängt sich mir gleich die Frage auf, warum benötige ich eine eigene Vorlage? Es gibt doch für nahezu jedes aktuelle Framework bzw. jede aktuelle Bibliothek, ob React, Angular oder Vue, eine Vorlage bzw. ein Starter Kit.
Das ist richtig, aber ein Starter Kit hilft einem nicht zu verstehen, wie die im Entwicklungsprozess eingesetzten Tools interagieren, bzw. wo sie konfiguriert werden müssen. Kommt es dann zu einem Problem, welche unausweichlich kommen werden, darf man sich das benötigte Wissen anlernen, wenn man gerade keine Zeit dafür hat.
Deshalb lasst uns von vorne beginnen...
Der Anfang
Früher hat man für eine Web-Anwendung eine HTML Seite benötigt und hat dort 1-2 JavaScript Dateien hinzugefügt um ein wenig dynamischen Inhalt zu erzeugen. Heutzutage entstehen immer mehr Anwendungen, die sich anfühlen wie Desktop-Anwendungen. Daher ist die Komplexität deutlich angewachsen.
Um dies zu beherrschen benötigt man heute einen ganzen Zoo von Tools, um aus den Skripten, den zusätzlich benötigten Bibliotheken und weiteren Medien eine lauffähige Web-Applikation zu erstellen.
Bibliotheken und Frameworks werden mit einem Paketmanager verwaltet und können damit samt Ihren benötigten Abhängigkeiten einfach dem Projekt hinzugefügt werden. Im Java Umfeld kümmert sich Maven oder Gradle um das laden der Abhängigkeiten. Im JavaScript Umfeld gibt es dafür npm oder yarn. Diese sorgen dafür, das alle Module und deren Abhängigkeiten vorhanden ist, um ein lauffähiges Projekt zu erstellen. Einen Vergleich der beiden kann man hier finden.
In diesen Beiträgen verwende ich Yarn, da mir die Handhabung besser gefällt.
Möchte man anstatt reinem JavaScript eine andere Sprache oder Sprachvariante verwenden, da sie einem einfachere, erweiterte oder ganz andere Syntax erlaubt, muss sie für den Browser übersetzt werden. Hier werde ich mich auf TypeScript und ECMAScript 2015 und neuer) beschränken.
Zur Übersetzung wird ein Transpiler wie Babel benötigt. Dieser kann neben den o.g. Sprachen auch die JavaScript-Grammatik für React (JSX) in reines JavaScript übersetzen.
Und als ob das bisher genannte nicht schon genug wäre, benötigt man noch einen sogenannten Module Bundler wie z.B. Webpack, der aus allen Artefakten und Abhängigkeiten eine fertige Web-Applikation erstellt, die von einem Webserver ausgeliefert werden kann.
Für diese Toolsammlung gibt es viele Tutorials, aber leider sind die meisten entweder nicht mehr aktuell, oder bestehen fast ausschließlich aus Konfigurationsblöcken, ohne weitere Erklärung.
Mit Hilfe der beiden sehr guten Tutorials Webpack from Nothing und How to setup Webpack +2.0 from scratch in 2017 habe ich mir meine Konfiguration erstellt. Dabei hat es mir sehr geholfen, die einzelnen Schritte selbst durchzuführen und an einigen Punkten auf Probleme zu stoßen.
Das Endziel ist eine vollständige Basis-Konfiguration für ECMAScript >=2015 und TypeScript zu erhalten, die man schnell erweitern kann, wenn neue Frameworks oder Plugins verwenden möchte.
Vorraussetzungen und minimale Build-Konfiguration
Die Konfiguration wurde unter macOS durchgeführt. Es funktioniert aber auch unter jedem anderen Betriebssystem. Man muss dort nur darauf achten, das sich nicht alle Befehle 1:1 übernehmen lassen.
Auf Unix-artigen Systemen wird zum Beispiel der Befehl $(yarn bin)/BEFEHL in PROJEKTVERZEICHNIS/node_modules/.bin/BEFEHL aufgelöst.
Auch die Aufrufe von einigen Funktionen unterscheiden sich bei der Benutzung von Yarn bzw. NPM.
Yarn vs. NPM
Yarn | NPM |
---|---|
yarn SKRIPT | npm run SKRIPT |
yarn add -D webpack | npm install --save-dev webpack |
yarn add react | npm install --save react |
Installation von NodeJS & Yarn
Als erstes wird NodeJS installiert. Mittels NodeJS kann JavaScript auf dem Desktop/Server ausgeführt werden und stellt die Basis für alle weiteren Tools dar. Es enthält den Paketmanager NPM.
Unter macOS verwende ich Homebrew, um Programme per Kommandozeile zu installieren.
$ brew install node yarn
Danach erstellt man das ein neues Projektverzeichnis und initialisiert es.
$ mkdir webpack-template
$ cd webpack-template
Die initiale Projektdatei package.json kann automatisiert (yarn -y init) oder interaktiv (yarn init) erzeugt werden.
$ yarn -y init
yarn init v1.3.2
warning The yes flag has been set. This will automatically answer yes to all questions which may have security implications.
success Saved package.json
✨ Done in 0.04s.
Danach installiert man den Module Bundler Webpack und speichert ihn als Entwicklungsabhängigkeit. Dies hat den Vorteil, das man später nur die package.json Datei benötigt und mittels yarn install alle Abhängigkeiten heruntergeladen und installiert werden.
$ yarn add -D webpack
yarn add v1.3.2
info No lockfile found.
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 📃 Building fresh packages...
success Saved lockfile.
success Saved 313 new dependencies.
├─ abbrev@1.1.1
[...]
└─ yargs@8.0.2
✨ Done in 14.14s.
Um zu prüfen welche Version von webpack installiert wurde, kann man das Tool direkt aufrufen.
$ $(yarn bin)/webpack --version
3.10.0
Beispiel: Einfaches JavaScript Multi Modul Projekt
Um die grundlegende Funktionalität von Webpack darzustellen, wird ein kleines Beispiel verwendet, das aus mehreren kleinen Modulen besteht. Aus diesen Modulen wird ein Datei, das Applikationsbundle, erzeugt. Damit müssen die JavaScript Dateien nicht einzeln mittels SCRIPT-Tags in der HTML Seite eingefügt werden.
$ mkdir -p src
src/index.js:
console.log("index.js wurde geladen.");
import modul1 from './modul1';
import modul2 from './modul2';
modul1.sagHallo();
modul2.sagHallo();
src/modul1.js:
console.log("modul1.js wurde geladen.");
export default {
sagHallo: function() {
console.log("modul1.js sagt hallo.");
}
}
src/modul2.js:
console.log("modul2.js wurde geladen.");
export default {
sagHallo: function() {
console.log("modul2.js sagt hallo.");
}
}
Danach wird das Projekt mittels webpack gebaut. Im Anschluß erstellt man eine HTML Datei, die nur das resultierende bundle.js lädt.
$ $(yarn bin)/webpack --entry ./src/index.js --output-filename=bundle.js
index.html:
<!DOCTYPE html>
<html>
<head>
<script src="bundle.js"></script>
</head>
<h3>Bitte die Entwicklerkonsole öffnen.</h3>
</html>
Jetzt kann die angelegte HTML Datei im Browser geöffnet werden. Die Module sollten geladen und ausgeführt werden, ohne das für jedes Modul ein eigener script-Tag genutzt wird.
Damit man zum erstellen des Applikationsbundles die Optionen nicht jedes mal manuell angeben muss, wird eine initiale webpack-Konfiguration erstellt.
webpack.config.js:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
Danach wird das Projekt mittels webpack und dem vereinfachtem Aufruf erneut gebaut. In der Konfiguration wurde definiert, das das Ergebnis im Verzeichnis dist abgelegt wird. Daher wird auch die index.html Datei dorthin verschoben.
// alte Datei löschen
$ rm bundle.js
// projekt neu erstellen
$ $(yarn bin)/webpack
$ ls dist
$ mv index.html dist
Um den gleichen Build-Befehl unabhängig vom benutzten Betriebssystem zu erhalten wird ein Alias-Kommando erstellt. Dazu passt man die package.json Datei an den Stellen zwischen den beiden Kommentaren beginn neuer code und ende neuer code an.
package.json:
{
"name": "webpack-template",
"version": "1.0.0",
"description": "webpack template",
"author": "Sven Paaß",
"license": "MIT",
/* beginn neuer code */
"main": "src/index.js",
"scripts": {
"webpack": "webpack --config webpack.config.js --display-error-details"
},
/* ende neuer code */
"devDependencies": {
"webpack": "^3.10.0"
}
}
Nun kann der Erstellungsprozess unabhängig von Betriebssystem mit yarn webpack gestartet werden.
$ yarn webpack
Wenn man mit git als Versionskontrolle arbeiten möchte, kann man jetzt für das Projekt ein neues Repository mittels git init einrichten und die Dateien hinzufügen. Ich lasse mir gerne von gitignore.io eine .gitignore Datei erstellen, in der die wichtigsten temporären Dateien / Verzeichnisse ausgeschlossen werden.
$ curl -o .gitignore https://www.gitignore.io/api/node%2Clinux%2Cmacos%2Cwindows
Den bisherigen Stand des Projekts findet Ihr in meinem gitlab-Projekt unter https://gitlab.com/svenpaass/webpack-template/tree/chapter1
Im zweiten Teil wird ein einfacher Markdown Viewer als Beispielprojekt erstellt und die Konfiguration in Produktion und Entwicklung aufgeteilt ...