HTML5-Tutorium: JavaScript: Hello World 05: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Kowa (Diskussion | Beiträge)
Kowa (Diskussion | Beiträge)
 
(114 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}


'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05a/web/index.html <code>index.html</code> (5a)], [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05b/web/index.html <code>index.html</code> (5b)], [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05c/web/index.html <code>index.html</code> (5c)], [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05d/web/index.html <code>index.html</code> (5d)],<br/>
'''Musterlösung'''<br/>
(Git-Repositories: [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05a.git 5a], [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05b.git 5b], [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05c.git 5c], [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05d.git 5d])
v02: [https://glossar.hs-augsburg.de/beispiel/tutorium/2025/wk_hello_world/wk_hello_world_05/web_v02/index.html <code>index.html</code>] ([https://validator.nu/?doc=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v02%2Findex.html HTML validate], [https://css-validator.org/validator?uri=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v03%2Findex.html&profile=css21&usermedium=all&warning=1&lang=de CSS validate], [https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v02%2Findex.html Google PageSpeed])<br/>
v03: [https://glossar.hs-augsburg.de/beispiel/tutorium/2025/wk_hello_world/wk_hello_world_05/web_v03/index.html <code>index.html</code>] ([https://validator.nu/?doc=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v03%2Findex.html HTML validate], [https://css-validator.org/validator?uri=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v03%2Findex.html&profile=css21&usermedium=all&warning=1&lang=de CSS validate], [https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v03%2Findex.html Google PageSpeed])<br/>
v04: [https://glossar.hs-augsburg.de/beispiel/tutorium/2025/wk_hello_world/wk_hello_world_05/web_v04/index.html <code>index.html</code>] ([https://validator.nu/?doc=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v04%2Findex.html HTML validate], [https://css-validator.org/validator?uri=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v04%2Findex.html&profile=css21&usermedium=all&warning=1&lang=de CSS validate], [https://pagespeed.web.dev/analysis?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2025%2Fwk_hello_world%2Fwk_hello_world_05%2Fweb_v04%2Findex.html Google PageSpeed])<br/>
 
[{{Git-Server}}/kowa/wk_hello_world_05.git Git-Repository]


==Anwendungsfälle (Use Cases)==
==Anwendungsfälle (Use Cases)==
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_03|dritten Teil des Tutoriums]]
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_03|dritten (und dem vierten) Teil des Tutoriums]]
ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.
ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.


In diesem Teil des Tutoriums geht es darum, die Anwendung mittels [[Vite]]<ref name="vite">[https://vitejs.dev/ Vite-Homepage]</ref> automatisch für den Server-Betrieb zu optimieren, sodass möglichst wenige, möglichst kleine Dateien zum Client übertragen werden.
Wie wir im vorherigen Teil des Tutoriums gesehen haben, sollten wird die verschiedenen Dateien
<code>main.js</code>, <code>greet.js</code> etc. wieder zu einer Datei zusammenfügen.
Und wir sollten alle Dateien komprimieren: Überflüssige Kommentare, Leerzeichen und Zeilenumbrüche
löschen, lange Variablen-, Konstanten- und Funktionsnamen verkürzen etc.


Im Tutorium wird „Vite 4“ verwendet.
Da dies gegen das Prinzip der Modularisierung spricht, wird dies nicht im Sourcecode, sondern automatisch mit Hilfe eines geeigneten Tools ([[Vite]], [[webpack]], ...) realisiert .
 
Das heißt, der Sourcecode wird weiterhin modular aufgebaut. Anschließend wird der Sourcecode mit Hilfe eines [[Transpiler]]s (Source-to-Source-Compiler) in eine kompakte Darstellung transformiert. Die Anzahl der Dateien, die vom Browser geladen werden müssen, wird drastisch reduziert, überflüssige Leerzeichen und Kommentare werden entfernt, Variablennamen werden durch kurze Namen ersetzt etc.
 
Ein Transpiler kann auch die Programmiersprache ändern. Zum Beispiel kann ECMAScript 6 in ECMAScript 5 übersetzt werden. Oder man verwendet eine Sprache wie TypeScript, CoffeeScript etc. oder sogar Java und übersetzt diese in ECMAScript, damit der Browser den Code interpretieren kann.
 
In diesem Teil des Tutoriums geht es also darum, die Anwendung mittels [[Vite|Vite 5]]<ref name="vite">[https://vitejs.dev/ Vite-Homepage]</ref> automatisch für den Server-Betrieb zu optimieren, sodass möglichst wenige, möglichst kleine Dateien zum Client übertragen werden.


==JavaScript Module Bundlers==
==JavaScript Module Bundlers==
Zeile 20: Zeile 33:
Üblicherweise optimieren die Bundlers nicht nur JavaScript-Dateien, sondern auch HTML-, CSS-, JSON- und andere Dateien.
Üblicherweise optimieren die Bundlers nicht nur JavaScript-Dateien, sondern auch HTML-, CSS-, JSON- und andere Dateien.


==Erstellen eines neuen Vite-Projekts==
==Erstellen eines neuen Vite-Projekts ([https://gitlab.multimedia.hs-augsburg.de/kowa/wk_hello_world_05/-/tree/v00 Version 00])==


Erstellen Sie ein neues Vite-Projekt <code>hello_world_05</code>:
Erstellen Sie ein neues Vite-Projekt <code>hello_world_05</code>:
Zeile 37: Zeile 50:
</source>
</source>


Öffnen Sie das Projekt in VSC und öffnen Sie in VSC ein zugehöriges Terminal (für den neuen Projektordner).
Öffnen Sie das Projekt in Visual Studio Code (VSC) und öffnen Sie in VSC ein zugehöriges Terminal (für den neuen Projektordner).
Führen Sie folgende Befehle aus:
Führen Sie folgende Befehle aus:


Zeile 50: Zeile 63:
Stellen Sie anschließend das Projekt unter Git-Kontrolle und speichern Sie es wieder in Gitlab.
Stellen Sie anschließend das Projekt unter Git-Kontrolle und speichern Sie es wieder in Gitlab.


==Konfigurieren des Vite-Projekts==
===Zur Erinnerung: .gitignore===
 
<strong>Achtung:</strong> Bevor Sie einen Commit durchführen, müssen Sie im selben Ordner, in dem sich die Datei <code>package.json</code> befindet, eine Datei namens <strong><code>.gitignore</code></strong> anlegen, in dem eine Zeile mit dem Wort <code>node_modules</code> enthalten ist. (Der Punkt zu Beginn des Dateinamens darf nicht fehlen!)
 
Glücklicherweise hat dies das Vite-Setup für Sie übernommen.
 
Diese Datei ist <strong>extrem wichtig</strong>. Wie Sie bereits im Node.js-Tutorium gesehen haben, enthält der
Ordner <code>node_modules</code> sehr schnell <strong>sehr viele</strong> Dateien (mehrere Zehntausend).
Wenn Sie diese im Repository speichern, bläht sich dieses extrem stark auf. Die Git-Push- und -Pull-Befehle werden dadurch sehr langsam.
 
Die Datei <code>.gitignore</code> dient dazu, dies zu verhindern. In jeder Zeile steht ein Dateiname oder ein Dateipattern (wie zum Beispiel <code>*.log</code>, das alle Dateien mit der Dateiextension <code>log</code> beschreibt), um zu verhindern, dass die zugehörigen Dateien ins Git-Repository eingefügt werden.
 
Wenn Sie dafür sorgen, die Dateien <code>package.json</code> und <code>package-lock.json</code> ins Repository eingefügt werden, kann ein anderer Benutzer, der Ihr Git-Repository auf seinen Rechner lädt, die fehlenden Node.js-Module jederzeit ganz einfach restaurieren:
 
<source lang="bash">
npm i
</source>
 
==Konfigurieren des Vite-Projekts [https://gitlab.multimedia.hs-augsburg.de/kowa/wk_hello_world_05/-/tree/v01 Version 01]==


Das neu angelegte Projekt enthält keine Vite-Konfigurationsdatei. Defaultmäßig werden alle Dateien des Web-Projekts im Root-Ordner <code>hello_world_05</code> abgelegt. Das ist – wie Sie bereits wissen – schlecht, da dort auch andere Dateien liegen, wie {{zB}} <code>package.json</code> oder <code>node_modules</code>.
Das neu angelegte Projekt enthält keine Vite-Konfigurationsdatei. Defaultmäßig werden alle Dateien des Web-Projekts im Root-Ordner <code>hello_world_05</code> abgelegt. Das ist – wie Sie bereits wissen – schlecht, da dort auch andere Dateien liegen, wie {{zB}} <code>package.json</code> oder <code>node_modules</code>.
Zeile 60: Zeile 91:
export default
export default
{ root:      'src',  
{ root:      'src',  
   publicDir: '../public',
   publicDir: '../public', 
  base:      '',
   build:  
   build:  
   { outDir:  '../web',
   { outDir:  '../web',
     target'es2020'
     minifytrue,
   }   
   }   
}
}
Zeile 69: Zeile 101:
Diese legt Folgendes fest:
Diese legt Folgendes fest:
* Der Root-Ordner des Projekts befindet sich im Unterordner <code>src</code> des Projektordners. Dort hinein kommen die ganzen HTML-/CSS-/JS-Dateien und Medien, die unter Kontrolle von Vite stehen sollen.
* Der Root-Ordner des Projekts befindet sich im Unterordner <code>src</code> des Projektordners. Dort hinein kommen die ganzen HTML-/CSS-/JS-Dateien und Medien, die unter Kontrolle von Vite stehen sollen.
* Der Ordner <code>public</code>, in dem alle Dateien enthalten sind, die von Vite '''nicht''' verändert werden, befindet sich weiterhin im Unterordner <code>public</code> des Projektordners. Vom Projektordner <code>src</code> aus gesehen, leigt er außerhalb von <code>src</code> eine Ebene höher. Das heißt, er befindet sich in der Ordnerhierarchie auf derselben Ebene wie <code>src</code> selbst.
* Der Ordner <code>public</code>, in dem alle Dateien enthalten sind, die von Vite '''nicht''' verändert werden, befindet sich weiterhin im Unterordner <code>public</code> des Projektordners. Vom Projektordner <code>src</code> aus gesehen, liegt er außerhalb von <code>src</code> eine Ebene höher. Das heißt, er befindet sich in der Ordnerhierarchie auf derselben Ebene wie <code>src</code> selbst.
* Wenn das Projekt von Vite mittels <code>npm run build</code> für den Produktivbetrieb erstellt wird, wird das Ergebnis in den Ordner <code>web</code> geschrieben. Dieser Ordner liegt ebenfalls auf derselben Ebene wie <code>src</code>.
* Die Option <code>base</code> enthält einen String, der vor jeden Asset-Pfad (<code>.css</code>, <code>.js</code>, <code>.jpg</code> ...) eingefügt wird. Standardmäßig lautet der Wert <code>'/'</code>. Das heißt, die zugehörigen Assetpfade sind absolut. Sie beginnen stets beim Top-Level-Verzeichnis der Web-App. Mit der Option <code>base: &#39;&#39;</code> legt man fest, dass die Pfade relativ sind. Das hat den Vorteil, dass man die Web-App in einen Unterordner einer anderen Web-App legen kann (Beispiel: <code>[https://glossar.hs-augsburg.de/beispiel/tutorium/2025/wk_hello_world/wk_hello_world_05/web_v00/index.html Verion 00]</code> funktioniert nicht, da absolute Pfade verwendet werden).
* Durch <code>npm run build</code> wird EcmaScript-Code der Version 2020 erstellt. Diese Version wird von allen modernen Brwosern weitgehend unterstützt. Wenn auch ältere Brwoser unterstützt werden sollen, muss hier eine andere EcmaScript-Version eingetragen werden.
* Wenn Sie das Projekt mittels <code>npm run build</code> für den Produktivbetrieb erstellen lassen, wird das Ergebnis in den Ordner <code>web</code> geschrieben (Defaultmäßig heißt der Ordnen <code>dist</code>). Dieser Ordner liegt ebenfalls auf derselben Ebene wie <code>src</code>.
* Durch <code>npm run build</code> wird komprimierter (minimized) Code erzeugt. Das gilt allerdings nicht für HTML-Dateien, sondern nur für CSS-, JavaScript-/TypeScript- und SVG-Dateien.


== Restrukturierung des Projekts ==
Sie sollten in der Datei <code>package.json</code> im Skript <code>build</code> auch noch die Option <code>--emptyOutDir</code> ergänzen,
damit der Web-Ordner vor jedem Rebuild geleert wird. Ohne diese Option sammeln sich im Web-Ordner im Laufe der Zeit Dateileichen an. Außerdem sollten Sie die Buildanweisung auch ausführen, bevor Sie sich das Ergebnis eines
Build-Laufs mittels <code>npm run preview</code> ansehen.
Die erreichen Sie, indem Sie den Build-Befehl zusätzlich unter dem Namen <code>prepreview</code> einfügen.


Wenn man nun das Projekt mittels <code>npm run dev</code> startet, wird man nichts sehen. Der Grund ist, dass der Browser keine Datei <code>index.html</code> findet. Der Grund ist, dass der Vite-Server nun den Inhalt des Ordners <code>src</code> ausliefert. Diesen gibt es aber noch gar nicht.
<source lang="javascript">
"build": "vite build --emptyOutDir",
"prepreview": "vite build --emptyOutDir",
</source>


Die Ordnerstruktur des Projekts muss an die Konfigurationsdatei angepasst werden.
Grundsätzlich gilt für die Datei <code>package.json</code>: Wenn Sie <code>npm run xyz</code> ausführen,
wird zuvor automatisch <code>npm run prexyz</code> ausgeführt, sofern <code>prexyz</code> definiert wurde. Nach
<code>npm run xyz</code>  automatisch <code>npm run postxyz</code> ausgeführt, sofern <code>postxyz</code> definiert wurde.
 
=== Restrukturierung des Projekts ===


Erstellen Sie folgende Ordnerstruktur:
Erstellen Sie folgende Ordnerstruktur:
Zeile 102: Zeile 145:
</pre>  
</pre>  


Das Ergebnis ist, dass Sie Fehlermeldungen erhalten, dass bestimmte Dateien nicht gefunden werden.
Das Ergebnis ist, dass Sie Fehlermeldungen erhalten, weil bestimmte Dateien nicht gefunden werden.
Das liegt daran, dass sich die Ordnerstruktur aus Sicht der Dateien im <code>src</code>-Ordner geändert haben.  
Das liegt daran, dass sich die Ordnerstruktur aus Sicht der Dateien im <code>src</code>-Ordner geändert haben.  
Die Pfade innerhalb der Dateien in diesem Ordner müssen daher angepasst werden.
Die Pfade innerhalb der Dateien in diesem Ordner müssen daher angepasst werden.
Zeile 108: Zeile 151:
Die Pfade zu Dateien im <code>public</code>-Ordner bleiben gleich. Aus Sicht der Dateien im <code>src</code>-Ordner
Die Pfade zu Dateien im <code>public</code>-Ordner bleiben gleich. Aus Sicht der Dateien im <code>src</code>-Ordner
befinden sie sich in der Root des Web-Auftritts. Im <code>public</code>-Ordner liegt in diesem Beispiel nur die Datei  
befinden sie sich in der Root des Web-Auftritts. Im <code>public</code>-Ordner liegt in diesem Beispiel nur die Datei  
<code>vite.svg</code>. Deren Pfade änder sic nicht, daher bleibt in der Datei code>src/index.html</code> und <code>src/js/main.js</code> die Zeilen
<code>vite.svg</code>. Deren Pfade ändern sich nicht, daher bleiben in den Dateien <code>src/index.html</code> und <code>src/js/main.js</code> die Zeilen
      
      
<source lang="javascript">
<source lang="javascript">
Zeile 114: Zeile 157:
</source>
</source>


und
bzw.


<source lang="javascript">
<source lang="javascript">
<img src="/vite.svg" class="logo" alt="Vite logo" />
import viteLogo from '/vite.svg'
</source>
</source>


Zeile 124: Zeile 167:
<source lang="javascript">
<source lang="javascript">
// src/index.html
// src/index.html
<script type="module" src="/main.js"></script>
<script type="module" src="/src/main.js"></script>


// src/js/main.js
// src/js/main.js
Zeile 133: Zeile 176:


Nehmen Sie geeignete Änderungen vor (sofern sie von VSC nicht automatisch durchgeführt wurden).  
Nehmen Sie geeignete Änderungen vor (sofern sie von VSC nicht automatisch durchgeführt wurden).  
Zum Schluss sollte die Anwendung wieder laufen.
Modifizieren und testen Sie die App mit Hilfe von <code>npm run dev</code> solange, bis sie fehlerfrei läuft.


== Packen der Web-Anwendung ==
=== Packen der Web-Anwendung ===


Bislang zeigt sich der Vorteil von Vite noch nicht wirklich.  
Bislang zeigt sich der Vorteil von Vite noch nicht wirklich.  
Zeile 143: Zeile 186:
Seine Stärke spielt Vite aus, wenn wir das Projekt packen. Das bedeutet, dass die Anzahl der Dateien  
Seine Stärke spielt Vite aus, wenn wir das Projekt packen. Das bedeutet, dass die Anzahl der Dateien  
reduziert wird und überflüssige Leerzeichen, Zeilenumbrüche, Kommentare etc. entfernt werden.
reduziert wird und überflüssige Leerzeichen, Zeilenumbrüche, Kommentare etc. entfernt werden.
Dadurch reduziert sich die Anzahl der Bytes, die zu einem Client (Brwoser) übertragen werden müssen, erheblich.
Dadurch reduziert sich die Anzahl der Bytes, die zu einem Client (Browser) übertragen werden müssen, erheblich.
Insbesondere für Smartphones mit eine geringen Datenvolumen profitieren davon.
Insbesondere für Smartphones mit einem geringen Datenvolumen profitieren davon.


Intelligente Frameworks wie [[Vue]], [[Svelte]] oder [[React]] oder React gehen sogar noch einen Schritt weiter  
Intelligente Frameworks wie [[Vue]], [[Svelte]] oder [[React]] oder React gehen sogar noch einen Schritt weiter  
und laden nur die Teile einer Web-Seite (nicht Web-Site!) nach, die sich geändert haben. JavaScript-Biliotheken werden so definiert,  
und laden nur die Teile einer Web-Seite (nicht Web-Site!) nach, die sich geändert haben. JavaScript-Bibliotheken werden so definiert,  
dass sie für eine ganze Web-Site nur einmal geladen werden müssen und für verschiedene Seiten wiederverwendet werden können.
dass sie für eine ganze Web-Site nur einmal geladen werden müssen und für verschiedene Seiten wiederverwendet werden können.
Hier spielen Web-Frameworks ihre Stärken aus. Sie stützen sich dabei auf Bundler wie Vite oder Webpack.
Hier spielen Web-Frameworks ihre Stärken aus. Sie stützen sich dabei auf Bundler wie Vite oder Webpack.
Zeile 161: Zeile 204:
Schauen Sie sich auch die generierten Dateien im Ordner <code>web</code> an.
Schauen Sie sich auch die generierten Dateien im Ordner <code>web</code> an.


==Webpack==
Testen Sie die Web-App dann, indem Sie entweder <code>web/index.html</code> mit dem Live Server von VSC starten
===Node.js-Pakete===
oder indem Sie <code>npm run preview</code> eingeben.


Um Webpack verwenden zu können, müssen Sie zunächst ein Node.js-Projekt anlegen.  
== Hello-World-App ([https://gitlab.multimedia.hs-augsburg.de/kowa/wk_hello_world_05/-/tree/v02 Version 02]) ==


<source lang="bash">
Ersetzen Sie nun die Vite-Default-App durch die Hello-World-App aus dem [[HTML5-Tutorium: JavaScript: Hello World 04|4. Teil des Tutoriums]]. In der Musterlösung habe ich die Version 04_4 als Hello-World-App verwendet.
npm init -y
</source>


Tagen Sie wie im Tutorium [[HTML5-Tutorium: JavaScript: Entwicklungsumgebung: Node.js]] beschrieben geeignete Werte in die [[JSON]]-Datei <code>package.json</code> ein (<code>name</code>, <code>version</code>, <code>description</code>,
Im Public-Bereich der Anwendung liegt noch die Datei <code>vite.svg</code>. Diese brauchen wir nicht mehr. Sie kann gelöscht werden. Dafür können Sie Dateien wie <code>robots.txt</code> oder </code>favicon.ico</code> einfügen.
<code>main</code>, <code>repository</code>, <code>keywords</code>, <code>author</code> und <code>license</code>).
Achten Sie darauf, dass Visual Studio Code keine Fehler meldet.


Installieren Sie nun die benötigten Node.js-Pakete:
<code>robots.txt</code> enthält Hinweise für die Suchmaschinen-Crawler, welche Dateien indexiert werden sollen und welche nicht. Die Crawler müssen sich aber nicht daran halten. Seriöse Crawler beachten die in der Datei aufgeführten Regeln allerdings.
</code>favicon.ico</code> ist ein Icon, das dem Text im Browser-Tab vorangestellt wird.


<source lang="bash">
Wenn Sie die Produktivversion mittels <code>npm run build</code> oder <code>npm run preview</code> erstellen möchten, muss es eine Datei <code>index.html</code> geben,
npm i -D webpack webpack-cli
da Vite defaultmäßig die Erstellung von Single-Page-Anwendungen unterstützt. Defaultmäßig wird nur die Datei <code>index.html</code> in den Ordner <code>build</code> übernommen. Das ist für unsere Zwecke in Ordnung, da wir mit Hilfe von Vue eine Single-Page-Anwendung erstellen werden.
npm i -D copy-webpack-plugin
Die Inhalte einer derartigen Anwendung werden per JavaScript nachgeladen. Man benötigt also tatsächlich nur eine HTML-Datei.
npm i -D css-loader style-loader file-loader extract-loader 
</source>


Das Paket <code>webpack</code> enthält das eigentlich Webpack-System. <code>webpack-cli</code> enthält Kommandozeilenbefehle, mit denen Webpack von einer Shell aus oder auch mittels NPM-Skripts gesteuert werden kann.
Achtung, die Datei <code>body.css</code> wird beim Packen von vite durch eine neue Datei mit zufälligem Namen ersetzt. Das zugehörige <code>link</code>-Element erhält keine id. Daher müssen wir in der Datei <code>main.js</code> die Zeile


Das Copy-Webpack-Plugin<ref>https://webpack.js.org/plugins/copy-webpack-plugin/</ref> dient dazu, mittels Webpack Dateien von einem Ordner in einen anderen zu kopieren.  
<source lang="javascript">
Verschiedene Loaders werden verwendet, um CSS- und JavaScript-Dateien für den „Bündelung“ vorzubereiten.<ref>https://webpack.js.org/loaders/</ref>
document.getElementById('body_css').rel = 'stylesheet';
</source>  


===Git commit===
löschen. Fügen Sie dafür folgende Zeile am Anfang in <code>main.js</code> ein:


<strong>Achtung:</strong> Bevor Sie einen Commit durchführen, müssen Sie im selben Ordner, in dem sich die Datei <code>package.json</code> befindet, eine Datei namens <strong><code>.gitignore</code></strong> anlegen. (Der Punkt zu Beginn des Dateinamens darf nicht fehlen!)
<source lang="javascript">
 
import '../css/body.css'
In diese Datei schreiben Sie ein einziges Wort: <code>node_modules</code>
 
<strong><code>.gitignore</code></strong>
<source lang="bash">
node_modules
</source>
 
Diese Datei ist <strong>extrem wichtig</strong>. Wie Sie bereits im Node.js-Tutorium gesehen haben, enthält der
Ordner <code>node_modules</code> sehr schnell <strong>sehr viele</strong> Dateien (mehrere Zehntausend).
Wenn Sie diese im Repository speichern, bläht sich dieses extrem stark auf. Die Git-Push- und -Pull-Befehle werden dadurch sehr langsam.  
 
Die Datei <code>.gitignore</code> dient dazu, dies zu verhindern. In jeder Zeile steht ein Dateiname oder ein Dateipattern (wie zum Beispiel <code>*.log</code>, das alle Dateien mit der Dateiextension <code>log</code> beschreibt), um zu verhindern, dass die zugehörigen Dateien ins Git-Repository eingefügt werden.
 
Wenn Sie dafür sorgen, die Dateien <code>package.json</code> und <code>package-lock.json</code> ins Repository eingefügt werden, kann ein anderer Benutzer, der Ihr Git-Repository auf seinen Rechner lädt, die fehlenden Node.js-Module jederzeit ganz einfach restaurieren:
 
<source lang="bash">
npm i
</source>
</source>


Fügen Sie nun alle Dateien (mit Ausnahme des Ordners <code>node_modules</code> ins Repository ein (zum Beispiels mittels <code>git add -u</code>) und committen Sie die Änderungen.
ECMAScript unterstützt den expliziten Import von CSS- oder JSON-Dateien nicht. Vite erweitert EXMAScript in dieser Hinsicht. Allerdings wird die von Vite erzeugte CSS-Datei, die einen zufälligen Namen erhält, statisch in die generierte Index-HTML-Datei eingafügt und damit synchron geladen.


=== Webpack ===
Wir üssem uns noch überlegen, wie wir Vite dazu bringen, die von ihm generierte CSS-Datei asynchron zu laden.


'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05a/web/index.html <code>index.html</code> (5a)]
''Anmerkung für Nicht-Single-Page-Anwendungen''<br/>
(Git-Repository: [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05a.git 5a])
Sie können auch eine Anwendung mit diversen HTML-Dateien mit Hilfe von Vite bündeln und komprimieren. Dafür müssten Sie allerdings
eine so genannte Rollup-Konfiguration in die Datei <code>vite.config.js</code> einfügen.  


Als nächstes Webpack konfiguriert werden, damit die Dateien <code>web/index.html</code>, <code>web/css/head.css</code>
* https://support.glitch.com/t/only-index-html-is-generated-on-build/51574/6
und <code>web/js/mains.js</code> automatisch generiert werden können.
* https://rollupjs.org/configuration-options/  
* https://rollupjs.org/configuration-options/#input


Benennen sie zunächst den Ordner <code>web</code> ins <code>src</code> um. Im Ordner <code>src</code> erstellen Sie künftig neue Dateien, nehmen Änderungen vor etc. Dabei sollten Sie unbedingt darauf, dass sinnvolle Module angelegt werden, viele sinnvolle Kommentare vorhanden sind, die Blöcke mittels Leerzeichen sauber eingerückt sind etc. <strong>Verwenden Sie niemals Tab-Zeichen zum Einrücken, da jeder Text-Editor Tab-Zeichen anders einrückt</strong>.
== Verbesserungen ([https://gitlab.multimedia.hs-augsburg.de/kowa/wk_hello_world_05/-/tree/v03 Version 03]) ==


Der Inhalt des Ordners <code>web</code>, der vom Browser dargestellt wird, soll künftig mittels Webpack generiert werden. Erstellen Sie dazu im Wurzelverzeichnis des Projekts die Datei <code>webpack.config.js</code>  
===  <code>head.css</code> inline und <code>body.css</code> dynamisch laden ===
(die Sie unbedingt auch in Git speichern sollten). Fügen Sie folgenden Code in diese Datei ein.


''<code>webpack.config.js</code>''
Zur Erinnerung:
<source lang="html">
* In <code>head.css</code> stehen möglichst wenig CSS-Anweisungen. Sie sollten ausreichen, um die aktuelle Seite “above the fold” („über dem Zeitungsknick“) fehlerfrei zu rendern. Das heißt, es sollte alles korrekt gerendert werden, was nach dem Laden im größtmöglichen Browserfenster sichtbar ist.
const
* Der Inhalt der <code>head.css</code> sollte mittels des Style-Tags direkt in den Head-Bereich der HTML-Seite eingefügt werden.
  path      = require('path'),
* Die restlichen CSS-Anweisungen werden in die Datei <code>body.css</code> eingetragen.
  CopyPlugin = require('copy-webpack-plugin');
* Dies Datei sollte asynchron, {{dh}} parallel zum Body-Element geladen werden.


function absolutePath(l_path)
Verwenden Sie im Style-Tag die Import-Anweisung, um die Datei <code>css/head.css</code> einzubinden. Dadurch wird erreicht, dass der Inhalt dieser Datei beim Bündeln direkt in die HTML-Datei eingebunden wurde (inline) und der Browser diese Datei nicht zusätzlich zu laden braucht.
{ return path.resolve(__dirname, l_path); }


module.exports =
<source lang="javascript">
{ entry:
<style>
   { head: absolutePath('src/css/head.css'),
   @import url("css/head.css");
    main: absolutePath('src/js/main.js'),
</style>
  },
 
  output:
  { filename: 'js/[name].js',
    path: absolutePath('web'),
  },
 
  plugins:
  [ new CopyPlugin
    ({ patterns:
      [{ context: 'src',
          from:    '*.html',
          to:      '.',
        },
      ],
    }),
  ],
 
  module:
  { rules:
    [ { test:    /head\.css$/,
        include: [ /src/ ],
        use:    [ { loader: 'file-loader',
                    options: { name: '[name].[ext]',
                                outputPath: 'css/',
                              }
                  },
                  'extract-loader',
                  'css-loader',
                ],
      },
 
      { test:    /\.css$/,
        include: [ /src/ ],
        exclude: [ /head\.css$/ ],
        use:    [ 'style-loader',
                  'css-loader',
                ],
      },
    ],
  },
};
</source>
</source>


Es handelt sich um eine JavaScript-Datei, die direkt von Node.js interpretiert wird.
Wie wir gesehen haben, wird der Inhalt Datei <code>css/body</code> bislang noch synchron geladen, obwohl wir
Aus diesem Grund wird auch nicht das ECMAScript-6-Modul-Konzept eingesetzt, sondern
den zugehörigen Import-Befehl in die Datei <code>main.js</code> eingefügt haben, die asynchron geladen wird..
[[CommonJS]], das Standard-Modulkonzept vom Node. Hier werden Module mittels <code>require</code>
und nicht mittels <code>import</code> importiert. Für Sie ist das allerdings nebensächlich,
da Sie im Rahmen der Tutorien keine eigenen komplexen Konfigurationsdateien für webpack implementieren werden.
 
Im Prinzip macht diese Datei nichts anderes als ein Objekt zu exportieren,
das Webpack-Konfigurationsinformationen enthält:
 
* <code>entry</code>: JavaScript-Dateien, die gebündelt und komprimiert werden sollen. Man muss jeweils nur die Wurzeldatei angeben. webpack sucht in dieser Datei rekursiv nach Import-Befehlen und packt die benötigten Dateien ebenfalls in die Ausgabedatei.
* <code>output</code>: Hier wird festgelegt, wie die gepackten Dateien heißen sollen. Für jeden Eintrag im Attribute <code>entry</code> wird eine Datei mit dem Namen <code>web/js/[name].js</code> erzeugt, wobei <code>[name]</code> durch den Schlüsselname des Entry-Eintrags ersetzt wird. In der obigen Datei gibt es zwei Entry-Elemente.
* <code>plugins</code>: Hier werden Webpack-Hilfsmodule geladen, die bestimmte Zusatzaufgaben erledigen. Sie verwenden derzeit nur das Modul <code>CopyPlugin</code>. Dieses kopiert alle HTML-Dateien (das ist in Ihrem Fall nur die Datei <code>index.html</code>) vom Ordner <code>src</code> in den Ausgabe-Ordner <code>web</code>. (In einer späteren Webpack-Konfiguration wird auch noch die HTML-Datei komprimiert werden.)
* <code>module</code>: In diesem Attribut werden Regeln (<code>rules</code>) angegeben,die festlegen, auf welche Weise eine Datei transformiert werden sollen. Bei jeder Regel gibt es einen Test, der festlegt, für welche Dateien die jeweilige Regel zutrifft. Mit Hilfe eines [[regulärer Ausdruck|regulären Ausdrucks]] wird im Tutoriumsbeispiel geprüft, ob die aktuelle Datei auf <code>head.css</code> oder <code>.css</code> endet, sich aber von <code>head.css</code> unterscheidet. Je nach Dateiname werden andere Loader zum Laden und Verarbeiten der zugehörigen Datei verwendet. (Für webpack gibt es diverse Loader, einige davon haben Sie zuvor mit Hilfe von <code>npm</code> installiert.) Leider gibt es soviel Loader, dass die Auswahl geeigneter Loader nicht gerade einfach ist. Erschwerend kommt hinzu, dass sich mit jeder neuen Hauptversion von webpack nicht nur die Struktur der Konfigurationsdatei, sonder auch die verfügbaren Loader und Plugins verändern. :-( )
 
CSS-Dateien werden zunächst mit dem CSS-Loader geladen und verarbeitet. Anschließend wird die Datei
<code>head.css</code> vom File-Loader Anweisungen in die Datei <code>web/css/head.css</code> geschrieben.
Dies hätten wir auch mit dem Copy-Plugin erreicht. Allerdings kann man für den File-Loader einen Optimierer hinzufügen, der die CSS-Datei komprimiert (minimiert), bevor sie in den Web-Ordner eingefügt wird (siehe Version 5b).
 
Alle übrigen CSS-Dateien werden nicht auf die Platte geschrieben, sondern in die JavaScript-Datei eingefügt, die die CSS-Datei importiert. Dies ist die Aufgabe des Style-Loaders. JavaScript-Dateien werden von Webpack automatisch
zu einer Datei zusammengefasst und (im Produktionsmodus) minimiert. Dies ist das Defaultverhalten des <strong>JavaScript</strong>-Bundlers und braucht daher nicht in eigenen Regeln beschrieben zu werden.
 
Mit dem Style-Loader wird erreicht, dass die Datei <code>src/css/main.css</code> in der
Ausgabedatei <code>web/js/main.js</code>
enthalten ist. Damit wird die Zahl der Dateien reduziert: Aus <code>src/js/main.js</code>, <code>src/js/greet.js</code> und <code>src/css/main.css</code> erzeugt Webpack <strong>eine</strong> (minimierte)
Datei namens <code>web/js/main.js</code>
 
Damit steht einer Verwendung von Webpack nichts mehr im Wege. Man könnte Webpack nun direkt von
der Kommandozeile aufrufen. Besser ist es allerdings NPM-Skript-Befehle
zu verwenden.
 
=== NPM-Skripte ===
 
Fügen Sie in das <code>scripts</code>-Objekt der Datei <code>package.json</code>
folgende Skript-Anweisungen ein:
 
<source lang="json">
"scripts": {
  "predev": "rm -rf web/*",
  "dev": "webpack --mode development",
  "preprod": "rm -rf web/*",
  "prod": "webpack --mode production",
  "postprod": "rm web/js/head.js",
  "prewatch": "rm -rf web/*",
  "watch": "webpack --mode development --watch"
}
</source>


Dieser Konfiguration definiert drei NPM-Skripte: <code>dev</code>, <code>prod</code> und <code>watch</code>.
In Vite gibt es jedoch eine Möglichkeit, CSS-Dateien dynamisch zu laden. Wenn man das Vite-Plugin <code>cssInjectedByJsPlugin</code> verwendet, werden die CSS-Dateien von Vite nicht statisch in die HTML-Datei eingefügt, sondern in der JavaScript-Datei dynamisch zur Laufzeit im Browser geladen und erst im Browser in die HTML-Datei eingefügt. Das zugehörige NPM-Package müssen Sie zunächst installieren:
Diese Skript können Sie von der Kommandozeile aus starten:


<source lang="bash">
<source lang="bash">
npm run dev
npm i -D vite-plugin-css-injected-by-js
npm run prod
npm run watch
</source>
 
Die Skripte <code>predev</code>, <code>preprod</code> und <code>prewatch</code> werden jeweils ausgeführt, bevor die eigentlichen Skripte ausgeführt werden. In allen drei Fällen wird der Web-Ordner vollständig gelöscht, da er ja neu erstellt werden soll. Für das NPM-Skript <code>prod</code> gibt es auch noch das Skript <code>postprod</code>, das
nach dem Skript <code>prod</code> ausgeführt wird. Es löscht die Datei <code>web/js/head.js</code>, die von Webpack angelegt wurde. Sie wird allerdings nicht mehr gebraucht, da mit daraus mit dem Extract-Loader CSS-Inhalt aus der Datei <code>web/js/head.js</code> extrahiert und mit dem File-Loader in die Datei
<code>web/css/head.css</code> extrahiert wird. Diese CSS-Datei wird von der Datei <code>web/index.html</code> direkt eingelesen.
 
Geben Sie nun im Terminal die Anweisung <code>npm run dev</code> (dev = development) ein.
 
Wenn Sie alles richtig gemacht haben, müsste Webpack fehlerfrei durchlaufen und die Dateien
<code>web/index.html</code>, <code>web/js/main.js</code> sowie <code>web/css/head.css</code> (sowie die überflüssige Datei  <code>web/js/head.js</code>) erstellen. Im Zweifelsfall müssen Sie auf das Reload-Icon hinter <code>HELLOWRLD05A</code> klicken.
 
Wenn Sie jetzt die Datei <code>index.html</code> im Browser öffnen, sollten Sie nach kurzer Zeit
wieder das Begrüßungsmenü sehen. Nach Eingabe des Namens und Klick auf den Say-hello-Button
oder Drücken der Enter-Taste sollten Sie freundlich begrüßt werden.
 
Allerdings ist das CSS-Layout immer noch mangelhaft. Die Datei <code>main.css</code>
wird bislang noch nicht eingebunden. Das können Sie ganz einfach ändern.
Fügen Sie in die Datei <code>src/js/main.js</code> folgenden Import-Befehl am Anfang der Datei ein:
 
<source lang="javascript"</code>
import '../css/main.css';
</source>
</source>


Dieser Befehl ist in JavaScript eigentlich nicht erlaubt. Wenn Sie jetzt versuchen, die Datei
Anschließend wird das Plugin in <code>vite.config.js</code> konfiguriert.
<code>src/index.html</code> im Browser zu öffnen, werden Sie in der Browser-Konsole
eine Fehlermeldung erhalten.
 
Webpack unterstützt allerdings das Importieren von CSS-Dateien in JavaScript-Dateien.
Das Tool wurde so konfiguriert, dass die CSS-Datei dynamisch in das HTML-Dokument „injiziert“ wird
(siehe oben).
 
Geben Sie im Terminal noch einmal die Anweisung <code>npm run dev</code> ein
und öffnen Sie die Datei <code>web/index.html</code> im Browser (nicht die Datei <code>src/index.html</code>!). Jetzt sollte sie wieder sauber formatiert sein
(evtl. erst nach einem Reload im Browser)!
 
Sehen Sie sich mal den Inhalt der Datei <code>main.js</code> an. Darin finden Sie
– neben vielen Kommentaren, die zur Strukturierung der Datei verwendet werden – die Inhalte der Dateien <code>main.js</code>, <code>greet.js</code> und <code>main.css</code>
sowie spezielle Anweisungen, die von Webpack eingefügt wurden.
 
In dieser Form ist die Datei für Entwicklungszwecke einigermaßen brauchbar. Bei einem Fehler
zeigt einem der Browser, in welcher Zeile dieser Datei der Fehler aufgetreten ist.
Normalerweise handelt es sich um eine Zeile, die Sie erfasst haben. Webpack-Befehle sollten keine
Fehler werfen. Nachteilig ist, dass diese Zeile etwas anders aussehen kann, wie in Ihrem Sourcecode,
da sie eventuell transformiert wurde. Aber man findet die Originalzeile normalerweise recht schnell.
 
Gehen Sie nochmal ins Terminal und geben Sie diesmal
die Anweisung <code>npm run prod</code> (prod = production) ein.
Es werden wieder die drei Dateien erstellt. Und die Web-Anwendung sollte
immer noch funktionieren. Wenn Sie sich die gebündelte JavaScript-Datei <code>web/js/main.js</code> noch einmal ansehen,
werden Sie feststellen, dass sie nun viel kleiner ist. Sie enthält keine überflüssige Leerzeichen, keine Zeilenumbrüche
und auch keine Kommentare mehr (evtl. mit Ausnahme des Kommentars, der Auskunft über den Autor der CSS-Datei <code>main.css</code>). Diese Datei ist für den Produktivbetrieb viel besser geeignet, da sie weniger Bandbreite
verbraucht. Insbesondere Smartphone-Besitzer freuen sich über kleine Dateien, da ihr Datenvolumen
dadurch weniger belastet wird. Für die Fehlersuche bei der Entwicklung der Web-Aanwendung ist diese
Variante allerdings vollkommen ungeeignet.
 
Nun können Sie noch die Anweisung <code>npm run watch</code> testen.
Dieser startet einen Webpack-Watcher, der bei jeder Änderung an einer Datei, die von Webpack
beim Bündeln berücksichtigt wird, dafür sorgt, dass die Dateien im Web-Ordner neu erstellt werden
und Sie die Ergebnisse Ihrer Änderung durch einen einfachen (Auto-)Reload der Datei <code>index.html</code>
im Browser betrachten können. Ändern Sie doch einmal in der CSS-Datei <code>src/css/head.css</code>
('''nicht in der Datei <code>web/css/head.css</code>''') die Hintergrundfarbe, speichern Sie die Datei und
laden Sie danach die HTML-Datei im Browser mittels des Reload-Buttons neu.
 
== Verbesserungen der Webpack-Konfiguration ==
 
=== Hinzufügen verschiedener Minimizer ===
 
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05a/web/index.html <code>index.html</code> (5b)]
(Git-Repository: [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05b.git 5b])
 
Wenn man die Dateien betrachtet, wurde nur die Datei <code>main.js</code> im Produktions-Modus minimiert.
Künftig sollen alle Dateien im Produktionsmodus minimiert werden.
 
Dafür brauchen wir drei neue Node.js-Pakete, zum Minimieren von CSS-, HTML- und JavaScript-Dateien:
<source lang="bash">
npm i -D css-minimizer-webpack-plugin
npm i -D html-minimizer-webpack-plugin
npm i -D terser-webpack-plugin
</source>
 
Nun muss man diese drei Plugins noch in die Webpack-Konfigurationsdatei <code>webpack.config.js</code> einarbeiten.
 
Zunächst muss die neuen Pakete importieren. Dazu ersetzt fügt man am Anfang der Datei drei weitere Require-Anweisungen ein.


<source lang="javascript">
<source lang="javascript">
const
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
  path      = require('path'),
  CopyPlugin = require('copy-webpack-plugin');
</source>


wird zu
export default
 
{ root:      'src',  
<source lang="javascript">
   publicDir: '../public',
const
   base:      '',
  path                = require('path'),
   build:
   CopyPlugin          = require('copy-webpack-plugin'),
  { outDir: '../web',
   TerserPlugin        = require('terser-webpack-plugin'),
    minify:  true,
   CssMinimizerPlugin = require('css-minimizer-webpack-plugin'),
  },
   HtmlMinimizerPlugin = require('html-minimizer-webpack-plugin');
  plugins:
   [ cssInjectedByJsPlugin(),
  ]
}
</source>
</source>


Außerdem muss das Konfigurations-Objekt, das exportiert wird, künftig mit einer Funktion berechnet werden,
Schreiben Sie die Hello-World-App entsprechend um.
damit man ermitteln kann, ob der Benutzer Webpack im Development- oder im Produktionsmodus ausführt.


<source lang="javascript">
=== HTML komprimieren ===
module.exports =
{ entry:
  ...
};
</source>


wird zu
Wenn man sich die Dateien im Web-Ordner ansieht, bemerkt man, dass nur die JavaScript- und CSS-Dateien gebündelt und verkleinert werden. Die HTML wurde dagegen nicht komprimiert. Um dies zu erreichen, benötigt man ein weiteres Vite-Plugin. Das zugehörige NPM-Package wird ebenfalls installiert:


<source lang="javascript">
<source lang="bash">
module.exports =
npm i -D vite-plugin-minify
function(p_env, p_argv)
{ const isProd = p_argv.mode === 'production';
 
  return {
 
  // the mode of the current webpack run: 'development' or 'production'
  mode: p_argv.mode || 'development',
 
  entry:
  ...
}};
</source>
</source>


Innerhalb dieser Funktion steht einem nun die Konstante <code>isProd</code> zur Verfügung. Sie hat den Wert
Anschließend muss das Plugin wieder in <code>vite.config.js</code> konfiguriert werden, in dem es zunächst importiert wird:
<code>false</code>, wenn Webpack im Development-Modus ausgeführt wird, und <code>true</code>, wenn Webpack im Produktionsmodus läuft.
 
Zu guter Letzt muss man noch ein paar Optimierungs-Regeln im Anschluss an das Objekt <code>module</code> in die Konfigurationsdatei
einfügen.


<source lang="javascript">
<source lang="javascript">
module.exports =
import { ViteMinifyPlugin } from 'vite-plugin-minify'
{ module:
  { ...
  },
};
</source>
</source>


wird zu
Anschließend wird der Initialisierungsbefehl in das Array <code>plugins</code> eingefügt. Diesmal wird allerdings zusätzlich ein
Konfigurationsparameter übergeben, der die Komprimierung der HTML-Datei veranlasst:


<source lang="javascript">
<source lang="javascript">
{ module:
ViteMinifyPlugin({}),
  { ...
  },
 
  optimization:
  { minimize: isProd,
 
    minimizer:
    [ new TerserPlugin                            // minimize JS
          ({ extractComments: true, }),
      new CssMinimizerPlugin                      // minimize CSS
          (),
      new HtmlMinimizerPlugin                      // minimize HTML
          ({ minimizerOptions:
            { collapseBooleanAttributes:  true,
              collapseWhitespace:          true,
              collapseInlineTagWhitespace: true,
            }
          }),  
    ],
  },
};
</source>
</source>


Das Attribut <code>minimize</code> wird im Development-Modus auf <code>false</code> gesetzt und im Produktions-Modus auf <code>true</code>.
Der HTML-Minimizer komprimiert auch CSS-Anweisungen, die im HTML-Code enthalten sind. In unseren Fall ist das der Inhalt der Datei
Das heißt, im Development-Modus werden keine Dateien minimiert. Im Produktionsmodus werden dagegen sowohl JS-, als auch CSS-, als auch HTML-Dateien minimiert.
<code>head.css</code>, der wegen des <code>@import</code>-Befehls von Vite direkt in die HTML-Datei eingefügt  wird.
Die einzelnen Minimizer heißen unterschiedlich, stammen von unterschiedlichen Autoren und akzeptieren unterschiedliche Konfigurationsattribute.
Dies ist ganz typisch für Webpack. Und in der nächsten Version funktioniert der ein oder andere Minimizer gar nicht mehr. Allerdings sind in der Zwischenzeit zumindest das Terser-Plugin und das CSS-Minimizer-Plugin offizieller Bestandteil von Webpack.


Wenn Sie jetzt <code>npm run dev</code> ausführen, sollte keine Datei im Web-Ordner komprimiert werden. Führen Sie dagegen <code>npm run prod</code> aus, sollten alle Dateien minimiert werden. Außerdem werden die Lizenzinformationen in eine eigene Datei ausgelagert.
'''Achtung!'''<br/>
Früher habe ich <code>vite-plugin-html</code> verwendet. Allerdings funktioniert bei Verwendung dieses Plugins der Vite-Proxy nicht mehr (Query Parameter und Argumente in der URL werden nicht weitergeleitet).


=== Inlining von <code>head.css</code> ===
=== Lizenzkommentare entfernen ===


'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05a/web/index.html <code>index.html</code> (5c)]
Ein Problem besteht noch. Die Lizenzkommentare werden in die komprimierten CSS- und JavaScript-Dateien eingefügt. Das kann gewünscht sein, kostet aber Platz. Das Problem kann man zumindest für JavaScript-Dateien beheben, indem man den Minimizer <code>terser</code> verwendet. Dieser bietet zahlreiche Konfigurationsmöglichkeiten an (ist allerdings beim Komprimieren wesentlich langsamer als der Standard-Minimizer). Schreiben Sie in der Datei
(Git-Repository: [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05c.git 5c])
<code>vite.config.js</code> an Stelle von
 
[https://developers.google.com/speed/pagespeed/insights/ Google PageSpeed Insights] hatte angemahnt, den Inhalt der Datei <code>head.css</code>
direkt in die Datei <code>index.html</code> einzufügen.
 
* Google PageSpeed Insights [https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2021%2Fhello_world%2FWK_HelloWorld05b%2Fweb%2Findex.html Version 5b]: Ressourcen beseitigen, die das Rendering blockieren: <code>.../css/head.css</code>
*Google PageSpeed Insights [https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2021%2Fhello_world%2FWK_HelloWorld05c%2Fweb%2Findex.html Version 5c]: Hier gibt es diese Empfehlung nicht mehr.
 
Um die Datei <code>head.css</code> in die Datei <code>index.html</code> einzufügen, muss man die HTML-Datei erzeugen. Ein einfaches Kopieren reicht nicht mehr aus. Anstelle des Copy-Plugins verwendet man das HTML-Webpack-Plugin. Dieses kann HTML-Dateien auf Basis von HTML-Templates erstellen und auch komprimieren. Da heißt, man benötigt auch das HTML-Minimizer-Plugin nicht mehr. Die CSS-Datei kann man mittels, des HTML-CSS-Inline-Plugins einfügen.
Dafür braucht man allerdings das Mini-CSS-Extract-Plugin anstelle des Extract-Loaders und des File-Loaders. Insgesamt bedeutet dies einen größeren Umbau der Konfigurationsdatei.  Zunächst sollten veraltete Node.js-Pakete entfernt und die dafür benötigten Pakete installiert werden:
<source lang="bash">
npm uninstall -D file-loader extract-loader
npm uninstall -D copy-webpack-plugin html-minimizer-webpack-plugin
 
npm i -D html-webpack-plugin html-replace-webpack-plugin
npm i -D mini-css-extract-plugin html-inline-css-webpack-plugin
</source>
 
Das HTML-Replace-Plugin wird benötigt, um an der modifizierten zum Schluss mit Hilfe von [[regulärer Ausdruck|regulären Ausdrücken]] noch zwei kleine Änderungen vorzunehmen. Damit werden Probleme behoben, die sich ergeben, weil es in den benutzten Paketen keine geeigneten Konfigurationsoptionen gibt.
Hier sieht man deutlich das Problem von Webpack: Es gibt sehr viele Loader, Plugins und Optimierer. Allerdings hat jedes Paket seine individuellen Schwächen und oft arbeiten zwei Pakete auch nicht wie gewünscht zusammen. Hier hilft meist nur Try and Error. Ob man zum Schluss die beste Variante gewählt hat, ist dabei unklar.
 
Die Datei <code>webpack.config.js</code> wird folgendermaßen geändert:


<source lang="javascript">
<source lang="javascript">
const
minify: true,
  path                = require('path'),
  CopyPlugin          = require('copy-webpack-plugin'),
  TerserPlugin        = require('terser-webpack-plugin'),
  CssMinimizerPlugin  = require('css-minimizer-webpack-plugin'),
  HtmlMinimizerPlugin = require('html-minimizer-webpack-plugin');
</source>
</source>


wird zu
folgende Konfigurationsanweisungen:


<source lang="javascript">
<source lang="javascript">
const
minify:  'terser',
  path                      = require('path'),
terserOptions:
  TerserPlugin              = require('terser-webpack-plugin'),
{ output: { comments: false } },
  CssMinimizerPlugin        = require('css-minimizer-webpack-plugin'),
  MiniCssExtractPlugin      = require('mini-css-extract-plugin'),
  HtmlWebpackPlugin          = require('html-webpack-plugin'),
  HTMLInlineCSSWebpackPlugin = require('html-inline-css-webpack-plugin').default,
  HtmlReplaceWebpackPlugin  = require('html-replace-webpack-plugin');
</source>
</source>


Das Plugins-Array muss vollständig ersetzt werden werden:
Für den CSS-Minimizer habe ich bislang keine entsprechenden Optionen gefunden. Schade.
Aber das Problem lässt sich ganz einfach beheben, indem man in CSS-Dateien keine [[JSDoc]]-Kommentare verwendet (was ja durchaus auch sinnvoll ist, da CSS keinen JavaScript-Code enthält). Anstelle von


<source lang="javascript">
<source lang="css">
plugins:
/**
[ ...
* @author    Wolfgang Kowarschick <kowa@hs-augsburg.de>
],
* @copyright 2016-2025
* @license  MIT
*/
</source>
</source>


wird zu
können Sie beispielsweise


<source lang="javascript">
<source lang="css">
plugins:
/*
[ new MiniCssExtractPlugin
* author    Wolfgang Kowarschick <kowa@hs-augsburg.de>
  ({ filename: "[name].css" }),
* copyright 2016-2025
  new HtmlWebpackPlugin
* license   MIT
  ({ template: absolutePath('src/index.html'),
*/
    chunks:  ['head', 'main'],
    minify:
    { collapseWhitespace:  isProd,
      removeComments:      true,
      ignoreCustomComments: [/@preserve/],
    },
  }),
  new HTMLInlineCSSWebpackPlugin
  (),
   new HtmlReplaceWebpackPlugin
  ([{ pattern:    /<script .*head\.js"><\/script>/,
      replacement: '',
    },
    { pattern:    /defer/g,
      replacement: 'async',
    },
  ]),
],
</source>
</source>


Das HTML-Webpack-Plugin kopiert in die Template-Datei <code>src/index.html</code> zwei Script-Anweisungen,
schreiben.
um die von Webpack erzeugten Dateien (“Chunks”, Klumpen) <code>web/js/head.js</code> und
<code>web/js/main.js</code> zu Laden. Diese Anweisungen dürfen also in der Template-Datei nicht enthalten sein.
Wie man sieht, kann man im HTML-Webpack-Plugin die Komprimierung mittels der Option <code>minify</code>
direkt konfigurieren. Auch hier werden die Leerzeichen und -zeilen nur im Produktivmodus, aber nicht im Developmentmodus entfernt.
 
Mit Hilfe des HTML-Replace-Plugins wird der Eintrag <code><script "src=css/head.js"></script></code> wieder aus
<code>index.html</code> gelöscht. Diese JavaScript-Datei enthält nur den CSS-Code, der mittels
des HTML-Inline-CSS-Plugins direkt eingefügt wurde. Warum dieses Plugin das überflüssige Script-Tag nicht
selbst entfernt, habe ich noch nicht herausgefunden.  


Außerdem wird <code>defer</code> durch </code>async</code>  
== Alias-Pfade in <code>vite.config.js</code> ==
ersetzt, da ich das asynchrone Laden gegenüber dem verzögerten Laden von JavaScript-Dateien bevorzuge. Warum
ich das im HTML-Webpack-Plugin nicht konfigurieren kann, weiß ich auch nicht.


Und die Regel für die <code>head.css</code> im Array <code>rules</code>) muss ersetzt werden.
Fügen Sie in die Datei <code>vite.config.js</code> unter dem Tag <code>resolve</code> ein paar Pafdaliases ein:


<source lang="javascript">
* <code>@</code>: Abkürzung für den Ordner <code>./src</code> als root
{ test:    /head\.css$/,
* <code>/css</code>: Abkürzung für den Ordner <code>./src/css</code>
  include: [ /src/ ],
* <code>/js</code>: Abkürzung für den Ordner <code>./src/js</code>
  use:     [ MiniCssExtractPlugin.loader,
            'css-loader',
          ],
},
</source>


Nun können Sie in der Datei <code>index.html</code> und der Javascript-Datei die absoluten Pfade
<code>@/...</code>, <code>/css/...</code> und <code>/js/...</code> verwenden. Beim Straten der Anwendung mittels
<code>npm run dev</code> und Bündeln der Anwendung
mittels <code>npm run build</code> werden die Pfade von Vite gemäß den Alias-Definitionen aufgelöst.


Wenn Sie jetzt <code>npm run dev</code> ausführen, sollte keine Datei im Web-Ordner komprimiert werden. Führen Sie dagegen <code>npm run prod</code> aus, sollten alle Dateien minimiert werden. Außerdem werden die Lizenzinformationen in eine eigene Datei ausgelagert. In beiden Fällen sollte der Inhalt der
Ersetzen Sie die relativen Pfade in den Dateien durch geeignete absolute Pfade.
CSS-Datei <code>head.css</code> in der HTML-Datei selbst enthalten sein. Einmal unkomprimiert und einmal komprimiert.
 
==== Ein kleine Verbesserung der Import-Anweisungen ====
 
Wenn Sie schon gerade dabei sind, fügen Sie noch folgendes Konfigurationsobjekt in die Export-Funktion von <code>webpack.config.js</code> ein:


<source lang="javascript">
<source lang="javascript">
resolve:
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
{ alias: { '/json': absolutePath('src/json/'),
import { ViteMinifyPlugin }  from 'vite-plugin-minify'
          '/css': absolutePath('src/css/'),
import { fileURLToPath, URL } from 'url'
          '/img':  absolutePath('src/img/'),
        },
},
</source>


Damit erreichen Sie, dass Dateien, die sich in den Ordnern <code>src/json/</code>,  <code>src/css/</code>,  <code>src/img/</code> befinden,
export default
direkt importiert werden können. Die Notwendigkeit, relative Pfadangaben wie <code>import '../../../css/irgenwas.css';</code> zu verwenden, entfällt.
{ root:      'src',  
Sie können künftig einfach <code>import '/css/irgenwas.css';</code> schreiben. Das gilt auch für Bilder oder JSON-Dateien, die Sie
  publicDir: '../public',
(mittels des erweiterten Import-Befehls von Webpack) in eine JavaScript-Datei importieren. Sie können selbstverständlich beliebig
  base:      '',
viele weitere Alias-Befehle definieren, natürlich auch für JavaScript-Bibliotheken, die in anderen Ordnern enthalten sind.
  build:  
 
  { outDir: '../web',
Ersetzen Sie also in der Datei <code>src/main.js</code>, den Befehl <code>import '../css/body.css';</code> durch
    minify:  'terser',
<code>import '/css/body.css';</code>
    terserOptions:
 
    { output: { comments: false } },
=== Verwendung des SCSS-Minimizers ===
  },
 
  plugins:  
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld05d/web/index.html <code>index.html</code> (5d)]
   [ cssInjectedByJsPlugin(),
(Git-Repository: [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05b.git 5d])
     ViteMinifyPlugin({}),
 
  ],  
Wenn man sich die Datei <code>web/js/main.js</code> ansieht, bemerkt man, dass die CS-Befehle, die von
  resolve:
Webpack in diese Datei eingefügt wurden (wegen des Import-Befehls <code>import '/css/body.css';</code>),  
  { alias:
im Produktions-Modus nicht komprimiert werden. Da heißt, dass das CSS-Minimizer-Plugin hier nicht greift.
    { '@':   fileURLToPath(new URL('./src',    import.meta.url)),
Also sollte es ersetzt werden.
       '/css': fileURLToPath(new URL('./src/css', import.meta.url)),
 
       '/js': fileURLToPath(new URL('./src/js', import.meta.url)),
Glücklicherweise gibt es einen ausgezeichneten Ersatz: Den SASS-Loader. Anstelle von CSS sollte man SASS/SCSS verwenden,  
     }
um auch CSS modularisieren und „[[DRY]] machen“ zu können. Glücklicherweise enthält diese Loader einen eigenen Minimizer.
   },
 
}
Modifizieren Sie die Pakete entsprechend:
 
<source lang="bash">
npm uninstall -D css-minimizer-webpack-plugin
npm i -D sass sass-loader
</source>
 
Löschen Sie das CSS-Minimizer-Plugin aus der Datei <code>webpack.config.js</code>, sowohl den Require-Befehl, als auch im Minimizer-Array im
Optimization-Objekt.
 
Fügen Sie dafür den SASS-Loader in die CSS-Objekte des Rules-Arrays ein.
 
<source lang="javascript">
module:
{ rules:
   [ { test:    /head\.(css|scss|sass)$/,
      include: [ /src/ ],
      use:     [ MiniCssExtractPlugin.loader,
                'css-loader',
                { loader: 'sass-loader',
                  options:  
                  { sassOptions: { outputStyle: isProd ? 'compressed' : 'expanded' } },
                },
              ],
     },
 
    { test:    /\.(css|scss|sass)/,
       include: [ /src/ ],
      exclude: [ /head\.(css|scss|sass)$/ ],
       use:    [ 'style-loader',
                'css-loader',
                { loader: 'sass-loader',
                  options:
                  { sassOptions: { outputStyle: isProd ? 'compressed' : 'expanded' } },
                },
              ],
     },
   ],
},
</source>
</source>
Dieser Loader übersetzt SCCS- und SASS-Anweisungen in CSS-Anweisungen. Er bietet zusätzlich eine Option <code>outputStyle</code> an,
die festlegt, ob die CSS-Anweisungen komprimiert werden sollen oder nicht. Dies nutzen wir aus, um die CSS-Anweisungen im Produktionsmodus zu komprimieren.
=== Weiteres Optimierungspotenzial ===
Google PageSpeed Insights [https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Fglossar.hs-augsburg.de%2Fbeispiel%2Ftutorium%2F2021%2Fhello_world%2FWK_HelloWorld05d%2Fweb%2Findex.html Version 5d] ist immer noch nicht ganz zufrieden.
Zum einen sollten die Anzahl der Dateien (zwei) und die Dateigrößen weiter reduziert werden, was aber schwierig ist.
Man könnte eine Datei <code>budget.json</code> definieren, die Google mitteilt, welche Dateianzahl und welche Dateigrößen man
für akzeptabel hält. Dan erhält man erst ab diesen Werten eine Warnung.
Zum anderen teilt einen Google das größte Element in der HTML-Seite mit. Hier gibt es tatsächlich noch Optimierungspotenzial, gerade bei
Single-Page-Anwendungen. Eine Single-Page wird in der Regel auf einmal geladen, aber nur portionsweise angezeigt. Wichtig ist eigentlich nur, dass
der Inhalt „above the fold“ („über dem Zeitungsknick“) in der HTML-Seite enthalten ist. Das ist der Bereich, den der Benutzer nach dem Laden der Seite
ohne Scrollen sieht. Bei der Hello-World-Anwendung wäre das die Section mit der ID <code>section_form</code>. Alle übrigen Bestandteile
der HTML-Seite könnten dynamisch nachgeladen werden, sobald sie benötigt werden. Genauso funktioniert Google Maps: Es werden nur die Kacheln der Erdoberfläche in der Auflösung geladen, die momentan benötigt werden. Um Verzögerungen, die durch das Nachladen entstehen, gerin zu halten, werden
Randkacheln und Kacheln in benachbarter Auflösung schon mal im Voraus geladen, während der Benutzer die aktuellen Karte betrachtet. Es ist natürlich
nicht sichergestellt, dass die Kacheln tatsächlich irgendwann angezeigt werden müssen. Aber es ist wahrscheinlich. Und daher wird der potenziell
unnötige Datenverkehr in Kauf genommen. Hier kommt es auf die Abwägung zwischen User Experience (möglichst kurze Wartezeiten)
und Energie- und Kosteneffizienz (möglichst geringes Transfervolumen) an.
Das Transfervolumen kann weiter reduziert werden, indem die Dateien vor dem Ausliefern vom Server mittels [[gzip]] weiter komprimiert werden. Der Client muss sie dann erst wieder entpacken, bevor er sie verarbeiten kann.
Dies ist aber eine Server-Optimierung, die nicht mit Webpack oder einen vergleichbaren Tool realisiert werden kann.


==Fortsetzung des Tutoriums==
==Fortsetzung des Tutoriums==


Sie sollten nun [[HTML5-Tutorium: JavaScript: Hello World 06|Teil 6 des Tutoriums]] bearbeiten.
Sie sollten nun [[HTML5-Tutorium: JavaScript: Hello World 06|Teil 6 des Tutoriums]] bearbeiten.
In diesem Teil des Tutoriums wird ausgenutzt, dass in die Konfigurationsdatei von Webpack ein SCSS-Loader integriert wurde. Damit kann man das Prinzip “[[don't repeat yourself|<strong>D</strong>on't <strong>R</strong>epeat <strong>Y</strong>ourself]]” (DRY) auch für CSS-Dateien umsetzen.
In diesem Teil des Tutoriums wird ausgenutzt, dass CSS nun auch Variablendefinitionen (eigentlich handelt es sich um Konstantendefinitionen) und den Import-Befehl unterstützt. Damit kann man das Prinzip “[[don't repeat yourself|<strong>D</strong>on't <strong>R</strong>epeat <strong>Y</strong>ourself]]” (DRY) auch für CSS-Dateien umsetzen.


==Quellen==
==Quellen==
<references/>
<references/>
<ol>
<ol>
<li value="6"> {{Quelle|Kowarschick, W.: Multimedia-Programmierung}}</li>
<li value="4"> {{Quelle|Kowarschick, W.: Web-Programmierung}}</li>
</ol>
</ol>
<noinclude>[[Kategorie: HTML5-Tutorium: JavaScript: Hello World]][[Kategorie: HTML5-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]</noinclude>
<noinclude>[[Kategorie: HTML5-Tutorium: JavaScript: Hello World]][[Kategorie: HTML5-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]</noinclude>

Aktuelle Version vom 11. April 2025, 08:43 Uhr

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 4
(unwichtige Fakten fehlen)
Quellenangaben: 3
(wichtige Quellen vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 3
(gut)

Vorlesung WebProg

Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5 | Vue 6

Musterlösung
v02: index.html (HTML validate, CSS validate, Google PageSpeed)
v03: index.html (HTML validate, CSS validate, Google PageSpeed)
v04: index.html (HTML validate, CSS validate, Google PageSpeed)

Git-Repository

Anwendungsfälle (Use Cases)

Gegenüber dem dritten (und dem vierten) Teil des Tutoriums ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.

Wie wir im vorherigen Teil des Tutoriums gesehen haben, sollten wird die verschiedenen Dateien main.js, greet.js etc. wieder zu einer Datei zusammenfügen. Und wir sollten alle Dateien komprimieren: Überflüssige Kommentare, Leerzeichen und Zeilenumbrüche löschen, lange Variablen-, Konstanten- und Funktionsnamen verkürzen etc.

Da dies gegen das Prinzip der Modularisierung spricht, wird dies nicht im Sourcecode, sondern automatisch mit Hilfe eines geeigneten Tools (Vite, webpack, ...) realisiert .

Das heißt, der Sourcecode wird weiterhin modular aufgebaut. Anschließend wird der Sourcecode mit Hilfe eines Transpilers (Source-to-Source-Compiler) in eine kompakte Darstellung transformiert. Die Anzahl der Dateien, die vom Browser geladen werden müssen, wird drastisch reduziert, überflüssige Leerzeichen und Kommentare werden entfernt, Variablennamen werden durch kurze Namen ersetzt etc.

Ein Transpiler kann auch die Programmiersprache ändern. Zum Beispiel kann ECMAScript 6 in ECMAScript 5 übersetzt werden. Oder man verwendet eine Sprache wie TypeScript, CoffeeScript etc. oder sogar Java und übersetzt diese in ECMAScript, damit der Browser den Code interpretieren kann.

In diesem Teil des Tutoriums geht es also darum, die Anwendung mittels Vite 5[1] automatisch für den Server-Betrieb zu optimieren, sodass möglichst wenige, möglichst kleine Dateien zum Client übertragen werden.

JavaScript Module Bundlers

Um Module einer Web-Anwendung für die Auslieferung zum Client zu komprimieren, zu bündeln und anderweitig zu optimieren, gibt es zahlreiche Werkzeuge. Für Node.js gibt es die sogenannten “JavaScript Module Bundlers”, wie z. B. Vite[1], Webpack[2] oder Browserify[3].

Üblicherweise optimieren die Bundlers nicht nur JavaScript-Dateien, sondern auch HTML-, CSS-, JSON- und andere Dateien.

Erstellen eines neuen Vite-Projekts (Version 00)

Erstellen Sie ein neues Vite-Projekt hello_world_05:

cd /webprog  # Ordner, in dem Ihre Projekte liegen
npm create vite@latest

Geben Sie für Vite folgende Optionen an:

Project name: hello_world_05
Select a framework: Vanilla
Select a variant: JavaScript

Öffnen Sie das Projekt in Visual Studio Code (VSC) und öffnen Sie in VSC ein zugehöriges Terminal (für den neuen Projektordner). Führen Sie folgende Befehle aus:

npm i
npm run dev

Nun wird ein Server gestartet und eine URL angezeigt, die Sie in einem Browser öffnen können. Make it so!

Stellen Sie anschließend das Projekt unter Git-Kontrolle und speichern Sie es wieder in Gitlab.

Zur Erinnerung: .gitignore

Achtung: Bevor Sie einen Commit durchführen, müssen Sie im selben Ordner, in dem sich die Datei package.json befindet, eine Datei namens .gitignore anlegen, in dem eine Zeile mit dem Wort node_modules enthalten ist. (Der Punkt zu Beginn des Dateinamens darf nicht fehlen!)

Glücklicherweise hat dies das Vite-Setup für Sie übernommen.

Diese Datei ist extrem wichtig. Wie Sie bereits im Node.js-Tutorium gesehen haben, enthält der Ordner node_modules sehr schnell sehr viele Dateien (mehrere Zehntausend). Wenn Sie diese im Repository speichern, bläht sich dieses extrem stark auf. Die Git-Push- und -Pull-Befehle werden dadurch sehr langsam.

Die Datei .gitignore dient dazu, dies zu verhindern. In jeder Zeile steht ein Dateiname oder ein Dateipattern (wie zum Beispiel *.log, das alle Dateien mit der Dateiextension log beschreibt), um zu verhindern, dass die zugehörigen Dateien ins Git-Repository eingefügt werden.

Wenn Sie dafür sorgen, die Dateien package.json und package-lock.json ins Repository eingefügt werden, kann ein anderer Benutzer, der Ihr Git-Repository auf seinen Rechner lädt, die fehlenden Node.js-Module jederzeit ganz einfach restaurieren:

npm i

Konfigurieren des Vite-Projekts Version 01

Das neu angelegte Projekt enthält keine Vite-Konfigurationsdatei. Defaultmäßig werden alle Dateien des Web-Projekts im Root-Ordner hello_world_05 abgelegt. Das ist – wie Sie bereits wissen – schlecht, da dort auch andere Dateien liegen, wie z. B. package.json oder node_modules.

Dies können Sie ändern, indem Sie eine Konfigurationsdatei vite.config.js im Projektordner anlegen:

// https://vitejs.dev/config/
export default
{ root:      'src', 
  publicDir: '../public',  
  base:      '',
  build: 
  { outDir:  '../web',
    minify:  true,
  }  
}

Diese legt Folgendes fest:

  • Der Root-Ordner des Projekts befindet sich im Unterordner src des Projektordners. Dort hinein kommen die ganzen HTML-/CSS-/JS-Dateien und Medien, die unter Kontrolle von Vite stehen sollen.
  • Der Ordner public, in dem alle Dateien enthalten sind, die von Vite nicht verändert werden, befindet sich weiterhin im Unterordner public des Projektordners. Vom Projektordner src aus gesehen, liegt er außerhalb von src eine Ebene höher. Das heißt, er befindet sich in der Ordnerhierarchie auf derselben Ebene wie src selbst.
  • Die Option base enthält einen String, der vor jeden Asset-Pfad (.css, .js, .jpg ...) eingefügt wird. Standardmäßig lautet der Wert '/'. Das heißt, die zugehörigen Assetpfade sind absolut. Sie beginnen stets beim Top-Level-Verzeichnis der Web-App. Mit der Option base: '' legt man fest, dass die Pfade relativ sind. Das hat den Vorteil, dass man die Web-App in einen Unterordner einer anderen Web-App legen kann (Beispiel: Verion 00 funktioniert nicht, da absolute Pfade verwendet werden).
  • Wenn Sie das Projekt mittels npm run build für den Produktivbetrieb erstellen lassen, wird das Ergebnis in den Ordner web geschrieben (Defaultmäßig heißt der Ordnen dist). Dieser Ordner liegt ebenfalls auf derselben Ebene wie src.
  • Durch npm run build wird komprimierter (minimized) Code erzeugt. Das gilt allerdings nicht für HTML-Dateien, sondern nur für CSS-, JavaScript-/TypeScript- und SVG-Dateien.

Sie sollten in der Datei package.json im Skript build auch noch die Option --emptyOutDir ergänzen, damit der Web-Ordner vor jedem Rebuild geleert wird. Ohne diese Option sammeln sich im Web-Ordner im Laufe der Zeit Dateileichen an. Außerdem sollten Sie die Buildanweisung auch ausführen, bevor Sie sich das Ergebnis eines Build-Laufs mittels npm run preview ansehen. Die erreichen Sie, indem Sie den Build-Befehl zusätzlich unter dem Namen prepreview einfügen.

"build": "vite build --emptyOutDir",
"prepreview": "vite build --emptyOutDir",

Grundsätzlich gilt für die Datei package.json: Wenn Sie npm run xyz ausführen, wird zuvor automatisch npm run prexyz ausgeführt, sofern prexyz definiert wurde. Nach npm run xyz automatisch npm run postxyz ausgeführt, sofern postxyz definiert wurde.

Restrukturierung des Projekts

Erstellen Sie folgende Ordnerstruktur:

src
| css
| img
| js

Verschieben Sie anschließend die Web-Dateien in diese Ordner:

src
| css
  - style.css
| img
  - javascript.svg
| js
  - counter.js
  - main.js
- index.html

Das Ergebnis ist, dass Sie Fehlermeldungen erhalten, weil bestimmte Dateien nicht gefunden werden. Das liegt daran, dass sich die Ordnerstruktur aus Sicht der Dateien im src-Ordner geändert haben. Die Pfade innerhalb der Dateien in diesem Ordner müssen daher angepasst werden.

Die Pfade zu Dateien im public-Ordner bleiben gleich. Aus Sicht der Dateien im src-Ordner befinden sie sich in der Root des Web-Auftritts. Im public-Ordner liegt in diesem Beispiel nur die Datei vite.svg. Deren Pfade ändern sich nicht, daher bleiben in den Dateien src/index.html und src/js/main.js die Zeilen

<link rel="icon" type="image/svg+xml" href="/vite.svg" />

bzw.

import viteLogo from '/vite.svg'

unverändert. Die anderen Pfade müssen dagegen eventuell angepasst werden:

// src/index.html
<script type="module" src="/src/main.js"></script>

// src/js/main.js
import './style.css'
import javascriptLogo from './javascript.svg'
import { setupCounter } from './counter.js'

Nehmen Sie geeignete Änderungen vor (sofern sie von VSC nicht automatisch durchgeführt wurden). Modifizieren und testen Sie die App mit Hilfe von npm run dev solange, bis sie fehlerfrei läuft.

Packen der Web-Anwendung

Bislang zeigt sich der Vorteil von Vite noch nicht wirklich. Der einzige Vorteil ist, dass CSS-Dateien auch in JavaScript-Dateien importiert werden können. Das ist im HTML-Standard nicht vorgesehen.

Seine Stärke spielt Vite aus, wenn wir das Projekt packen. Das bedeutet, dass die Anzahl der Dateien reduziert wird und überflüssige Leerzeichen, Zeilenumbrüche, Kommentare etc. entfernt werden. Dadurch reduziert sich die Anzahl der Bytes, die zu einem Client (Browser) übertragen werden müssen, erheblich. Insbesondere für Smartphones mit einem geringen Datenvolumen profitieren davon.

Intelligente Frameworks wie Vue, Svelte oder React oder React gehen sogar noch einen Schritt weiter und laden nur die Teile einer Web-Seite (nicht Web-Site!) nach, die sich geändert haben. JavaScript-Bibliotheken werden so definiert, dass sie für eine ganze Web-Site nur einmal geladen werden müssen und für verschiedene Seiten wiederverwendet werden können. Hier spielen Web-Frameworks ihre Stärken aus. Sie stützen sich dabei auf Bundler wie Vite oder Webpack.

Führen Sie folgenden Befehl aus:

npm run build

Durch diesen Befehl wird die Web-App gepackt und im Ordner web abgelegt. Öffnen Sie die Datei web/index.html mit Hilfe des Live-Server-Plugins und sehen Sie sich das Ergebnis an. Schauen Sie sich auch die generierten Dateien im Ordner web an.

Testen Sie die Web-App dann, indem Sie entweder web/index.html mit dem Live Server von VSC starten oder indem Sie npm run preview eingeben.

Hello-World-App (Version 02)

Ersetzen Sie nun die Vite-Default-App durch die Hello-World-App aus dem 4. Teil des Tutoriums. In der Musterlösung habe ich die Version 04_4 als Hello-World-App verwendet.

Im Public-Bereich der Anwendung liegt noch die Datei vite.svg. Diese brauchen wir nicht mehr. Sie kann gelöscht werden. Dafür können Sie Dateien wie robots.txt oder favicon.ico einfügen.

robots.txt enthält Hinweise für die Suchmaschinen-Crawler, welche Dateien indexiert werden sollen und welche nicht. Die Crawler müssen sich aber nicht daran halten. Seriöse Crawler beachten die in der Datei aufgeführten Regeln allerdings.

favicon.ico ist ein Icon, das dem Text im Browser-Tab vorangestellt wird.

Wenn Sie die Produktivversion mittels npm run build oder npm run preview erstellen möchten, muss es eine Datei index.html geben, da Vite defaultmäßig die Erstellung von Single-Page-Anwendungen unterstützt. Defaultmäßig wird nur die Datei index.html in den Ordner build übernommen. Das ist für unsere Zwecke in Ordnung, da wir mit Hilfe von Vue eine Single-Page-Anwendung erstellen werden. Die Inhalte einer derartigen Anwendung werden per JavaScript nachgeladen. Man benötigt also tatsächlich nur eine HTML-Datei.

Achtung, die Datei body.css wird beim Packen von vite durch eine neue Datei mit zufälligem Namen ersetzt. Das zugehörige link-Element erhält keine id. Daher müssen wir in der Datei main.js die Zeile

document.getElementById('body_css').rel = 'stylesheet';

löschen. Fügen Sie dafür folgende Zeile am Anfang in main.js ein:

import '../css/body.css'

ECMAScript unterstützt den expliziten Import von CSS- oder JSON-Dateien nicht. Vite erweitert EXMAScript in dieser Hinsicht. Allerdings wird die von Vite erzeugte CSS-Datei, die einen zufälligen Namen erhält, statisch in die generierte Index-HTML-Datei eingafügt und damit synchron geladen.

Wir üssem uns noch überlegen, wie wir Vite dazu bringen, die von ihm generierte CSS-Datei asynchron zu laden.

Anmerkung für Nicht-Single-Page-Anwendungen
Sie können auch eine Anwendung mit diversen HTML-Dateien mit Hilfe von Vite bündeln und komprimieren. Dafür müssten Sie allerdings eine so genannte Rollup-Konfiguration in die Datei vite.config.js einfügen.

Verbesserungen (Version 03)

head.css inline und body.css dynamisch laden

Zur Erinnerung:

  • In head.css stehen möglichst wenig CSS-Anweisungen. Sie sollten ausreichen, um die aktuelle Seite “above the fold” („über dem Zeitungsknick“) fehlerfrei zu rendern. Das heißt, es sollte alles korrekt gerendert werden, was nach dem Laden im größtmöglichen Browserfenster sichtbar ist.
  • Der Inhalt der head.css sollte mittels des Style-Tags direkt in den Head-Bereich der HTML-Seite eingefügt werden.
  • Die restlichen CSS-Anweisungen werden in die Datei body.css eingetragen.
  • Dies Datei sollte asynchron, d. h. parallel zum Body-Element geladen werden.

Verwenden Sie im Style-Tag die Import-Anweisung, um die Datei css/head.css einzubinden. Dadurch wird erreicht, dass der Inhalt dieser Datei beim Bündeln direkt in die HTML-Datei eingebunden wurde (inline) und der Browser diese Datei nicht zusätzlich zu laden braucht.

<style>
  @import url("css/head.css");
</style>

Wie wir gesehen haben, wird der Inhalt Datei css/body bislang noch synchron geladen, obwohl wir den zugehörigen Import-Befehl in die Datei main.js eingefügt haben, die asynchron geladen wird..

In Vite gibt es jedoch eine Möglichkeit, CSS-Dateien dynamisch zu laden. Wenn man das Vite-Plugin cssInjectedByJsPlugin verwendet, werden die CSS-Dateien von Vite nicht statisch in die HTML-Datei eingefügt, sondern in der JavaScript-Datei dynamisch zur Laufzeit im Browser geladen und erst im Browser in die HTML-Datei eingefügt. Das zugehörige NPM-Package müssen Sie zunächst installieren:

npm i -D vite-plugin-css-injected-by-js

Anschließend wird das Plugin in vite.config.js konfiguriert.

import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'

export default
{ root:      'src', 
  publicDir: '../public',
  base:      '',
  build: 
  { outDir:  '../web',
    minify:  true,
  },
  plugins: 
  [ cssInjectedByJsPlugin(),
  ]
}

Schreiben Sie die Hello-World-App entsprechend um.

HTML komprimieren

Wenn man sich die Dateien im Web-Ordner ansieht, bemerkt man, dass nur die JavaScript- und CSS-Dateien gebündelt und verkleinert werden. Die HTML wurde dagegen nicht komprimiert. Um dies zu erreichen, benötigt man ein weiteres Vite-Plugin. Das zugehörige NPM-Package wird ebenfalls installiert:

npm i -D vite-plugin-minify

Anschließend muss das Plugin wieder in vite.config.js konfiguriert werden, in dem es zunächst importiert wird:

import { ViteMinifyPlugin } from 'vite-plugin-minify'

Anschließend wird der Initialisierungsbefehl in das Array plugins eingefügt. Diesmal wird allerdings zusätzlich ein Konfigurationsparameter übergeben, der die Komprimierung der HTML-Datei veranlasst:

ViteMinifyPlugin({}),

Der HTML-Minimizer komprimiert auch CSS-Anweisungen, die im HTML-Code enthalten sind. In unseren Fall ist das der Inhalt der Datei head.css, der wegen des @import-Befehls von Vite direkt in die HTML-Datei eingefügt wird.

Achtung!
Früher habe ich vite-plugin-html verwendet. Allerdings funktioniert bei Verwendung dieses Plugins der Vite-Proxy nicht mehr (Query Parameter und Argumente in der URL werden nicht weitergeleitet).

Lizenzkommentare entfernen

Ein Problem besteht noch. Die Lizenzkommentare werden in die komprimierten CSS- und JavaScript-Dateien eingefügt. Das kann gewünscht sein, kostet aber Platz. Das Problem kann man zumindest für JavaScript-Dateien beheben, indem man den Minimizer terser verwendet. Dieser bietet zahlreiche Konfigurationsmöglichkeiten an (ist allerdings beim Komprimieren wesentlich langsamer als der Standard-Minimizer). Schreiben Sie in der Datei vite.config.js an Stelle von

minify: true,

folgende Konfigurationsanweisungen:

minify:  'terser',
terserOptions: 
{ output: { comments: false } },

Für den CSS-Minimizer habe ich bislang keine entsprechenden Optionen gefunden. Schade. Aber das Problem lässt sich ganz einfach beheben, indem man in CSS-Dateien keine JSDoc-Kommentare verwendet (was ja durchaus auch sinnvoll ist, da CSS keinen JavaScript-Code enthält). Anstelle von

/**
 * @author    Wolfgang Kowarschick <kowa@hs-augsburg.de>
 * @copyright 2016-2025
 * @license   MIT
 */

können Sie beispielsweise

/*
 * author    Wolfgang Kowarschick <kowa@hs-augsburg.de>
 * copyright 2016-2025
 * license   MIT
 */

schreiben.

Alias-Pfade in vite.config.js

Fügen Sie in die Datei vite.config.js unter dem Tag resolve ein paar Pafdaliases ein:

  • @: Abkürzung für den Ordner ./src als root
  • /css: Abkürzung für den Ordner ./src/css
  • /js: Abkürzung für den Ordner ./src/js

Nun können Sie in der Datei index.html und der Javascript-Datei die absoluten Pfade @/..., /css/... und /js/... verwenden. Beim Straten der Anwendung mittels npm run dev und Bündeln der Anwendung mittels npm run build werden die Pfade von Vite gemäß den Alias-Definitionen aufgelöst.

Ersetzen Sie die relativen Pfade in den Dateien durch geeignete absolute Pfade.

import cssInjectedByJsPlugin  from 'vite-plugin-css-injected-by-js'
import { ViteMinifyPlugin }   from 'vite-plugin-minify'
import { fileURLToPath, URL } from 'url'

export default
{ root:      'src', 
  publicDir: '../public',
  base:      '',
  build: 
  { outDir:  '../web',
    minify:  'terser',
    terserOptions: 
    { output: { comments: false } },
  },
  plugins: 
  [ cssInjectedByJsPlugin(),
    ViteMinifyPlugin({}),
  ], 
  resolve:
  { alias:
    { '@':    fileURLToPath(new URL('./src',     import.meta.url)),
      '/css': fileURLToPath(new URL('./src/css', import.meta.url)),
      '/js':  fileURLToPath(new URL('./src/js',  import.meta.url)),
    }
  },
}

Fortsetzung des Tutoriums

Sie sollten nun Teil 6 des Tutoriums bearbeiten. In diesem Teil des Tutoriums wird ausgenutzt, dass CSS nun auch Variablendefinitionen (eigentlich handelt es sich um Konstantendefinitionen) und den Import-Befehl unterstützt. Damit kann man das Prinzip “Don't Repeat Yourself” (DRY) auch für CSS-Dateien umsetzen.

Quellen

  1. Kowarschick (WebProg): Wolfgang Kowarschick; Vorlesung „Web-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2024; Quellengüte: 3 (Vorlesung)