Danny Fischer

Web & Product Engineer

I'm a Software Engineer from Hamburg who worked with brands like Volkswagen, Audi, Hapag-Lloyd, comdirect and Unitymedia to realize ambitious projects.

About me
  1. Critical CSS and Server-side Applications

  2. Tutorial: Server Setup mit nginx, HHVM und WordPress

  3. Hamburg, 25. Januar 2014

    Städtetour bei -12°C? Klar!

Critical CSS and Server-side Applications

A Workflow for non-static Website Performance.

The Critical Rendering Path: You’ve probably heard about it if you’re living in the front-end world. Against the do not mix HTML and CSS philosophy, it’s highly effective to put the render-critical parts of your stylesheet directly into the delivered HTML response.

But this article is not a pro and cons list of this technique, rather a solution for one fundamental problem of the available tools: They are supposed to be used with static, highly predictable sites where deliverable HTML (generated by Jekyll or Middleman for example) files lying around, waiting to be analyzed.

Usually we build applications which are not static, but dynamic at a larger scale with varying layouts and templates, though. To extract the render critical CSS in those cases, we need to send actual HTTP Requests to evaluate what is critical on the pages in question. Render Critical CSS Workflow / Overview

The Solution

We need three things in order to deliver the critical CSS based on the requested page:

  1. A build task which generates the critical CSS.
  2. Logic to find the page-matching critical CSS file.
  3. Output the critical CSS inline in the head section.

I skip the details on how your development environment might look like and go straight to the important parts, because the workflow is adaptable to almost any technology-stack. In my example, I’m using a WordPress instance served by Vagrant which resembles the later production environment.

⚠️

This article was published in 2015, some information may be outdated. Double-check the following instructions with current best practices in mind.

The Build Task in gulp.js

Let’s take a look on how we generate the critical CSS.

We create a JavaScript array with an object for each page we want later to be generated, providing the localhost (or alias like in my sample code) url as well as a unique name.

In the gulp task we use JavaScript’s map() method on the previously defined array to iterate over all objects. In the function’s body we use the Penthouse Node module to generate the actual critical CSS by supplying the main CSS file and page data — Penthouse uses PhantomJS behind the scenes, a headless WebKit browser. The returned data is written to a file matching the objects name value.

When finished developing, run gulp criticalCSS to generate the CSS files for your production environment.

1var penthouse = require('penthouse');
2...
3var criticalPages = [{
4 url: 'http://demo.local/',
5 name: 'index'
6}, {
7 url: 'http://demo.local/projects',
8 name: 'projects'
9}, {
10 url: 'http://demo.local/about',
11 name: 'about'
12}];
13
14gulp.task('criticalCSS', function() {
15 criticalPages.map(function(page) {
16 penthouse({
17 url: page.url,
18 css: 'dist/css/main.css',
19 width: 1280,
20 height: 1280
21 }, function(err, data) {
22 require('fs').writeFile('dist/css/critical/' + page.name + '.css', data);
23 });
24 });
25});

The Function Logic

Now the defined directory contains our critical CSS files we can work with. On the Back-End side of our application we need some sort of logic to define which of the available files need to be inlined in the requested page. This part depends heavily on your application, so I go ahead and do WordPress and PHP things for now.

1function criticalCSS()
2{
3 $dir = get_template_directory_uri().'/dist/css/critical/';
4 $page = null;
5
6 if (is_page('about')) {
7 $page = file_get_contents($dir.'about.css');
8 }
9
10 elseif (is_page('projects')) {
11 $page = file_get_contents($dir.'projects.css');
12 }
13
14 else {
15 $page = file_get_contents($dir.'index.css');
16 }
17
18 $output = $page;
19
20 printf('<style>%s</style>', $output);
21}

The example above is heavily simplified for readability reasons, but you get the point. We check which page (layout, type, ) is requested and return the corresponding stylesheet.

Inline and asynchronous load of CSS

Finally, we got the critical CSS files and the logic to know what we need to inline on a requested page. Time to inline the critical CSS and set up everything to load the big evil main CSS file asynchronously via JavaScript. Again, that part depends on your app, I assume a template called base or head.

1<head>
2 ...
3
4 <?php criticalCSS(); ?>
5 // function call to inline the critical CSS
6
7 <script>
8 loadCSS( ... ){ ... } // include loadCSS here...
9 loadCSS("PATH/TO/main.css"); // load main.css async
10 </script>
11 <noscript>
12 <link href="PATH/TO/main.css" rel="stylesheet" />
13 </noscript>
14 ...
15</head>

The criticalCSS() function call handles all the things needed in order to output the complete <style>...</style> tag. The included loadCSS function handles the asynchronous load and prevents the render blocking, when called with the main CSS file.


But there is one trade-off to this method: We deliver the extracted critical CSS twice, in the HTML response as well as in the full CSS file which is asynchronously loaded through JavaScript. Depending on your sites structure and heaviness this caveat is more or less wasting a couple of bytes.

I think this downside is worth the initial render-improvement, especially if your main CSS file is large. The performance gain is exponential to the size of the main CSS file.


There are many additional steps someone can do to improve the performance of a site even further, I point to some things which can be considered.

Further Reading & Additional Resources

Enhance.js — A boilerplate which contains many things for progressive enhancement.

Server Setup with nginx, HHVM and WordPress — How to deliver WordPress sites in an efficient and fast way, written by me.

Need for Speed 2 — Summary of many details and techniques regarding performance.

Questions, Comments or something else? Hit me up on Twitter.

Tutorial: Server Setup mit nginx, HHVM und WordPress

Speed up all PHP things!

Wer PHP-basierte Webseiten ausliefern möchte, hat mittlerweile eine Menge Möglichkeiten, viele werden den Wechsel von Apache zu nginx in Kombination mit PHP-FPM bereits hinter sich haben, welcher bereits einen ansehnlichen Performance-Vorteil gebracht hat.

Durch den Einsatz von HHVM und dessen JIT-Compiler (vs. konventionellem PHP Interpreter) lässt sich im Zusammenspiel mit nginx ein weiterer großer Schritt in Sachen Performance machen. Ein netter Nebeneffekt ist die Tatsache, dass sich auch starkfrequentierte Anwendungen auf vergleichsweise günstiger Hardware betreiben lassen.

Wie man solch einen Server zusammenbaut, gibt es im nachfolgendem Tutorial, kurz und bündig samt beispielhafter WordPress Instanz. Das ganze passiert bei DigitalOcean auf einer Ubuntu 14.04 LTS Maschine.

Vorbereitung

Nach dem Hochfahren einer neuen Maschine sorgt man erst einmal routinemäßig dafür, dass das System und Abhängigkeiten auf dem neusten Stand sind.

1$ apt-get update && apt-get upgrade
2$ apt-get dist-upgrade
3$ apt-get autoremove

Jetzt legt man einen neuen Benutzer an und setzten das Passwort um die späteren Aktionen nicht mit dem Root-Benutzer auszuführen zu müssen. Alternativ zum Passwort kann hier auch mit SSH Keys gearbeitet werden.

1$ adduser demo

Anschließend erteilen wir dem erstellten Benutzer sudo-Rechte.

1$ visudo
1# User privilege specification
2root ALL=(ALL:ALL) ALL
3demo ALL=(ALL:ALL) ALL

Aus Sicherheitsgründen ist es in diesem Zuge ratsam das Anmelden des Root-Benutzers zu verbieten und den SSH Port zu ändern. Finden und ersetzen.

1$ nano /etc/ssh/sshd_config
1Port 1234 PermitRootLogin no
1$ service ssh restart

Ein guter Zeitpunkt das Verzeichnis anzulegen, aus dem später die Webseite ausgeliefert werden soll und der Ordnerstruktur die korrekten Besitzrechte zu erteilen.

1$ mkdir -p /var/www/demo.local
2$ chown -R demo /var/www

Nun kann man sich abmelden und mit dem neuem Benutzer erneut via SSH einloggen.

1ssh -p 1234
2demo@domain.local

nginx

Die Installation von nginx folgt jetzt. Da HHVM Änderungen an der Konfiguration von nginx automatisch vornehmen kann, wird HHVM erst anschließend installiert. Es wird empfohlen den Mainline-Branch (heißt development, etwas verwirrend) zu nutzen…

In NGINX nomenclature, “stable” means that no new features are added (the feature set is stable). Only major bugfixes are committed to that version. In general, you should deploy the NGINX mainline branch at all times.

…dafür fügt man entsprechendes Repository dem Paketmanager hinzu.

1$ sudo apt-add-repository ppa:nginx/development
2$ sudo apt-get update
3$ sudo apt-get install nginx
4$ sudo service nginx start

HHVM

Kommen wir endlich zu HHVM. Im HVVM GitHub Repository finden sich zahlreiche Prebuilt Packages, auch für Ubuntu 14.04, so brauchen wir es nicht selbst kompilieren und sind ready to roll, nachdem die Paketquelle hinzugefügt wurde.

1$ wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add - echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list
2$ sudo apt-get update
3$ sudo apt-get install hhvm

Um HHVM mit nginx nutzen zu können muss die mitgelieferte FastCGI Installation ausgeführt werden, welche auch die angesprochenen Änderungen an nginx vornimmt und die Schnittstelle zu nginx darstellt.

1$ sudo /usr/share/hhvm/install_fastcgi.sh

Man schaltet Server zwar nicht so oft ab, aber um HHVM nicht manuell nach jedem Systemstart ausführen zu müssen, werfen wir HHVM in den Autostart von Ubuntu.

1$ sudo update-rc.d hhvm defaults

Datenbank: MariaDB

Als Datenbankserver kommt MariaDB zum Einsatz, für die korrekte Version ist es auch hier nötig die Repository manuell hinzuzufügen.

1$ sudo apt-get install software-properties-common
2$ sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
3$ sudo add-apt-repository 'deb http://ams2.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu trusty main'
4$ sudo apt-get update
5$ sudo apt-get install mariadb-server

Nachdem MariaDB installiert ist, wird noch für etwas mehr Sicherheit gesorgt. Beim Ausführen des nächsten Befehls werden wird man aufgefordert das MySQL Root Passwort zu ändern, welches zuvor gesetzt wurde, diese wird mit Nein beantwortet, die restlichen Abfragen werden mit Ja abgearbeitet.

1$ mysql_secure_installation

Fertig? Dann ist alles bereit eine neue Datenbank anzulegen, hierfür begibt man sich in die SQL Shell und tut genau dies. Vergebenes Passwort für den Root-Benutzer des Datenbankservers bereit halten.

1$ mysql -u root -p
1MariaDB [(none)] CREATE DATABASE demo; MariaDB [(none)] exit

WordPress & Konfiguration

Zu guter Letzt brauchen man natürlich noch WordPress an sich, die Installation ist relativ einfach und mit wenigen Anweisungen ausgeführt, ohne einen SFTP Client zu starten.

1$ cd /var/www/demo.local
2$ wget http://de.wordpress.org/latest-de_DE.tar.gz
3$ tar -xvzf latest-de_DE.tar.gz
4$ mv wordpress/* .
5$ rm -rf wordpress
6$ rm -rf latest-de_DE.tar.gz

Die WordPress Installation wird wie gewohnt im Browser fertiggestellt.

Nun müssen noch ein paar Anpassungen an der Konfiguration von nginx vornehmen, damit die Sachen so ausgeliefert werden, wie sie sollen.

1$ nano /etc/nginx/nginx.conf

Die folgenden Zeilen sind standardmäßig auskommentiert, die Option server_tokens versteckt bei Fehlermeldungen des Servers die verwendete nginx-Version (Sicherheit und so) und da wir die gzip Kompression unbedingt verwenden möchten, ändern wir dies ebenfalls. Sofern Grafiken im SVG Format eingebunden werden sollen, fügt man zusätzlich image/svg+xml den gzip_types hinzu.

1server_tokens off; gzip_vary on; gzip_proxied any; gzip_comp_level 6;
2gzip_buffers 16 8k;
3gzip_http_version 1.1;
4gzip_types … image/svg+xml;

Im letzten Schritt der Konfiguration von nginx geht es an den Server-Block, welcher dafür verantwortlich ist, HTTP Anfragen entgegenzunehmen und letztendlich die Antwort zur gesendeten Anfrage an den Client zu senden. nginx liest hierzu Konfigurationsdateien ein die dem Schema /etc/nginx/conf.d/*.conf und /etc/nginx/sites-enabled/* entsprechen, dies ist in der nginx.conf einstellbar. Der Einfachheit halber wird der bereits vorgegebenen Server-Block bearbeitet.

1$ nano /etc/nginx/sites-enabled/default

Auch hier finden sich wieder zahlreich auskommentierte Anweisungen, die nicht benötigen werden, der Übersicht halber kann man nicht verwendete Server-Blöcke löschen. Am Ende sollte die Konfiguration wie folgt aussehen.

1server {
2 listen 80;
3 server_name demo.local;
4 root /var/www/demo.local;
5
6 index index.php index.html;
7
8 include hhvm.conf;
9
10 location / {
11 try_files $uri $uri/ /index.php?$args;
12 }
13
14 location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff2|woff|ttf|svg|otf)$ {
15 expires 30d;
16 add_header Pragma public;
17 add_header Cache-Control "public";
18 }
19
20}

Static durch Caching

Bonuspunkte gibt es für das Caching von dynamischen Anfragen, insbesondere bei WordPress lässt sich hier die Response Time verringern, in dem bei bereits im Cache liegende Seiten direkt an den Client gesendet werden, statt die Anfrage erst über HHVM und Datenbank zu schicken.

Die Auswahl an Möglichkeiten für die Umsetzung sind mehr als zahlreich, neben dem FastCGI-Cache von nginx gibt es – natürlich – diverse WordPress Plugins.

Mit Cachify lässt sich relativ einfach das gewünschte Ziel erreichen, nach der Installation und Wahl der Caching-Methode ergänzt man den zuvor genannten Server-Block um entsprechende Anweisungen und ist damit eigentlich schon fertig.

Ich bin derzeit noch am Experimentieren welche Konfiguration die beste Performance bringt, doch dabei geht es um die letzten Millisekunden. Grundsätzlich kann ich als solide Basis das Cachify Plugin von Sergej empfehlen, welches im Gegensatz zu anderen Plugin-Lösungen ohne großen Overhead daherkommt und sich auf das Wichtigste konzentriert, dies kann man leider nicht von vielen Plugins behaupten. An dieser Stelle noch mal ein Dank an Sergej für die großartige Arbeit in der WordPress Community.

Firewall

Als abschließende Übung machen wir den Server noch etwas sicherer, in dem wir die bei Ubuntu mitgelieferte Firewall aktivieren.

1$ sudo ufw allow 1234
2$ sudo ufw allow 80
3$ sudo ufw allow 443
4$ sudo ufw enable

Der Server antwortet nun nur auf Anfragen auf korrespondierenden Ports: dem benutzerdefiniertem SSH Port (1234), HTTP (80) und HTTPS (443).

Fertig.

Updates in eigener Sache

Plattformen, Hosting, Deployment

Heute gibt es mal wieder ein kleines Update hier in eigener Sache, da ich in den letzten Monaten einfach eine Menge zu tun hatte und zu nichts kam was die Schreiberei angeht und auch niemanden mit Zeug langweilen wollte, welcher niemanden interessiert. Egal, nachfolgend einige Dinge die passiert sind.

WordPress, Jekyll, Middleman?

Wer eine Webseite betreibt, kennt diese Grundsatzfrage die einem von Zeit zu Zeit in den Sinn kommt: Welche Plattform will ich eigentlich nutzen und ist die aktuelle die passendste? Nicht anders war es auch als ich anfing dieser Seite ein Facelift zu verpassen.

Ganz oben auf meiner Liste standen die Static Site Generators, namentlich Jekyll und dessen Ruby on Rails-artiger Bruder Middleman, in die man Markdown und ‘HTML+CSS-Backformen’ wirft und sich eine statische HTML-Seite backen lässt, die man anschließend günstig auf Amazon S3 oder kostenlos auf GitHub Pages hosten kann.

Jedoch entschied ich mich gegen das verlockend klingende Angebot den Overhead den WordPress mit sich bringt abzuwerfen und wollte stattdessen meinen bisherigen Stack optimieren, um so eine ähnliche Performance zu erreichen wie die statischen Kollegen. Auch wollte ich nicht auf diverse WordPress Funktionen verzichten die man eben seit Jahren gewohnt ist. An dieser Stelle ein Verweis auf das wohl beste WordPress Plugin: Advanced Custom Fields.

Development & Deployment

Wo ich schon einmal dabei war hinter den Kulissen umzubauen habe ich auch gleich meinen bisherigen Workflow etwas angepasst und wechselte z.B. von Grunt zu gulp.js und tauschte aufgeblasene Icon-Fonts durch ein SVG Sprite aus, welches von gulp-svg-sprites aus einzelnen SVG-Icons zusammengebaut wird. Wie üblich gibt es noch zahlreiche andere Änderungen (Hallo Refactoring und Optimierung) die aus Erfahrungswerten resultieren, aber damit könnte / werde ich denk ich ein anderes Mal einen kompletten Artikel füllen. Also weiter im Text.

Weil “Daten via SFTP vom Computer auf den Server ziehen” dank Git und massig Deployment-Lösungen nicht mehr angebracht ist, hab ich Capistrano in meinen Workflow integriert, welches den wünschenswerten “One Command Deploy” bringt, heißt: Commits zu GitHub pushen, cap production deploy und binnen Sekunden sind die Änderungen live. Für Notfälle gibt es auch noch die Option eines Rollback zur vorherigen Version.

Da ich sowieso vor hatte meine Host Europe vServer nach und nach zu DigitalOcean umzuziehen konnte ich so direkt einmal HHVM mit nginx aufsetzen und es im Production-Einsatz testen. Der Performance-Gewinn ist wirklich erheblich, ohne jetzt Zahlen und Statistiken auspacken zu wollen, die man im Web zu genüge findet. Das kombiniert mit Caching ist wohl die aktuell schnellste Technik, WordPress und generell PHP-basierte Anwendungen auszuliefern.

+ About Seite

Was ist schwieriger als eine Seite über die eigene Person zu bauen und mit Texten über sich selbst zu versehen? Richtig, eine Seite über sich selbst zu bauen. Zumindest war das mein Empfinden, als ich nach Ewigkeiten fertig war eine About-Page zusammenzuwürfeln, welche meine Tätigkeiten grob abbildet.

+ Fotos (Kategorie)

Eine weitere Änderung erfuhr die Foto Kategorie, welche bisher lediglich die Beiträge einschloss, welche in entsprechender Kategorie lagen. Unvorteilhaft für meine Anforderungen.

Problem: Ich schreibe z.B. ein Review zu irgendetwas und streue dort Fotos mit ein, aber diese werden nie in der Foto-Kategorie gelistet, da es sich eben um kein reinen Foto-Beitrag handelt und ich nur ungern die Kategorie mit Reviews belege. (Stay on Topic!)

Lösung: Attachments (ein WordPress Post Type) mit Kategorien versehen und diese in den WP Query der Archivseite einschließen. Dann noch ein passenderes Layout dazu entwerfen und fertig ist die Foto-Seite.

So viel für den Moment, ich habe vermutlich zig Sachen vergessen zu erwähnen, wollte diese Sache aber endlich abschließen und es gibt ja immer noch die Möglichkeit, weitere Beiträge zu schreiben. In diesem Sinne.

Hamburg, 25. Januar 2014

Städtetour bei -12°C? Klar!

Was tut man, wenn man zum ersten Mal so richtig in Hamburg ist, in meinem Fall “wohnt”, und die Stadt bisher noch nicht weiter erkundet hat?

Richtig, man schnappt sich seine Kamera und zieht los, von früh bis spät, die Temperatur im Bereich von zwölf Grad Celsius unter Null lässt man gekonnt ausser acht und fährt mit U und S-Bahn einfach umher.

Zentraler Punkt ist der Jungfernstieg, da wo quasi alle Linien zusammenlaufen und von wo aus man überall problemlos hinkommt, durchaus praktische Sache.

hamburg hafencity 25012014 hamburg landungsbruecken 25012014 hamburg jungfernstieg rathaus 25012014 hamburg hafencity 3 25012014 hamburg elbe 25012014 hamburg elbe1 25012014 hamburg alster bokeh 25012014 hamburg alster 25012014