Transcript

faucet-pipeline

JavaScript, CSS, Bilder und Fonts bereit zum Ausliefern

Jede Web-Anwendung muss einen ganzen Haufen Assets – also JavaScript, CSS, Bilder und Fonts – ausliefern. Aber wie sorgt man dafür, dass diese Dateien optimal ausgeliefert werden? Lucas beschäftigt sich seit längerem mit diesem Thema im Rahmen des Open-Source-Projekts faucet-pipeline. Also löchert Robert ihn mit einer Reihe von Fragen zu Themen wie Dateigröße, über Bundling zu Caching – und wie faucet dabei hilft.

Back to episode

Transcript

Robert Glaser: Herzlich Willkommen beim INNOQ-Podcast! Neue Folge, neues Glück, hätte ich fast gesagt, aber Glück brauchen wir ja nicht. Heute habe ich Lucas bei mir. Lucas kennt ihr bestimmt, er ist nämlich der eigentliche Moderator dieses Podcasts. Ich bin immer nur so Ersatzmoderator oder ich springe gerne mal ein, wenn Lucas keine Zeit hat. Und heute kommt es zum – wie sagt man? – Aufeinandertreffen der Moderatoren.

Lucas Dohmen: So ist es.

Robert Glaser: Und wir moderieren uns nicht nur gegenseitig, Lucas ist heute mit einem ganz speziellen Thema da. Denn Lucas ist ja nicht hauptberuflich Podcast-Moderator, auch wenn man das manchmal annehmen könnte. Lucas ist bei INNOQ auch Senior Consultant und engagiert sich viel in der Open Source-Community und hat ich weiß nicht wie viele Projekte. Die können wir ja später im Verlauf der Sendung mal zählen. Aber darum geht es gar nicht, sondern es geht um ein bestimmtes Projekt, das du mit Kolleginnen und Kollegen von INNOQ zusammen gebaut hast. Und zwar geht es da um die Bibliothek faucet oder das Tool faucet, wie der Wasserhahn auf englisch.

Lucas Dohmen: Genau.

Robert Glaser: Soweit ich das verstanden habe, ist faucet eine Asset-Pipeline, eine Open Source-Asset-Pipeline, mit der ich statische Dateien in meiner Webanwendung bundeln, präprozessieren, generieren und was weiß ich noch was mit tun kann. Habe ich da recht oder ist das etwas ganz anderes oder was tut faucet eigentlich genau? Was ist das? Und was ist eigentlich die Problemstellung, die du damit versuchst zu lösen?

Lucas Dohmen: Das ist eine gute Frage, Robert. Also grundsätzlich bin ich ja kein Fan davon, Probleme zu lösen, die schon gelöst sind, sondern lieber irgendwie zu überlegen, welche von den Lösungen, die es schon gibt, könnte man verwenden. Und faucet ist so ein bisschen daraus entstanden, dass keins von den existierenden Tools das erfüllt hat, was wir damals im Projekt gebraucht haben. Also es ist aus einem Kundenprojekt heraus entstanden – dazu kann ich auch gleich noch ein bisschen mehr erzählen – weil diese Probleme gelöst werden sollten. Und der Kunde war freundlicherweise so nett, mir zu erlauben, das auch als Open Source-Projekt zu starten und tatsächlich dann auch Teile von der Open Source-Arbeit daran zu sponsern. Also, worum geht es? Wahrscheinlich in jeder Webanwendung, die es so gibt, haben wir Assets. Das sind so Sachen wie Bilder, Fonts, CSS, JavaScript. Das sind so die vier Hauptkategorien, die man so gut wie immer hat. Und bei diesen Kategorien gibt es verschiedene Dinge, die wir mit diesen Assets machen wollen, bevor wir sie in Produktion bringen. Und ich würde das so grob in vier Kategorien von Problemen, die wir lösen müssen, einteilen, um diese Sachen in Produktion vernünftig ausliefern zu können. Und für mich wäre so das erste Offensichtliche: Wir möchten, dass diese Assets so klein sind wie möglich. Wir möchten möglichst wenig Bandbreite verbrauchen, wir möchten, dass es möglichst schnell beim Kunden oder der Kundin ankommt, also müssen wir das kleiner bekommen. Und das kommt natürlich ganz darauf an, was für eine Art von Asset das ist, wie wir das kleiner bekommen. Nehmen wir jetzt mal Bilder. Bilder gibt es zum Beispiel in JPG oder als PNG-Bild. Und wenn wir die jetzt standardmäßig so nehmen, wie wir sie bekommen, dann können wir da auf jeden Fall noch etwas herausholen. Robert ist ja zum Beispiel großer Fan von mozjpeg als Kompressor. Das ist tatsächlich einfach ein Tool, das ein JPG nimmt und ein JPG daraus macht, aber das JPG hat dann einfach eine geringere Dateigröße ohne die Qualität einzubüßen. Das wäre jetzt so ein Beispiel für diese Kategorie von Problemen. Wir möchten das Bild einfach kleiner haben. Eine Variante davon ist, vielleicht möchten wir auch ein anderes Bildformat verwenden. Also vielleicht haben wir gemerkt, dass wenn wir das als WebP ausliefern, was so ein modernes Bildformat ist, dass es da kleiner ist als JPG oder PNG. Dann möchten wir vielleicht unsere Bilder erst einmal konvertieren in ein anderes Format, weil das einfach besser funktioniert, weil das kleiner ist. Oder wir möchten vielleicht so etwas machen wie, wir haben JavaScript und wir möchten das minifizieren. Das ist ja so ein Ding, das gab es irgendwie früher einmal, dieses JSMinify oder wie hieß das noch mal? JSMin?

Robert Glaser: JSMin hieß das, glaube ich. Aber es gab ja zig Libraries dafür.

Lucas Dohmen: Ich glaube, das war so das erste. Also zumindest das erste, was ich benutze habe. Und was man mit JS-Minify macht, ist: Man versucht quasi, das JavaScript kleiner zu machen, indem man beispielsweise Whitespaces herausnimmt oder vielleicht sogar krassere Sachen macht und alle Variablennamen in einbuchstabige Variablennamen umbenennt oder so etwas. Das wäre jetzt so ein typischer Minify-Prozess. Ein Tool, das dafür aktuell gerne benutzt wird, ist Terser, das ist so ein Fork von UglifyJS. Das kann halt sehr gut Sachen kleiner machen.

Robert Glaser: Wenn wir kurz dabei bleiben, bei diesem ganzen Minifizieren.

Lucas Dohmen: Klar, auf jeden Fall.

Robert Glaser: Entschuldigung, dass ich dir jetzt so hereinfalle, aber ich habe so viele Fragen. Bei diesem ganzen Minifizieren habe ich mich immer gefragt, warum macht man das eigentlich? Ich habe doch einen Webserver und typischerweise ist doch da Gzipping oder irgendetwas aktiviert. Und was halt richtig gut geht, um Textdateien kleinzukriegen, ist doch, die zu zippen. Und wenn der Webserver das sowieso macht, wieso muss ich dieses ganze Minifizieren dann noch mal anstoßen? Erfindet man dann nicht Zipping neu und falls ja, legt man dann auf das Minifizierte noch mal Zip drauf? Also ich würde mir gerne auch so ein bisschen Sachen sparen. Denn es sind ja alles Technologien, Libraries, die ich dann in mein Projekt ziehe. Wozu muss ich minifizieren, ist meine Frage?

Lucas Dohmen: Das ist eine sehr, sehr gute Frage. Nginx und Apache wäre jetzt ein gutes Beispiel. Das gehört ja so in die Kategorie Reverse Proxy. Also man hat irgendetwas, was vor der Anwendung sitzt und man hat da so einen Reverse Proxy und der Reverse Proxy bearbeitet diese Sachen. Und es gibt ja auch viele Reverse-Proxies, die speziell darauf ausgerichtet sind, solche Optimierungen auszuführen. Also Varnish beispielsweise ist ja auch ein Reverse Proxy und die nennen sich ja selbst Web-Accelerator oder so etwas, ich glaube, so hieß es, um genau solche Sachen zu tun. Und grundsätzlich können wir all diese Dinge, die ich gerade auch aufgezählt habe, auch in einem Reverse Proxy machen. Und das ist auch vielleicht keine schlechte Idee. Also wenn wir jetzt darüber nachdenken: Du kommst auf meine Webseite und du hast einen älteren Browser und dann kannst du kein WebP, dann kann das der Reverse Proxy anhand deiner HTTP-Header ja feststellen. Wenn du WebP-Unterstützung hast, dann schickt der dir WebP, und wenn du es nicht hast, dann schickt er dir halt JPG, beispielsweise. Und genauso könnte der feststellen, dass du Gzip unterstützt, dann schickt er dir Gzip. Und wenn du das nicht unterstützt, dann schickt er dir kein Gzip.

Robert Glaser: Ah, ok. Also ich halte am besten alles vor für jede Art von Client und jede Art von Feature-Unterstützung, die da so ankommen kann bei mir. Und dadurch, dass einmal alles von faucet quasi gebaut, gebundelt, minifiziert abgelegt wurde, habe ich auch alles. Also wahrscheinlich mache ich das im Build-Schritt. Und egal wer oder was dann da ankommt bei mir, bekommt die richtigen Sachen geliefert, weil sie eben alle da sind.

Lucas Dohmen: Genau. Und das könntest du beispielsweise im Reverse Proxy machen. Und jetzt bleibt noch die andere Frage von dir, warum muss ich das überhaupt alles tun? Ich könnte das alles quasi im Reverse Proxy live machen, aber dann mache ich ja jedes Mal die Arbeit für jeden Request. Gerade eine Bildkompressionslibrary wie mozjpeg, die braucht halt tatsächlich eine erhebliche Menge Zeit, um das Bild zu komprimieren. Das möchtest du nicht jedes Mal machen, wenn es ausgeliefert wird. Du möchtest es quasi einmal machen in einem Build-Step und danach nur noch ausliefern. Das wäre so die Traumvorstellung. Das heißt, wenn du das im Reverse Proxy machen möchtest, gibt es einige, die so schnell sind, dass du das live machen kannst, aber andere Operationen möchtest du vielleicht in einem Build-Step machen. Ein Beispiel für etwas, was du gut live machen kannst, ist zum Beispiel Gzipping, weil Gzip sehr, sehr schnell ist. Wenn du das im Reverse Proxy machst, dann brauchst du nicht unbedingt die gegzippte Version. Aber es schadet auch nicht. Wenn sowieso dein CSS und das JavaScript immer das gleiche ist, was du auslieferst, wenn du dann sowieso schon eine gegzippte Version hast, warum dann nicht die ausliefern? Also da spricht ja nichts gegen.

Robert Glaser: Okay, das verstehe ich.

Lucas Dohmen: Aber wenn wir jetzt an so etwas wie CDNs denken, also zum Beispiel, wie heißt es…?

Robert Glaser: CloudFront oder …

Lucas Dohmen: Ja. Cloudflare meinte ich gerade, danke dir. Cloudflare wäre jetzt so ein Beispiel, die machen ganz viele von diesen Sachen. Die können sogar auch dein CSS minifizieren, on the fly quasi, und legen es dann halt im Cache ab. Wenn du so etwas benutzt, dann brauchst du vielleicht diesen Aspekt gar nicht zu beachten, weil du das einfach an einer anderen Stelle löst. Und das ist auch absolut fein. Es ist halt nur oft so, dass entweder das zu aufwändig wäre, also einfach laufzeitmäßig zu aufwändig wäre oder vielleicht hat man einfach nicht ein Cloudflare davor sitzen sondern eher ein Nginx, wo jetzt zum Beispiel Image-Optimierung eher selten mit dabei ist. Aber grundsätzlich könntest du das da auch lösen. Und ich finde das auch einen absolut sinnvollen Lösungsansatz bei diesen Verkleinerungsoperationen, sage ich jetzt mal.

Robert Glaser: Aber wenn man noch mal zurück zu faucet kommen will. Man verliert sich immer so schnell in diesen …

Lucas Dohmen: Aber warte mal. Robert, ich glaube, ich habe noch eine Frage von dir vergessen. Du hast noch gefragt, wenn es doch Gzip gibt, wieso muss ich dann überhaupt noch meine Bilder optimieren. Das hast du auch noch gefragt, ne?

Robert Glaser: Stimmt, die hast du noch offen.

Lucas Dohmen: Genau, die ist noch offen, nicht dass ich deine Fragen vergesse. Das Ding ist, dass die meisten von diesen Kompressionsformaten wie Gzip oder auch modernere wie dieses Brotli beispielsweise, was jetzt mittlerweile in den meisten Browsern eingebaut ist, die sind optimiert, um Text zu komprimieren, nicht um Binärdaten zu komprimieren. Wenn du ein JPG beispielsweise durch Gzip durchjagst, dann wird dabei nicht viel Ersparnis herauskommen. Wohingegen wenn du das durch einen besseren JPG-Kompressor zum Beispiel hindurchjagst, dann wird ein viel, viel kleineres Bild daraus. Das heißt, für CSS, JavaScript, HTML und so, dafür ist Gzip und Brotli genau das Richtige, oder auch für ein SVG beispielsweise. Aber für ein JPG oder ein WebP-Bild oder einen Font ist es nicht das Richtige. Also es ist dieselbe Kategorie, aber man kann nicht mit einem Tool alle Probleme darum lösen.

Robert Glaser: Okay, gut, jetzt haben wir so ein bisschen einen Exkurs gemacht in das Thema Kompression von meinen ganzen statischen Dateien, die ich so haben könnte in meiner Webanwendung. Aber faucet ist ja, wenn ich das richtig verstanden habe, eigentlich nicht nur ein Tool, um Dinge zu komprimieren, sondern du hast es am Anfang gesagt, es kann ja noch viel mehr. Hast du das, das ist jetzt eine dumme Frage, aber habt ihr – ich sage immer du du aber in dem Fall meine ich immer das Team, das dahinter steht und auch die Open Source-Kontributoren. Habt ihr da alles neu erfunden? Also vom Kompressor bis zum Wandler bis zum weiß der Henker was? Oder nutzt faucet selber Open Source-Tools und agiert nur als API, wie man das so sagen kann?

Lucas Dohmen: Also absolut, ich fände es einen ganz schön krassen Aufwand, all diese Dinge neu zu schreiben. Wir greifen ganz, ganz viel auf existierende Tools zurück. Im Prinzip bietet faucet so eine Art kuratierte Tool-Suite. Du hast mir jetzt gerade ganz, ganz viele Fragen gestellt, was wäre denn da jetzt der beste Kompressor? Und diese Fragen gibt es natürlich auch immer wieder. Das heißt also, was wir mit faucet versuchen ist quasi, diese Tools zu kuratieren und dir jetzt einen Kompressor zu geben, der sehr, sehr gut ist, damit du nicht diesen Rechercheaufwand betreiben musst. Das heißt, wir paketieren für dich schon einmal unsere Meinungen dazu, welches Tool da das aktuell beste ist. Und wir wechseln diese Meinung auch und tauschen dann quasi untendrunter die Tools aus, ohne dass du als Anwender von faucet irgendetwas machen musst. Das ist so ein bisschen die Philosophie. Das heißt, wir beschäftigen uns damit, damit du dich damit nicht beschäftigen musst.

Robert Glaser: Aha, ok. Also so ein bisschen in die Richtung Omakase, also japanisches Menü-Restaurant Es wird gegessen, was auf den Tisch kommt.

Lucas Dohmen: Genau, absolut.

Robert Glaser: Aber das kann ja auch für einige Menschen ein Vorteil sein. Ich zähle mich jetzt einfach mal dazu. Ich genieße das, wenn jemand wie du oder ihr, das Team, technologische Entscheidungen für mich trefft. Da gehört natürlich auch so ein bisschen Vertrauen dazu, dass das die richtigen Entscheidungen sind, und nimmt mir im Projektalltag wahrscheinlich sehr viel Arbeit ab, weil ich mich nicht mit Konfigurationenaufwänden befassen muss. Zum Beispiel, nehme ich jetzt mozjpeg oder nehme ich Gützli? Oder ist das nicht vielleicht dasselbe? Man sieht es schon, da kann man sich in so einen Fuchsbau verrennen und ich persönlich mag das nicht, alle diese Entscheidung treffen zu müssen von Projekt zu Projekt. Deswegen finde ich so einen kuratierten Ansatz gut. Du wahrscheinlich auch, sonst hättest du es nicht so gemacht.

Lucas Dohmen: Richtig. Also tatsächlich ist das auch etwas… Ich habe mir darüber sehr viele Gedanken gemacht bei Fejo damals und ich habe gedacht, eigentlich ist von all den Entscheidungen, die ich hier getroffen habe, keine so spezifisch für diesen Kunden, dass ich das nicht auch bei einem anderen Kunden bräuchte. Es gibt immer Gründe, vielleicht davon abzuweichen, aber für die meisten Kunden sind diese Probleme, über die wir gerade sprechen, eigentlich immer die gleichen. Das heißt, sie einmal zu lösen, ist absolut sinnvoll, weil wir das dann nicht jedes Mal neu machen müssen. Ich habe da auch keine Lust zu. Ich habe keine Lust, in jedem Projekt erst einmal die eine Woche oder mehr zu investieren, um da diese ganze Build-Chain aufzubauen, sondern ich möchte das halt einmal machen und dann einfach wiederverwenden können. Und genauso möchte ich, dass meine Kolleginnen und Kollegen bei INNOQ das auch nutzen können und einfach sagen können, okay, Lucas und Frederik haben sich darüber schon mal Gedanken gemacht und die sind zu diesem Schluss gekommen. Und wenn sie jetzt keine Lust haben, das zu hinterfragen, dann können sie es erst einmal so nehmen. Das ist so quasi die Idee und das ist das, wodurch wir einfach Zeit sparen, sowohl unseren Kunden als auch uns selbst. Auch Nerven, weil das auch nicht so eine total tolle Aufgabe ist, diese ganzen Tools zusammenzusuchen. Das ist auch nicht INNOQ-spezifisch, genauso für Leute, die außerhalb von INNOQ sind und dieses Tool benutzen, da gibt es auch ein paar. Die brauchen dann halt einfach darüber nicht nachzudenken. Sie können das einfach nehmen, es ist Open Source. Wenn sie jetzt merken, diese Wahl, die die getroffen haben, ist total doof, okay. Dann ist es vielleicht nicht das richtige Tool. Aber gerade für jemanden wie Robert, der halt einfach gerne Dinge fertig macht, ist das so dieses Tool, bei dem man dann halt eben nicht erst einmal noch so ein Auswahlprozess anstoßen muss und schauen muss, evaluieren wir jetzt mal den aktuell besten JavaScript-Minifier oder so.

Robert Glaser: Okay. Jetzt haben wir so ein bisschen über die Philosophie gesprochen, was faucet eigentlich ist. Also es ist quasi eine API, ein Tool, das verschiedene fertige Lösungen zusammenfasst, kuratiert und das versucht, es den Anwenderinnen und Anwendern möglichst einfach zu machen, diese Dinge nicht selbst konfigurieren zu müssen, die Entscheidungen, die technologischen Entscheidungen, welche Komponenten für welchen Einsatzzweck benutzt werden, nicht selbst treffen zu müssen. Und wir haben so ein bisschen über die Kompressionsthematik gesprochen. Aber faucet macht ja noch viel mehr, wenn ich hier auf eure Website schaue (die packen wir auch mal in die Shownotes, faucet-pipeline.org). Dann steht da ja viel mehr. Und da sehe ich ganz zu vorderst natürlich JavaScript. Danach werden die meisten sicher auch suchen oder viele werden über dieses Thema bei faucet landen.

Lucas Dohmen: Auf jeden Fall.

Robert Glaser: Was macht denn faucet mit JavaScript?

Lucas Dohmen: Genau. Also ich hatte ja schon eben quasi gesagt, der eine große Themenkomplexe ist irgendwie, die Dateigröße zu verringern. Der zweite Punkt – und da ist gerade JavaScript ein wichtiger Fall für – ist Transformation, so nenne ich das jetzt einmal. Wir haben beispielsweise unseren Code in TypeScript geschrieben und das kann der Browser nicht, also muss ich es erst einmal konvertieren in JavaScript. Oder ich habe so etwas benutzt wie JSX, was Leute in React beispielsweise benutzen. Das ist ja so eine Syntaxerweiterung von JavaScript und das kann man kompilieren zu normalem JavaScript. Das wäre jetzt auch so eine Transformation. Ein anderes Beispiel wäre SCSS oder Sass, das viele Leute, die CSS schreiben, gerne benutzen als Tool. So ein Präprozessor oder eine Sprache, die in CSS kompiliert, die dem bestimmte Features hinzufügt, also Sass beispielsweise in CSS verwandelt. Oder ich möchte so etwas machen wie: Ich habe ganz mordernes JavaScript geschrieben, und ich möchte das so umwandeln, dass das in einem älteren Browser funktioniert, wie etwa im Internet Explorer 11. Das wäre auch so eine Transformation, die wir durchführen wollen. Oder ich habe CSS und ich möchte da bestimmte Prefixes hinzufügen. Es gibt ja diese Browserprefixes, die mittlerweile nicht mehr das Mittel der Wahl sind bei den Browserherstellern, das ist jetzt nicht mehr ein so ganz brandaktuelles Thema. Aber es kommt immer noch vor, gerade wenn man halt doch ein bisschen ältere Browser unterstützen will. Dann gibt es halt bestimmte Möglichkeiten, quasi automatisch eine zweite Version von einer Regel hinzuzufügen, die in älteren, anderen Browsern funktioniert.

Robert Glaser: Das sind diese -webkit-Präfixe für Properties in CSS, die noch nicht final sind?

Lucas Dohmen: Oder -moz für Mozilla oder so etwas. Das wären diese Prefixes. Das sind alles so Transformationen, das trifft eigentlich hauptsächlich auf CSS und JavaScript zu, dass wir nicht CSS so schreiben, wie es nachher genau ausgeliefert wird, sondern quasi erst noch so einen Transformationsschritt davor haben. Das wäre auch ein ganz übliches Requirement, was ganz viele Leute haben, dass sie das machen wollen.

Robert Glaser: Aber lass uns bei JavaScript bleiben. Da hattest du kurz gesagt, es gibt auch in JavaScript Dinge, Technologien, die ich nutzen möchte wie beispielsweise React, die, würde ich sie so an den Browser schicken, der Browser natürlich überhaupt nicht versteht und irgendwie nur einen Syntax-Error rendern würde. Da bietet faucet mir also eine Möglichkeit, dass ich diese Syntax in natives JavaScript übersetzen lassen kann, richtig?

Lucas Dohmen: Genau, so ist es.

Robert Glaser: Okay. Wie sieht es denn aus mit modernen JavaScript-Funktionen? Die landen ja auch nicht immer sofort in Browsern. Zum Beispiel, wir hatten in den letzten Jahren dieses ganze Modulthema. JavaScript konnte ja nie richtig native Module oder Imports. Das war auch so ein Grund, warum diese ganzen Bundling-Tools, so nennen die sich ja, glaube ich, an den Markt kamen, die dann quasi Modulsyntaxen erfunden haben oder irgendwann sich nach dem JavaScript-Standard gerichtet haben, oder ihn auch getrieben haben, dass es überhaupt mal ein Standard wurde über die letzten Jahre. Wie sieht es da aus? Kann faucet auch bundlen? Das heißt, kann ich mein JavaScript modular schreiben und faucet kümmert sich darum, dass die Imports klappen von verschiedenen Modulen?

Lucas Dohmen: Genau, das ist auf jeden Fall auch ein ganz wichtiges Thema. Das wäre für mich so der dritte Themenkomplex, das Bundling. Das gibt es ja nicht nur für JavaScript, sondern auch wieder für CSS. Das gibt es in beiden Welten, dieses Problem. Und das ist auch ein ganz essenzieller Teil von dieser Funktionalität in faucet. Tatsächlich ist es ja auch nicht so, dass es ausschließlich darum geht, dass jetzt irgendwie der Browser die moderne Syntax nicht unterstützt oder keine Module-Unterstützung hat oder so. Das Problem ist tatsächlich etwas… Also manche Leute haben das irgendwie, seitdem es HTTP/2 gibt, als abgehakt in ihrem Kopf gespeichert, aber tatsächlich sehe ich das ein bisschen anders. Wenn wir so ein typisches JavaScript-Projekt haben: Wir haben vielleicht 120 verschiedene JavaScript-Dateien geschrieben, die mit verschiedener… Sagen wir jetzt mal, die sind in dieser modernen ECMAScript 6-Modul-Syntax geschrieben, mit import … und export …. Und dann haben wir irgendwie 140 Dateien. Dann kann jetzt ein moderner Browser einfach quasi die Startdatei laden, darin lesen, du importierst hier folgende fünf Dateien, dann lädt er diese fünf Dateien herunter. Dann schaut er, darin sind wieder irgendwelche Import-Statements, die löst er auch auf, lädt sie herunter und so weiter. Das funktioniert in einem modernen Browser, es ist aber die Frage, ob das so wünschenswert ist. Wenn wir das nämlich tun, dann haben wir kaskadierende Requests. Wir starten mit einem Request und erst wenn der heruntergeladen ist, wissen wir, welche Dependencies diese Datei hatte. Also startet der jetzt vier weitere Requests. Darin sind jetzt noch einmal drei Dateien referenziert. Dann startet er noch einmal drei weitere Requests. Und dasselbe gilt für CSS. Da gibt es ja auch eine moderne Import-Syntax, die auch die meisten Browser unterstützen. Auch da gilt dasselbe, wir würden so eine Kaskade aufbauen und gerade in Webanwendungen ist halt Latenz ein ganz, ganz kritisches Thema. Also die Zeit, die es braucht, ein Paket zu schicken und die Antwort zu bekommen, weil wir ja erst einmal jedes Mal die Antwort bekommen müssen, sie interpretieren und erst dann können wir den nächsten Request auslösen. Und wir möchten bei solchen kaskadierenden Requests eine möglichst kleine Kaskade haben, weil das halt einfach viel zu viel Zeit kostet, jedes Mal hin und her zu springen.

Robert Glaser: Okay, das heißt, das Problem ist eigentlich, wenn ich mir als Entwickler super Mühe gebe, meinen JavaScript-Code modular, wiederverwendbar und möglichst kleinteilig zu strukturieren, was ja auch Teil von guter Architektur ist, dann ist das für das Entwicklungsteam und mich wahrscheinlich super, weil mein Code idealerweise wartbarer wird, modularer, übersichtlicher. Aber für den Client, den Browser wäre es ein Albtraum, besonders für ein Mobile Device, das auf einem Akku läuft in einer schlechten Mobilfunkzelle, wenn da 25 kaskadierende, kleine Requests entstehen, um JavaScript-Module nachzuladen, die wiederum Module nachladen. Das geht wahrscheinlich ziemlich auf den Akku.

Lucas Dohmen: Genau, das geht auf den Akku und das kostet einfach sehr viel Zeit, weil wir ja jedes Mal warten müssen, bis alles heruntergeladen ist. Grundsätzlich können wir mit HTTP/2 und HTTP/3 – das ist ein Thema, das möchte ich jetzt nicht ganz aufmachen, das würde dann doch den Rahmen etwas sprengen –

Robert Glaser: Dazu könnten wir aber mal einen Podcast machen.

Lucas Dohmen: Das können wir gerne machen, Robert. Dann haben wir direkt schon unsere zweiten Termin.

Robert Glaser: Den machst du besser mit Stefan.

Lucas Dohmen: Okay. Jedenfalls, diese Technologien erlauben es uns quasi, mehr Dateien gleichzeitig herunterzuladen, was toll ist. Das heißt also, grundsätzlich ist das besser, als bei HTTP/1 mehr Dateien zu haben, aber das Problem von dieser Kaskade, von diesen kaskadierenden Requests, das geht nicht weg. Das geht nicht weg, weil es halt einfach in dem drin steckt, dass du die Antwort erst interpretieren muss, bevor du den nächsten Request schicken kannst. Und solange es dieses Problem gibt, müssen wir uns damit beschäftigen. Es gibt einen Fix dafür und das ist ein Server Push. Server Push ist so ein HTTP/2-Feature. Da fragst du eine Datei an und der Server antwortet dir nicht mit einer Datei sondern mit mehreren Dateien, weil er weiß, dass du die brauchen wirst. Das Problem daran ist, wenn du das übertreibst, dann machst du das Caching kaputt. Denn wenn der Browser diese Dateien schon gecacht hat, dann muss er dir hier jetzt quasi sagen, bitte brich diese Antworten ab, die kenne ich schon. Dadurch wird es in der Praxis tatsächlich sehr, sehr wenig benutzt, dieses Push. Ich habe es tatsächlich noch nie in einem Projekt benutzt, weil mit dieser Trade-off das nicht wert ist. Das heißt, ich denke dann lieber darüber nach, wie sorge ich dafür, dass wir keinen kaskadierenden Request haben. Das heißt nicht, dass alles in einer JavaScript-Datei landen muss. In den meisten Projekten habe ich dann doch irgendetwas zwischen drei und zehn JavaScript-Dateien. Aber ich sorge dafür, dass sie nicht kaskadierend sind, sondern dass ich weiß, auf welcher Webseite ich welche von diesen JavaScript-Dateien laden muss.

Robert Glaser: Okay, verstehe. Das heißt, als Entwickler kann ich hingehen und meinen JavaScript-Code so strukturieren, wie ich es für richtig halte und faucet kümmert sich darum, diese Abhängigkeiten aufzulösen und zusammenzukleben. So kann man das ja irgendwie sagen beim Bundling. Alles wird nacheinander in eine Datei geschrieben und das hat zur Folge, dass aus meinen 15 Imports, die ich da so habe quer über alle Dateien, alle in einem File landen, der Code dieser Imports. Und der Browser muss dann nur noch dieses eine File laden.

Lucas Dohmen: Genau.

Robert Glaser: Okay, das ist ja erst einmal cool. Aber manchmal habe ich ja den Fall, dass ich gar nicht alles zusammenkleben möchte in eine große Datei. Zum Beispiel, ich erinnere mich an Projekte, da wurde alles in eine Datei geklebt, von jQuery bis zu meinem eigenen Code, also Third Party-Dependencies und dann noch mein Anwendungscode und dann noch Gott weiß was. Da kann ich aber mit faucet weiterhin sagen, ich möchte jQuery zum Beispiel nicht reinbundeln. Aber alle meine 15 Web Components, die ich vielleicht für meinen Tabellenkalkulation oder was auch immer selbst geschrieben habe, die sollen gebundelt werden.

Lucas Dohmen: Genau, das kannst du tun, bei faucet heißt das Externals. Und da sagst du, dieses Modul, das referenziert du zwar in deinem Code, also du sagst irgendwie import $ from 'jquery' – man merkt, Robert ist länger nicht im Geschäft…

Robert Glaser: [lachend] Vorsicht.

Lucas Dohmen: Und dann sage ich einfach faucet Bescheid, auch wenn du das im Code findest, dann steht jQuery einfach global zur Verfügung. Und dann sorgst du einfach in deinem HTML dafür, dass jQuery heruntergeladen wird, einfach als <script src="jquery.js">, dass das irgendwo steht. Und faucet geht einfach davon aus, dass es da ist und ignoriert diese Dependency. Und das ist auch etwas, was ich in vielen Projekten genauso mache. Nicht unbedingt mit jQuery, aber mit irgendwelchen größeren Dependencies, weil ich immer davon ausgehe, dass externe Dependencies einfach einen anderen Update-Zyklus haben als meine eigenen. Das heißt, ich werde meinen eigenen Code wahrscheinlich häufiger updaten, als ich jetzt irgendeine Third Party-Library update, weil die jetzt ja nicht jeden Tag eine neue Version hat. Das heißt, ich mache quasi eine JavaScript-Datei für jede von meinen großen externen Dependencies und einen Bundle von meinen ganzen Dateien und da benutzt ich halt Externals, um dann diese Dateien zu referenzieren.

Robert Glaser: Okay.

Lucas Dohmen: Das wäre jetzt so das, was mir meistens schon ausreicht. Damit verwandt ist das Thema Code-Splitting. Das ist so die Idee, dass man tatsächlich nicht eine Datei ausspuckt sondern mehrere Dateien. Das ist auch etwas, was viele Tools unterstützen, das unterstützt faucet-pipeline derzeit noch nicht. Wir tüfteln daran gerade noch so ein bisschen. Vielleicht kommt das demnächst, das kann ich aber noch nicht versprechen.

Robert Glaser: Wofür brauche ich das?

Lucas Dohmen: Genau, das ist halt die Frage: Wofür brauche ich das? Ein Beispiel für mich wäre jetzt: Du benutzt eine größere externe JavaScript-Library, und du möchtest, dass da erst einmal aller Code, den du gar nicht brauchst, herausgelöscht wird. Dieses Verfahren nennt sich Dead Code-Elimination oder in JavaScript-Parlance heißt das Tree Shaking. Da sage ich zum Beispiel, ich importiere von underscore.js nur fünf Funktionen, dann sollen auch nur fünf Funktionen in meinem Bundle landen. Wenn ich das jetzt so mache mit den Externals, wie wir das eben besprochen haben, dann ist das ja so, dass erst einmal ganz Underscore da ist, auch wenn ich nur fünf Funktionen davon brauche. Und das könnte okay sein, weil ich einfach sage, das ist gecacht und dann ist es mir egal. Oder ich sage, ich möchte tatsächlich quasi ein Custom Build von Underscore erzeugen, der nur die Funktionen enthält, die ich tatsächlich auch brauche. Und dafür wäre Tree Shaking eine ganz gute Option. Dann habe ich am Schluss quasi eine app.js, in der mein Code ist, und eine underscore.js, in der aber nur der Teil von Underscore ist, den ich tatsächlich brauche. Dafür könnte man Tree Shaking beispielsweise gut verwenden. Das ist der Grund, warum das so ein bisschen auf unserem Radar ist, aber wir haben es einfach noch nicht angepasst. Also wir wollen es natürlich auch nicht selber bauen, das passt ja auch nicht zu der Philosophie. Wir wollen nur einen guten Weg finden, wie wir das integrieren in unser Tooling. Und da haben wir noch nicht den super guten Weg gefunden, weswegen wir das erst einmal nach hinten verschoben haben.

Robert Glaser: Okay. Das heißt, ihr könnt alles, was JavaScript-Bundling so erfordert, bis auf dieses Tree Shaking-Thema?

Lucas Dohmen: Nee, Tree Shaking können wir auch. Wir können nur nicht Code-Splitting. Also Tree Shaking machen wir auch.

Robert Glaser: Okay, super. Dann lass uns kurz, du hattest es ja schon einmal angesprochen, zu CSS kommen. Es gibt ja Syntaxen, Sprachen, die CSS ähnlich sind, die aber CSS ausspucken, also transpilieren. Dazu zählt vor allem Sass. Das kennen vielleicht einige Hörerinnen und Hörer. Das könnt ihr auch?

Lucas Dohmen: Genau.

Robert Glaser: Okay. Das heißt, wenn ich mir faucet ins Projekt hole, bekomme ich nativ Unterstützung für Sass, ECMAScript 6, also den aktuellen JavaScript-Standard? Oder muss ich da noch zusätzliche Libraries mit in mein npm-File klemmen?

Lucas Dohmen: Da ist die Philosophie von faucet: Wir stellen uns so ein bisschen gegen den Bibliothekstrend, quasi einfach alles immer von Anfang an zu installieren, was es auf der Welt gibt, sondern wir bieten… Also es gibt einmal faucet-pipeline-core. Das ist quasi die Kernbibliothek, die kann erst einmal gar nichts. Und dann gibt facuet-pipeline-js beispielsweise und das unterstützt dann all diese Dinge, über die wir gesprochen haben, für JavaScript. Denn wenn du in deinem Projekt gar kein JavaScript brauchst, sondern nur CSS, dann brauchst du ja nicht jetzt irgendwie Babel oder Webpack oder sonst etwas zu installieren. Das heißt, wir abstrahieren ja für dich, welche von diesen Bibliotheken wir ausgewählt haben, also das ist kuratiert. Du musst nur sagen, ich brauche JavaScript, dann installierst du zusätzlich faucet-pipeline-js. Und wenn du sagst, ich brauche Sass, dann installierst du faucet-pipeline-sass. Und dann bekommst du alle Dependencies mit ins Projekt hinein, die du dafür brauchst, um diese Sachen zu bauen. Das ist so ein bisschen der Ansatz. Denn auch gerade jetzt, wenn du über TypeScript beispielsweise sprichst: In vielen Projekten haben wir kein TypeScript, aber ein paar schon, es wäre ja jetzt irgendwie verrückt, wenn faucet-pipeline grundsätzlich TypeScript als Dependency hätte. Dann hättest du irgendwie schon ganz schön viel auf der Platte, was du gar nicht brauchst.

Robert Glaser: Einige würden sich das wahrscheinlich wünschen.

Lucas Dohmen: Ja, vielleicht.

Robert Glaser: Vielleicht ist das nach eurer Philosophie einfach kein guter Standard.

Lucas Dohmen: Genau. Also wir versuchen auch, den Dependency-Graph von diesem Tool übersichtlich zu halten und nicht einfach auf Verdacht alle Tools zu installieren. Sondern es gibt quasi so ein Grundset von Pipelines, also Sass, JavaScript. Images, static-Files, die man sich erst einmal grundsätzlich installieren kann, die dann meistens auch noch so ein, zwei Plug-ins anbieten. Da fordern sie dich dann einfach auf, noch ein zusätzliches Plug-in zu installieren, wenn du diese Funktionalität nutzen möchtest. Das ist so ein bisschen die Philosophie dahinter.

Robert Glaser: Okay. Du hast static erwähnt, was versteht ihr unter static? Sind das einfach statische Dateien, die faucet auch behandeln soll, aber eigentlich mehr oder weniger in Ruhe lässt, weil ich vielleicht nicht möchte, dass da irgendetwas prozessiert wird?

Lucas Dohmen: Genau. Also static ist so die allereinfachste von unseren Plug-ins, das kopiert einfach Dateien. Und das erscheint vielleicht ein bisschen komisch, warum muss man das überhaupt tun? Der eine Grund dafür wäre, dass wir einfach irgendwie ein Source-Directory haben, in dem unsere ganzen TypoScript-Dateien sind und unsere Icons. Und jetzt möchten wir quasi einfach einen Schritt haben, der daraus einen public-Folder macht, in dem alle Dateien liegen, die verarbeitet sind und manche davon wurden halt einfach nur kopiert. Also beispielsweise habe ich fertige Font-Dateien, die sind schon in WOFF2 beispielsweise, dann muss ich damit gar nichts mehr tun, die müssen nur kopiert werden. Oder ich habe vielleicht den jQuery-Min Build, der schon fertig ist, als npm-Abhängigkeit, dann kopiere ich den einfach so rüber. Dann muss ich den jetzt nicht noch durch faucet-pipeline-js hindurchschieben, weil ich damit eh nichts tutn möchte. Ich möchte einfach, dass dieses schon minifizierte File einfach kopiert wird. Damit ich das dann als External beispielsweise verwenden kann. Dafür kann ich zum Beispiel faucet-pipeline-static benutzen. Der andere Grund, warum es static gibt, ist das ganze Thema Cache Busting. Das ist so die vierte und letzte Requirement-Säule von faucet-pipeline. Das ist der Grund, warum es das auch gibt. Darüber können wir gerne auch gleich noch sprechen.

Robert Glaser: Das wäre sowieso meine nächste Frage gewesen. Ich lese nämlich auf eurer Seite, ihr könnt JavaScript, TypeScript, Sass, static, alles Mögliche. Aber hier steht noch Fingerprinting und Manifest. Das führt uns wahrscheinlich zum Thema Caches Busting. Möchtest du kurz erklären, was es damit auf sich hat, warum ich das überhaupt in einer Webanwendung brauche? Was die Idee dahinter ist und welche Arbeit ich habe, die mir faucet quasi dabei abnimmt?

Lucas Dohmen: Sehr gerne. Also das Problem, das wir behandeln, ist Caching. Wir haben beispielsweise CSS-Dateien. Und jetzt möchten wir ja dafür sorgen, dass unsere Clients, also die Browser von unseren Benutzern und Benutzerinnen, dass die diese Datei am besten nur einmal herunterladen und erst noch mal neu herunterladen, wenn sie sich tatsächlich verändert hat. Und wie machen wir das jetzt? Wenn wir über Caching reden, gibt es da so verschiedene Kategorien. Beispielsweise könnte man jetzt irgendwie ETag setzen, dann würde der Browser quasi die Ressource anfragen, würde sagen, ich kenne diese Version der Datei, ist das noch die aktuelle? Und dann antwortet der Server, ja, ist noch aktuell, kannst du so benutzen und muss sie dann nicht noch mal schicken. Das geht immer, das kann auch irgendwie ein Nginx oder ein Apache. Aber viel, viel besser wäre es ja, wenn der Browser weiß, okay, diese Datei, die hat sich tatsächlich nicht geändert und deswegen muss ich gar nichts anfragen, sondern ich benutze einfach die gecachte Datei. Und um das zu erreichen…

Robert Glaser: Das heißt, den Netzwerk-Request als solchen auch noch einsparen, der notwendig wäre, um zu fragen, ist Ding hier noch aktuell?

Lucas Dohmen: Exakt. Und das wäre jetzt zum Beispiel so, in meinem HTML steht irgendwie app.js als Referenz, dann lädt er die Datei app.js runter. Es gibt ja so ein max-age beispielsweise. Da könnte ich jetzt sagen, cache das für ein Tag oder cache das für immer. Dann wäre es ja wünschenswert, wenn ich sagen könnte, cache das für immer. Wenn ich das aber jetzt tue und ich habe eine neue Version von app.js, wie bekommt der Browser das jetzt mit? Und genau dafür gibt es Cache Busting. Cache Busting ist jetzt die Idee, dass du hintendran an den Dateinamen noch einen Cache Buster schreibst, das ist einfach Hashwert von dem Inhalt der Datei. Also du nimmst die Datei, hashst die mit SHA oder so etwas, bekommst einen Hashwert und dann heißt dieser Teil halt app-und_dann_irgend_so_eine_Buchstabensuppe.js. Wenn sich die Datei jetzt verändert, dann ändert sich der Hash, das heißt, ich erzeuge eine neue JavaScript-Datei. Das heißt, wenn ich in dem HTML immer die aktuelle JavaScript-Datei referenziere, dann kann ich diese JavaScript-Datei so lange cachen, wie ich will. Denn selbst wenn es eine neue Version gibt, ändert sich der Hashwert und es wird eine neue Datei angefragt. Das ist die Idee vom Cache Busting. Das gilt halt nicht nur für JavaScript, das gilt für alle vier Kategorien, die wir jetzt eben erwähnt haben. Bei einem Font möchte ich auch nur, dass der einmal heruntergeladen wird und auch kein weiterer Request geschickt wird. Gerade Fonts sind halt so ein Thema, die ändern sich so gut wie gar nicht. Also du schickst einmal den Font runter und dann soll der den bitte behalten und du wirst den ja nicht dauernd anpassen. Aber wenn du ihn anpasst, weil du vielleicht einen Bug in deiner Font-Datei entdeckt hast, dann möchtest du natürlich, dass alle Leute diese neue Datei bekommen und dass du nicht erst noch eine Caching-Zeit abwarten musst.

Robert Glaser: Verstehe.

Lucas Dohmen: Und dieses Problem ist tatsächlich auch so ein bisschen das, bei dem ich am Anfang, als ich die erste Version von faucet alleine geschrieben habe, am meisten investiert hatte. Denn das Problem ist gar nicht so einfach, wenn du darüber nachdenkst. Bei JavaScript ist das einfach. Du hast eine JavaScript-Datei, und am Schluss kommt irgendwie eine gehashte JavaScript-Datei heraus und du musst nur die richtige referenzieren. Aber beispielsweise wenn du jetzt einen Font hast oder ein Logo, dann werden die ja meistens in einer CSS-Datei referenziert. Das heißt also, du schiebst irgendwie dein Font und dein Logo durch irgendetwas durch. Da kommt ein Cache Buster heraus. Jetzt muss aber deine CSS-Datei wissen, wie diese Datei heißt, damit sie die korrekt im CSS referenzieren kann.

Robert Glaser: Für mich hört sich das nach einem Haufen Arbeit an.

Lucas Dohmen: Genau.

Robert Glaser: Also faucet kümmert sich darum, alle meine Dateien zu prüfen, zu hashen und umzubenennen. Also nicht umzubenennen, sondern zu kopieren mit dem Hash im Dateinamen hintendran. Aber jetzt müsste ich ja als Entwickler hingehen und sagen oh Gott, hat meine Web Component XY sich geändert, die JavaScript-Datei dazu, ist der Hash noch der gleiche wie früher? Wenn nicht, wie ist er jetzt? Dann müsste ich den Link, den Script-Tag in meinem HTML ja entsprechend auf die neue Datei zeigen lassen.

Lucas Dohmen: Genau.

Robert Glaser: Das klingt nach Schweinearbeit, auf gut deutsch.

Lucas Dohmen: Richtig. Und genau das möchten wir einfach machen und das ist so eine von den Sachen, die faucet halt wirklich quasi auszeichnet als – meiner Meinung nach – eine sehr, sehr einfache Lösung für dieses Problem. Denn was faucet am Schluss macht: Zum Einen sorgt es erst einmal dafür, dass diese Dateien in einer bestimmten Reihenfolge verarbeitet werden, also erst einmal kopiert es dir alle statischen Dateien. Also sowohl die Fonts, die einfach eins zu eins kopiert werden, als auch die Bilder, die vielleicht vorher noch durch irgendeinen Kompresser durchgelaufen sind. All diese Dateien macht zuerst, erzeugt dafür dann jeweils die neue Datei mit diesem Cache Buster hintendran. Und dann in einem zweiten Schritt wird CSS und JavaScript verarbeitet. Und das CSS kann dann schon das Mapping durchführen. Immer wenn man an irgendeiner Stelle jetzt eine URL von irgendeinem Font oder einem Bild haben möchte, kann es einfach nachschauen, wie heißt diese Referenz auf die Datei mit ihrem Cache Buster denn jetzt und sie wird dann automatisch in dem CSS ersetzt. Und im letzten Schritt habe ich dann quasi jetzt alles verarbeitet und dann kann meine Webanwendung auf dieses Mapping auch zugreifen. Und dieses Mapping, das haben wir Manifest genannt. Das Mapping ist einfach eine JSON-Datei: Auf der linken Seite steht der Name, bevor er gehasht wird und auf der rechten Seite steht der Name, nachdem er gehasht wurde. Und dann kannst du in deiner Webanwendung einfach in dieses JSON reinschauen, sagen, ich brauche jetzt die app.css und dann steht in dem JSON drin, wie diese jetzt heißt, dass die jetzt app345.css heißt.

Robert Glaser: Okay, verstehe.

Lucas Dohmen: Und dann musst du dir darüber überhaupt gar keine Gedanken machen.

Robert Glaser: Also wie quasi eine Landkarte?

Lucas Dohmen: Ja.

Robert Glaser: Meine app.js will ich immer app.js nennen in meinem Code, in meiner HTML-Datei oder wo auch immer ich die brauche. Und faucet weiß, wie sie nach der Änderung richtig heißt. Und das steht dann in dieser manifest.json. Und die kann ich auswerten, um mir da die richtigen Dateinamen zu besorgen für die app.js und co.

Lucas Dohmen: Genau, exakt.

Robert Glaser: Okay, das klingt super. Ich muss natürlich immer noch die JSON-Datei in meiner Programmiersprache, in meinem Framework der Wahl öffnen. JSON parsen können ja die meisten Sprachen. Das sollte nicht so ein gigantischer Aufwand sein. Aber habt ihr auch Integration für Frameworks, dass ich das vielleicht überhaupt nicht machen muss und dass sich das quasi unsichtbar integriert, so richtig Rails-mäßig?

Lucas Dohmen: Genau. Also das haben wir, wir haben das für Rails, wir haben das für Spring Boot und wir haben das für Express.js, das sind so die, wo es funktioniert, wo wir auch in Produktion dieses Plug-in benutzen. Das Rails-Plug-in habe ich tatsächlich vor langer, langer Zeit geschrieben. Das sind, glaube ich, zwölf Zeilen Code oder so. Also es ist wirklich nicht viel Arbeit, weil es ja eigentlich nur eine JSON-Datei ausliest und dann das Mapping durchführt. Das heißt, wenn ihr jetzt irgendwie ein Framework habt wie jetzt Phoenix oder so und das gibt es da noch nicht, dann heißt das noch nicht, dass ihr dann faucet nicht benutzen könnt, sondern dann müsst ihr vielleicht ein kleines Plug-in schreiben. Das ist in den meisten Web-Frameworks gar nicht so viel Arbeit, also auch das Express-Plug-in ist relativ klein. Das sind aber schon fertige. Wenn ihr diese Frameworks benutzt, dann ist das Problem schon gelöst, dann müsst ihr eigentlich nichts mehr machen. Wenn ihr jetzt ein anderes Web-Framework benutzt, dann müsst ihr eventuell noch so ein kleines Plug-In schreiben. Aber wie gesagt, wir haben extra JSON gewählt in dieser super einfachen Struktur, weil es halt total einfach ist, dafür dann ein Plug-in zu schreiben.

Robert Glaser: Okay, und wenn ihr das tun solltet, liebe Hörerinnen und Hörer, dann macht doch eine OpenSource-Contribution auf GitHub.

Lucas Dohmen: Auf jeden Fall.

Robert Glaser: Denn wenn der oder die Zweite mal ein Phoenix-Plug-in sucht, dann ist es schon da. Ihr kennt das Prozedere, dafür wäre euch das Team, inklusive Lucas, wahrscheinlich sehr dankbar.

Lucas Dohmen: Auf jeden Fall.

Robert Glaser: Okay. Das heißt, wir haben jetzt so ein bisschen geredet über… Was heißt so ein bisschen, wir sind schon in die Tiefe gegangen zu Fingerprinting und Manifest und damit auch natürlich auch Cache Busting, das will ich ja damit bewerkstelligen können. Da sieht man, finde ich ganz gut, wenn man sich da so langhangelt, was das eigentlich für ein endloser Ast an Tätigkeiten ist, den ich in einer performanten, gut strukturierten Webanwendung ebenso berücksichtigen muss. Und für mich erschließt sich damit natürlich auch der Wert, den so ein Tool wie faucet hat.

Lucas Dohmen: Genau.

Robert Glaser: Gibt es noch andere Sachen, die wir jetzt noch nicht besprochen hatten, die faucet vielleicht auch noch kann, die du wichtig findest für eine gute Webanwendung?

Lucas Dohmen: Ich glaube, eine Sache würde ich noch ergänzen und das ist das File-Watching. Das ist etwas, was ich als jemand, der in vielen Projekten auch Frontend-Arbeit macht, einfach immer vermisse, wenn es nicht da ist. Also ich möchte irgendwie in meinem Editor meine CSS- und JavaScript-Dateien offen haben. Wenn ich die speichere und dann in meinem Browser Reload drücke, dann soll die bitte aktuell sein. Das ist ein Workflow, ohne den kann ich nicht gut arbeiten, denn das ist mir zu träge, dann immer erst noch irgendwie einen Compiler anzuwerfen oder sonst irgendetwas. Ich möchte, dass das automatisch passiert. Deswegen hat faucet das Watching fest eingebaut. Das heißt, man startet faucet mit so einer Watch-Option und dann macht es dasselbe, was es dann für den Produktionsbuild auch machen würde, nur dass es halt jedes Mal neu baut, wenn sich eine Datei verändert. Und dabei ist es auch intelligent. Also wenn ich beispielsweise JavaScript habe und meine JavaScript-Datei besteht aus 120 Dateien, dann weiß faucet, aus welchen 120 Dateien die besteht und nur wenn sich eine von diesen 120 Dateien ändert, dann baut der exakt diese JavaScript-Datei neu und baut nicht einfach alles neu. Und mit einem Watch-Prozess watchen wir alle Arten von Dateien. Also ist das auch sehr CPU-entlastend. Viele haben dann halt irgendwie vier, fünf verschiedene Tools, die alle File-Watching machen. Wir haben tatsächlich einen Prozess, einen Node.js-Prozess, der das gesamte File-Watching macht für alle Arten von Dateien und dann intelligent die Sachen neu baut, die sich verändert haben.

Robert Glaser: Ah, okay. Das heißt, wenn ich meine Webanwendung entwickle, egal mit welcher Programmiersprache, egal mit welchem Framework, dann starte ich einfach parallel diesen Node-Prozess, in dem faucet dann läuft und faucet watcht dann einfach mein Projektverzeichnis. Ich kann vielleicht noch einschränken, bitte schau nur in dem Ordner, weil das andere Java-Dateien sind, die sind für dich eh nicht relevant. Und es baut mir die Sachen so, wie ich sie dann vielleicht auch im Build-Schritt vorm Deployment hätte.

Lucas Dohmen: Genau. Wir können dann tatsächlich auch überlegen, ob wir vielleicht bestimmte Sachen nicht machen. Wenn wir beispielsweise sagen, im Development möchte ich meine JavaScript-Dateien nicht minifizieren, weil das irgendwie hinderlich ist, wenn ich debuggen möchte, dann kann ich das quasi im Development-Mode einfach ausstellen. Dann mache ich das nur im Production-Build. Aber trotzdem kommt quasi auch eine Manifest-Datei heraus. Also selbst wenn ich mich dann entscheide – was ich den meisten Leuten empfehle – beim Development kein Fingerprinting anzuschalten, weil ich da normalerweise meine CSS-Dateien sowieso nicht cache, das mache ich irgendwie dann ja doch eher in Produktion, erzeugt es trotzdem einfach ein Manifest, in dem auf der linken Seite und der rechten Seite quasi dasselbe steht, weil sich die Datei ja nicht umbenennt. Aber ich habe dann einfach in meinem HTML-Code oder meinem Templating-Code trotzdem immer einfach dieselbe Anweisung drin und es ist egal, ob ich jetzt Cache Busting anhabe oder nicht. Es wird halt einfach gemappt zu der korrekten Datei.

Robert Glaser: Wobei man darüber natürlich auch trefflich diskutieren kann, Produktions- und Development-Gleichheit oder eben nicht.

Lucas Dohmen: Das stimmt, ja.

Robert Glaser: Ich glaube, wenn ich mich richtig erinnere, Rails hatte das früher. Die haben ja schon ewig lange eine Asset-Pipeline. Die hatten das früher so, dass bei der lokalen Entwicklung die statischen Dateien eben nicht gefingerprintet wurden und auf Production eben schon. Das hat halt zu dem bekannten Problem geführt, dass man lokal einfach Dinge nicht entdeckt hat und auf Production war das Verhalten nennenswert anders als lokal. Und dann sind eben Sachen auf Production passiert, die man lokal nicht kannte.

Lucas Dohmen: Genau.

Robert Glaser: Und ich glaube, aus diesen Lehren sind sie auch dazu gewechselt, das jetzt auf Developmemt und Production einfach gleich zu tun. Denn es stört ja im Developmemt auch keinen.

Lucas Dohmen: Wir ermöglichen das auch, das ist deine Wahl, ob du das anmachen möchtest oder nicht, kannst du selbst entscheiden. Es ist beides offen.

Robert Glaser: Okay. Aber eine Minifizierung von JavaScript will ich lokal wahrscheinlich wirklich nicht, weil das das Debuggen elend schwer macht.

Lucas Dohmen: Also manche Leute machen das auch lokal, weil sie sagen, ich habe hier Source Maps – Source Maps ist so ein Format, in dem sagt man quasi, dieses Stück von dem Endresultat mappt auf diese Original-Datei. Das ist auch etwas, was wir unterstützen. Also wir erzeugen auch Source Maps für dich, wenn du das möchtest. Alle modernen Browser-Tools wie Firefox, Chrome, Safari verstehen diese Source Maps können dann tatsächlich diese nicht minifizierte Datei referenzieren. Aber ich sehe das einfach ein bisschen als unnötigen Overhead, das im Development zu machen. Also wenn der Minifizierer nicht einen signifikanten Bug hat, dann ändert der ja nichts an der Semantik von deinem Code und dann sollte es auch funktionieren. Aber klar, manche Leute sagen, wenn ich minifiziere, dann muss ich auch lokal minifizieren, denn falls der jetzt irgendetwas falsch macht, dann möchte ich das auch lokal direkt mitbekommen. Aber ich hatte noch nie ein Problem mit dem Minifizierer, den wir mit anbieten. Deswegen sehe ich diese Notwendigkeit nicht unbedingt, das lokal auch zu tun.

Robert Glaser: Du hast dir das Positive erhalten. Ich bin verbittert über die Jahre. Ich rechne immer in jeder Software mit signifikanten Bugs, egal in welcher Version sie vorliegt.

Lucas Dohmen: Das ist natürlich wahr, ja.

Robert Glaser: Eine Sache habe ich mir noch aufgeschrieben. Du hast ganz am Anfang erwähnt, da haben wir so ein bisschen in CSS, was faucet ja auch macht, auch mit Sass oder ohne, wie ich es halt möchte, über Vendor-spezifische Properties gesprochen. Vielleicht für neue CSS-Funktionen, die es noch nicht in den Standard geschafft haben, wo Browser-Hersteller dann immer ihr Browser- oder Hersteller-Präfixe vorgehangen haben. Wie geht da denn faucet eigentlich vor? Also woher weiß denn faucet, nur weil ich vielleicht die relativ neue Scroll-Behavior-Property in CSS benutze, dass es die zu präfixen hat in dem CSS, das hinten herausfällt?

Lucas Dohmen: Das haben wir natürlich auch nicht selber gebaut. Das entspricht ja auch unsere Philosophie, das nicht zu tun.

Robert Glaser: Was habt ihr denn selber gebaut?

Lucas Dohmen: Genau, es ist eigentlich gar nichts mehr übrig, ne? Da benutzen wir das Tool Autoprefixer. Das ist, glaube ich, auch das gängige Tool dafür. Das verwendet eine sogenannte Browserslist. Das ist eine Datei, darein schreibst du, folgende Browser möchte ich unterstützen. Und dann steht da halt drin IE 11, Chrome neuste Version und so weiter.

Robert Glaser: Ah, okay.

Lucas Dohmen: Und dann weiß Autoprefixer, für welchen dieser Browser es welches Prefix setzen muss und macht das dann automatisch. Der Riesenvorteil daran ist, wenn dann halt irgendwann der glorreiche Tag kommt, an dem du IE 11-Support abschalten darfst, weil das der Product Owner oder die Product Ownerin beschlossen hat, dann brauchst du nichts zu tun an deinem Code, du musst eigentlich nur deine Browserslist-Datei anpassen, einmal compile drücken und die Sachen sind halt weg, die du nicht mehr brauchst.

Robert Glaser: Ah, okay. Also Browserslist muss auch in die Shownotes, das merken wir uns. Da kann ich, glaube ich, auch sehen, wie die Syntax ist, wie ich das eben beschreiben kann, welche Browser ich supporten möchte.

Lucas Dohmen: Genau. Das finde ich ein sehr, sehr elegantes Format. Genau.

Robert Glaser: Super! Wir sehen, wir sind jetzt bei 50 Minuten und könnten wahrscheinlich noch locker drei Stunden über die Best Practices moderner Webend und speziell Frontend-Entwicklung reden. Aber wir sehen ja schön, dass faucet viel davon so einfach macht. Eine letzte Frage von mir zum Schluss: Wie kommen die Leute, die Hörerinnen und Hörer, die sich jetzt vielleicht dafür interessieren, dass mal in ihrem eigenen Projekt ausprobieren oder sogar direkt nutzen möchten, dahin? Wie kommen sie dahin, was müssen sie tun? Wie installieren sie das?

Lucas Dohmen: Also ich finde ja immer so ein bisschen Code durch zu diskutieren in einem Audioformat so mittelcool. Deswegen würde ich euch einfach empfehlen, auf faucet-pipeline.org zu gehen. Da seht ihr einen ganz kleinen Code-Snippet. Das ist eine kleine Konfigurationsdatei. Wir stecken sehr viel Mühe hinein, dass die möglichst einfach ist, möglichst einfach zu verstehen ist und in den meisten Fällen bist du irgendwie mit ein paar Zeilen Code dabei, die du auch alle verstehst und die du nicht irgendwie bei Stack Overflow zusammengoogeln musst. Die brauchen wir und dann installieren wir uns noch ein paar npm-Pakete, je nachdem, was wir brauchen. Beispielsweise möchten wir jetzt faucet-pipeline-js und faucet-pipeline-sass und faucet-pipeline-static haben, dann installieren wir diese drei Pakete. Und danach müssen wir eigentlich nur das Kommando faucet ausführen und wir sind fertig. Das ist quasi der gesamte Workflow und wir abstrahieren diese ganzen Tools, die du dafür braucht, dann weg und du musst eigentlich nur das Tool starten. Das ist der Anspruch, den wir haben.

Robert Glaser: Und wenn ich mich jetzt beteiligen möchte an der Entwicklung, das Ganze ist ja OpenSource, oder ein Problem finde – wobei natürlich eure Software keine signifikanten Bugs enthält [lacht] – dann finde ich die Repositories wahrscheinlich auch auf GitHub, oder?

Lucas Dohmen: Genau. Also alles davon ist in einer Organisation, die ist auch referenziert von der Webseite, wir packen die natürlich auch in die Shownotes, da findet ihr allen Code dazu. Wir freuen uns über jede Art von Kontribution, ob jetzt Bug-Tickets, einfach nur ein “Danke, cool, das funktioniert in meinem Projekt”, das ist auch nett, das kann man auch als Issue einfach anlegen, dann sagen wir “Danke” und schließen das einfach. Oder ihr möchtet vielleicht Code hinzufügen, weil ihr sagt, es fehlt faucet-pipeline-elm, weil Elm die beste Programmiersprache der Welt ist. Dann freuen wir uns, wenn ihr ein Plug-in dafür schreibt. Also es ist absichtlich erweiterbar gebaut. Das heißt, wenn ihr tatsächlich irgendwie einen Use Case habt, der von einem existierenden Plug-in nicht abgedeckt ist, dann könnt ihr sogar ein neues Plug-in schreiben. Wir haben auch eine Anleitung, wie man Plug-ins schreibt. Wir freuen uns da über jede Art von Kontribution, einfach Bescheid sagen, was ihr so braucht. Wenn ihr Fragen habt, öffnet da einfach ein Issue und wir versuchen, euch zu helfen.

Robert Glaser: Okay super, ich bin natürlich faucet-Fan. Ich bin hier zwar Moderator, aber ich bin leider nicht neutral, was das Thema faucet angeht, weil ich es auch selbst in vielen Projekten benutzt habe und immer noch aktiv benutze. Lucas, wir haben das ja mittlerweile auch… Das ist nichts Neues. Wir benutzen das wirklich auch in zahllosen Kundenprojekten. Da können wir jetzt nicht immer Namen nennen, aber da ist von der großen Versicherung bis zum Handelskonzern alles dabei, Start-ups haben das. Da können die Leute sich wahrscheinlich relativ sicher sein, dass das kein Experimentierfeld ist, oder?

Lucas Dohmen: Auf jeden Fall. Also wir benutzen das mittlerweile in einem Großteil der neuen Projekte, die diese Probleme haben und das angehen möchten, da benutzen wir faucet. Ich benutze das eigentlich in jedem Kundenprojekt irgendwo. Innoq.com benutzt das beispielsweise. Fejo, der Kunde, für den ich das damals gebaut habe, der benutzt das auch immer noch in Produktion. Ich würde sagen, es ist Production Grade.

Robert Glaser: Zu viel, um es aufzuzählen.

Lucas Dohmen: Genau, ja.

Robert Glaser: Super, jetzt könnten wir einen Cut machen machen und die Leute entlassen, weil wir ja eigentlich auch schon 55 Minuten jetzt hier verplappert haben. Aber ich bin gerade so interessiert an dieser einen brennenden Frage, die so stetig im Hintergrund schwelt und wozu wir wahrscheinlich auch noch Fragen von den Hörerinnen und Hörern bekommen würden. Warum kann ich denn nicht den Industriestandard Webpack benutzen, um meine ganzen Sachen zu bundeln und zu präprozessieren und was faucet eben auch alles kann? Also das wirft uns ein bisschen zurück an den Anfang, aber vielleicht können wir damit ja auch abschließen, denn ihr habt faucet ja zu einem Zeitpunkt gebaut, als es Webpack schon gab, und hattet dann wahrscheinlich auch Gründe, das zu tun, obwohl es Webpack gab, oder?

Lucas Dohmen: Ja, auf jeden Fall. Also ich habe das Projekt damals alleine angefangen. In der erste Version war eigentlich nur ein schönes Interface darum herum, um Webpack. Die erste Version basierte tatsächlich auf Webpack. Und wir haben das auch genutzt, also das war halt bei Fejo, da haben wir das in Produktion gehabt, das hat auch funktioniert. Der Hauptgrund damals war halt das ganze Thema Cache Busting- Weil das halt in Webpack nicht mit dabei ist, sollte das halt einfach mit gelöst werden. Und das habe ich quasi darum herum gebaut. Also ich habe unten drunter Webpack verwendet, und dann halt Cache Busting, File Watching und so weiter als ein Interface angeboten, was dann halt auch Sass beispielsweise gewatcht hat und so weiter. Und Webpack hat uns da erst einmal gute Dienste erwiesen, hat dann aber leider in der Produktion ein, zwei Probleme gehabt. Denn als dann mal eine Exception flog und wir herausfinden wollten, was los war, haben wir festgestellt, dass der Code, den Webpack am Schluss ausspuckt, sehr schwer zu debuggen ist, auch wenn man beispielsweise so etwas wie Source Maps verwendet. Durch die Art und Weise, wie es den Output-Code strukturiert hat, war es sehr, sehr schwer das zu debuggen. Und dann ist damals ein Kollege dazugekommen – der nur unter dem Namen FND bekannt ist – der hat mich damals in dem Projekt unterstützt und der hat gesagt, hey, lass uns mal ausprobieren, ob das mit Rollup besser ist, ich habe viel Gutes von Rollup gehört. Und dann haben wir tatsächlich die nächste Version von faucet gebaut und die basierte auf Rollup statt Webpack. Und mit Rollup haben wir tatsächlich sehr, sehr gute Erfahrungen gemacht. Aber schlussendlich ist das auch so ein bisschen der Grund für diese Philosophie von faucet, dass wir sagen: Hey, es gibt irgendwie coole Tools da draußen. Aber hast du Bock, immer zu schauen, welches davon das Neuste ist? Wir schauen uns das an, wir probieren das in verschiedenen Projekten aus. Und wir suchen halt Lösungen heraus, die sich in Projekten auch schon als stabil erwiesen haben. Und aktuell würden dir halt empfehlen, nimm lieber Rollup als Webpack, nicht weil Webpack doof ist, sondern einfach weil wir merken, dass es unsere Probleme besser löst. Und wenn dann irgendwann das nächste tolle Tool kommt, dann werden wir das austauschen. Und das Tolle daran ist, dass du als jemand, der faucet benutzt, dafür nichts ändern musst, du musst eigentlich nur faucet updaten. Denn deine Konfiguration geht nicht auf diese speziellen Tools ein. Deine Konfiguration sagt nicht, dass du Rollup benutzt, das steht darin nicht, sondern wir machen das, und wir übersetzen das dann in dieses Tool für dich.

Robert Glaser: Okay.

Lucas Dohmen: Und genauso: Aktuell diskutieren wir, ob wir Babel noch haben wollen oder ob wir Sucrase beispielsweise, das ist halt jetzt ein moderneres Tool, verwenden wollen. Wenn wir uns dafür entscheiden, das zu tun, musst du als faucet-User nichts daran ändern, wir ändern das unter der Haube und du updatest faucet und du bekommst die neuere Version von dem neueren Tool. Und gerade das Thema Cache Busting ist halt etwas, das eigentlich so ein bisschen holistisch angegangen werden muss. Also du musst das halt irgendwie für CSS lösen, für JavaScript lösen, für Bilder lösen und so weiter. Und da habe ich damals auf jeden Fall keine gute Lösung gefunden und da sehe ich auch heute immer noch kein Tool, das dann dieses einfache Mapping am Schluss rauswirft und dir einfach ein Paket bietet, was Bild-Optimierung macht, CSS-Optimierung, JavaScript-Optimierung, alles aus einer Hand, alles vorkuratiert. Und das ist der Grund, warum es das Projekt weiterhin gibt.

Robert Glaser: Okay, super, dann sind wir jetzt kurz vor einer Stunde, das passt super in eine Trainingseinheit oder so etwas. Ich hoffe, wir sind nicht zu lange geworden. Lucas, dann lass uns doch hier einen Cut machen. Und der Aufruf gilt natürlich an alle Hörerinnen und Hörer: Checkt das mal aus, schaut es euch mal an und probiert es einfach mal aus. Wir sind natürlich nicht neutral, aber gerade ich kann es sehr empfehlen.

Lucas Dohmen: Danke dir.

Robert Glaser: Gut, Lucas, dann danke ich dir für die Beantwortung meiner Fragen und das nette Gespräch und wir sehen uns vielleicht noch einmal in einem Aufeinandertreffen hier wieder, oder?

Lucas Dohmen: Bestimmt. Die Moderatoren werden sich wiedertreffen.

Robert Glaser: Okay. Dann mach es gut und wir sagen allen Tschüss, macht es gut.

Lucas Dohmen: Genau, ciao.

Robert Glaser: Tschüss.