ACHTUNG: Hier handelt es sich um die Dokumentation für Stud.IP <4.2.
Pakete und Kompression von JavaScript
Motivation
Für wartbares JavaScript sind u.a. folgende Punkte entscheidend:
Dokumentation
Unbestreitbar sollte JavaScript-Code genau wie jeder andere Code an Ort und Stelle kommentiert sein/werden können. Idealerweise müsste literate programming möglich sein („When was the last time you spent a pleasant evening in a comfortable chair, reading a good program?").
Dem steht allerdings das Problem gegenüber, dass mit unserem gegenwärtigen System jedes Dokumentationsbyte auch an alle Stud.IP-Nutzer ausgeliefert wird. Gute Dokumentation kann recht ausführlich sein und es spricht alles dagegen, statt der gegenwärtigen ~350 kB (ohne vorhandene Dokumentation) eines Tages ~700 kB (mit zukünftiger Dokumentation) auszuliefern.
Anzahl der Dateien
Wenn man Code wartbar halten will, macht es Sinn, Code-Teile, die nichts miteinander zu tun haben, nicht in einer riesigen, sondern lieber in mehreren separaten Dateien vorzuhalten.
Dem steht aber der Wunsch gegenüber, möglichst wenig Requests an den Server zu schicken (siehe z.B. http://code.google.com/speed/page-speed/docs/rtt.html). In der jüngeren Vergangenheit was das dramatischer (http://www.browserscope.org/?category=network) als es jetzt ist. Dennoch macht man alles richtig, wenn man möglichst wenig Dateien sendet.
Komprimierung
Anders als bei z.B. PHP-Code macht es bei JavaScript einen Unterschied, wie man seinen Code formattiert, da jedes einzelne Zeichen über die Leitung geht. Selbstverständlich würde man niemals uneingerückten Code auf einer Zeile schreiben, nur um die Zahl der Bytes zu minimieren. Andererseits machen sich selbst einfache Formen der Komprimierung (z.B. Einrückung und Kommentare entfernen) in Hinsicht auf die Performance bezahlt. Mit vorhandenen Tools wie dem YUI-Compressor[1], Google-Closure-Compiler[2] oder dem Uglifier[3] läßt sich viel gewinnen. Die Komprimierung des Webservers (z.B. Apaches mod_deflate) setzt dem ganzen das Sahnehäubchen auf (ist aber natürlich alleine für sich nicht so gut wie die genannten Tools.)
1: http://developer.yahoo.com/yui/compressor/
2: http://code.google.com/p/closure-compiler/
3: https://github.com/mishoo/UglifyJS
Spezifischer Code
Nicht jeder JavaScript-Code muss auf jeder Seite verfügbar sein. Es ist z.B. unnötig, die Studienbereichzuordnung auch auf Wiki-Seiten zu laden. Derzeit bleibt uns nicht anderes übrig, als alles in einer Datei und damit auf jeder Webseite zu haben. Schöner könnte es sein, wenn man das für jede Seite (natürlich nur in einem gewissen Rahmen siehe "Anzahl der Dateien") selbst entscheiden könnte.
Fazit
Der Stud.IP-Nutzer mag (aus Performance-Gründen) JavaScript, das in wenigen Dateien ohne unnötige Zeichen komprimiert ausgeliefert wird.
Der Stud.IP-Entwickler mag (aus Wartbarkeitsgründen) JavaScript, das in vielen Dateien mit viel Whitespace und Dokumentation versehen ist.
Stud.IP-Implementation
Glücklicherweise kann man in Stud.IP mit geringem Aufwand beides haben:
1.) JavaScript wird in sinnvolle Dateien aufgeteilt und kann dort beliebig formatiert und dokumentiert werden.
2.) Diese Dateien in sinnvolle Pakete zusammen, die dann je nach Bedarf der Seite geladen werden.
Die Pakete werden in der Datei config/assets.yml formuliert:
compress: true
javascripts:
jquery: &jquery
- javascripts/jquery/jquery-1.7.js
- javascripts/jquery/jquery-ui-1.8.14.custom.min.js
- javascripts/jquery/jquery.metadata.js
- javascripts/jquery/jquery.placehold-0.3.js
- javascripts/jquery/validator.min.js
base:
- *jquery
- javascripts/underscore.js
- javascripts/l10n.js
[...]
raumzeit:
- javascripts/raumzeit.js
smileys:
- javascripts/smiley.js
3.) In Stud.IP wird per Default das Paket "base" eingebunden. Weitere
Pakete können im PHP-Code so hinzugefügt werden:
[code]
<?= PageLayout::addSqueezePackage("raumzeit") ?>
[/code]
4.) Entsprechend des Modus, in dem sich die Stud.IP-Version befindet
(Produktiv- oder Entwicklermodus), werden die JS-Pakete
unterschiedlich ausgegeben:
a.) Im Entwicklermodus will man alle Möglichkeiten zum Debugging
haben. Wenn man beispielsweise die Pakete "base" und "raumzeit"
eingebunden hat, ergibt sich folgende Ausgabe:
<script src="assets/javascripts/jquery/jquery-1.7.js"></script>
<script src="assets/javascripts/jquery/jquery-ui-1.8.14.custom.min.js"></script>
<script src="assets/javascripts/jquery/jquery.metadata.js"></script>
<script src="assets/javascripts/jquery/jquery.placehold-0.3.js"></script>
<script src="assets/javascripts/jquery/validator.min.js"></script>
<script src="assets/javascripts/underscore.js"></script>
<script src="assets/javascripts/l10n.js"></script>
<script src="assets/javascripts/raumzeit.js"></script>
Es werden lediglich Tags generiert, die auf die unkomprimierten Einzeldateien verweisen. Performance ist in diesem Zusammenhang nebensächlich.
b.) Im Produktivmodus will man optimale Performance erreichen. Mit
denselben Paketen "base" und "raumzeit" ergibt sich dazu folgendes:
<script src="assets/squeezed/base.js"></script>
<script src="assets/squeezed/raumzeit.js"></script>
Die darin verlinkten Dateien enthalten den konkatenierten und
anschließend komprimierten Code aller JS-Dateien, die zum
entsprechenden Paket gehören. Der Inhalt einer solchen JS-Paket-Datei
würde zum Beispiel so aussehen:
(function(){var a=window;a.hello=function(a,b){a.alert("Hello, "+a)}})();
Wenn man ein Stud.IP-Release installiert hat, wurden die
entsprechenden Dateien bereits erzeugt. Nimmt man später Änderungen an
den eigentlichen JS-Dateien (also beispielsweise an
"assets/javascripts/raumzeit.js") vor, müssen die Dateien erneut
erzeugt werden. Dazu gibt man auf der Kommandozeile innerhalb der
Stud.IP-Installation den folgenden Befehl ein:
make build
Systemseitige Anforderungen
Damit tatsächlich komprimierte (und nicht nur konkatenierte) JS- bzw. CSS-Paket-Dateien herauskommen, müssen auf dem Rechern die Node.js-Pakete uglify-js
und clean-css-cli
installiert sein. Diese stehen in manchen Linux-Distributionen über den regulären Paketmanager zur Verfügung.
Sollte dies bei Ihnen nicht der Fall sein, installieren Sie über den Paketmanager Ihres System den "Node.js Packet Manager" npm
oder alternativ über das passende Installationspaket unter https://nodejs.org/. Anschliessen führen Sie den folgenden Befehl aus, um die beiden Pakete systemweit zu installieren:
npm install -g uglify-js clean-css-cli