Strategien für das Cache-Busting von CSS

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Große Leistungsgewinne lassen sich durch das Browser-Caching von CSS erzielen. Sie stellen sicher, dass Ihr Server eingerichtet ist, um Header zu senden, die dem Browser mitteilen, die CSS-Datei für eine bestimmte Zeit aufzubewahren. Dies ist eine bewährte Methode, die viele, wenn nicht die meisten Websites bereits anwenden.

Hand in Hand mit dem Browser-Caching geht das Cache-Busting. Angenommen, der Browser hat die CSS-Datei ein Jahr lang im Cache gespeichert (nicht ungewöhnlich). Dann möchten Sie das CSS ändern. Sie benötigen eine Strategie, um den Cache zu brechen und den Browser zum Herunterladen einer neuen Kopie des CSS zu zwingen.

Hier sind einige Möglichkeiten.

Das CSS muss im Cache sein, damit dies relevant ist…

Nur um sicherzugehen, hier sehen einige gut aussehende Header für eine gecachte CSS-Datei aus

Wir suchen nach dem Cache-Control und Expires Header. Ich bin kein Experte für Serverkonfigurationen. Ich würde mir wahrscheinlich die H5BP-Serverkonfigurationen ansehen. Aber hier sind einige klassische Wege mit Apache/HTAccess, um das zu erreichen

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)(\.gz)?$">
  Header set Expires "Thu, 15 Apr 2020 20:00:00 GMT"
</FilesMatch>
<IfModule mod_expires.c>
  ExpiresActive on
  ExpiresByType text/css                  "access plus 1 year"
  ExpiresByType application/javascript    "access plus 1 year"
</IfModule>

Query-Strings

Die meisten Browser sehen heutzutage eine URL mit einem anderen Query-String als eine andere Datei und laden eine frische Kopie herunter. Die meisten CDNs unterstützen und empfehlen dies sogar.

<link rel="stylesheet" href="style.css?v=3.4.1">

Kleine Änderung vornehmen? Ändern Sie es zu

<link rel="stylesheet" href="style.css?v=3.4.2">

Sie könnten es sich potenziell einfacher machen, indem Sie eine serverseitige Variable festlegen, die Sie an mehreren Stellen verwenden. Eine Änderung würde somit den Cache für viele Dateien gleichzeitig brechen.

<?php $cssVersion = "3.4.2"; ?>

<link rel="stylesheet" href="global.css?v=<?php echo $cssVersion; ?>">

Vielleicht könnten Sie sogar Semantische Versionierung verwenden. Sie könnten auch eine Konstante definieren.

Dateinamen ändern

Query-Strings funktionierten nicht immer. Einige Browser sahen keinen Unterschied bei einem anderen Query-String als eine andere Datei. Und einige Software (habe ich gehört: Squid) würde Dateien mit Query-Strings nicht cachen. Steve Souders sagte uns, dass wir es nicht tun sollen.

Ein ähnliches Konzept war, den Dateinamen selbst zu ändern. Wie hier im HTML

<link rel="stylesheet" href="style.232124.css">

Sie würden dies programmgesteuert behandeln, nicht den Dateinamen in Ihrem Projekt wörtlich ändern. Da diese Datei auf dem Server nicht wirklich existiert, benötigen Sie einige Tricks, um sie zur richtigen Datei zu leiten. Jeremy Keith hat kürzlich seine Technik dafür abgedeckt.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+).(\d+).(js|css)$ $1.$3 [L]

Das weist den Server an, diese Zahlen in JavaScript- und CSS-Dateinamen zu ignorieren, aber der Browser wird sie immer noch als neue Datei interpretieren, wenn ich diese Zahl ändere.

Er verwendet Twig, daher sind die Vorlagen, die er verwendet, letztendlich wie

{% set cssupdate = '20150310' %}

<link rel="stylesheet" href="/css/main.{{ cssupdate }}.css">

Ich bin sicher, Sie können sich eine Version davon in jeder Backend-Sprache vorstellen (wie ASP). Stufe auf, indem Sie ein Build-Tool oder ein Deployment-Skript die Variable selbst aktualisieren lassen.

Cache-Busting „Nummer“ basierend auf dem letzten Aktualisierungsdatum der Datei

Bei der Suche nach diesem Cache-Busting-Zeug sehen Sie viele Ratschläge, die empfehlen, den Server zu verwenden, um zu überprüfen, wann die Datei zuletzt aktualisiert wurde, um die Cache-Busting-„Nummer“ zu erstellen (Nummer bedeutet, was auch immer Sie ändern, um den Cache zu brechen).

function autoversion($url) {
  $path = pathinfo($url);
  $ver = '.'.filemtime($_SERVER['DOCUMENT_ROOT'].$url).'.';
  return $path['dirname'].'/'.str_replace('.', $ver, $path['basename']);
}
<link href="<?php autoversion('/path/to/theme.css'); ?>" rel="stylesheet">

Ich kann dazu nicht gut sprechen. Mir scheint, dass die Aufforderung an Ihren Server, diese Informationen bei jedem Seitenaufruf abzurufen, in der Produktion ziemlich intensiv und gefährlich wäre. Früher habe ich Dinge getan wie „Ich lasse PHP einfach die Dimensionen des Bildes in Datenattributen ausgeben!“, nur um festzustellen, dass der Server zum Stillstand kommt. Seien Sie jedenfalls vorsichtig.

ETags

ETags scheinen eine gute Idee zu sein, denn der Sinn von ihnen ist es, Informationen bereitzustellen, um zu prüfen, ob der Browser bereits eine Kopie dieser Datei hat.

Aber die meisten Ratschläge lauten: „schalten Sie Ihre ETag-Header aus“. Yahoo sagt

Das Problem mit ETags ist, dass sie typischerweise mit Attributen konstruiert werden, die sie für einen bestimmten Server, der eine Website hostet, einzigartig machen. ETags stimmen nicht überein, wenn ein Browser die ursprüngliche Komponente von einem Server abruft und später versucht, diese Komponente auf einem anderen Server zu validieren, eine Situation, die auf Websites, die einen Servercluster zur Bearbeitung von Anfragen verwenden, nur allzu häufig vorkommt.

Ein weiteres Problem ist, dass sie nicht so effektiv sind wie tatsächliches Caching. Um einen ETag zu prüfen, muss immer noch eine Netzwerkanfrage gestellt werden. Es geht nicht nur um den Download von Dateien, der die Leistung beeinträchtigt, sondern um die gesamte Netzwerkaushandlung und Latenz.

Auch hier bin ich kein Experte, aber hier ist, was im Apache-Bereich im Allgemeinen empfohlen wird, um sie auszuschalten

<IfModule mod_headers.c>
  Header unset ETag
</IfModule>
FileETag None

Framework macht es für uns

Rails Asset Pipeline

Ich habe einige Erfahrungen mit der Rails Asset Pipeline und Sprockets. Es ist ein Traumsystem, wenn Sie mich fragen. Ich verlinke Stylesheets in Vorlagen

<%= stylesheet_link_tag "about/about" %>

Und es erzeugt HTML wie

<link href="http://assets.codepen.io/assets/about/about-7ca9d3db0013f3ea9ba05b9dcda5ede0.css" media="screen" rel="stylesheet" type="text/css" />

Diese Cache-Busting-Nummer ändert sich nur, wenn sich die Datei ändert, sodass Sie den Cache nur für die Dateien brechen, die gebrochen werden müssen. Außerdem gibt es Methoden für Bilder und JavaScript.

WordPress

Wenn Sie ein Seitencaching-Tool in WordPress verwenden, wie W3 Total Cache oder etwas Ähnliches, müssen Sie wahrscheinlich weniger Angst vor der `filemtime`-Angelegenheit haben, die zu serverintensiv ist.

Gilbert Pellegrom postete eine WordPress-spezifische Technik, die sie verwendet

wp_register_style( 'screen', get_template_directory_uri().'/style.css', array(), filemtime( get_template_directory().'/style.css' ) );
wp_enqueue_style( 'screen' );

// Example Output: /style.css?ver=1384432580

Das WordPress-Plugin Busted! macht im Grunde dasselbe im Hintergrund. Es kümmert sich sozusagen automatisch um alles.

CodeKit

CodeKit hat keine integrierte Methode zum Ändern von Dateinamen, aber es gibt eine Möglichkeit, Shell-Skripte unter von Ihnen festgelegten Umständen auszuführen.

Michael Russell hat einen Blogbeitrag darüber, wie man Zeitstempel in Dateien einfügen kann, den Sie sicher modifizieren könnten, um stattdessen Dateinamen zu ändern.

Build-Tools

Alle beliebten Task-Runner / Build-Tool-Dinger haben Plugins, die beim Ändern von Dateinamen helfen. Sufian Rhazi hat einen Beitrag darüber, wie man es in rohem Node.js macht.

Grunt

Gulp

Brokkoli

Innerhalb von Präprozessoren

Beim Verknüpfen von Assets innerhalb anderer Assets (z. B. eines Bildes, auf das Sie aus einer LESS-Datei verweisen) könnten Sie den Präprozessor zur Arbeit bringen. Ben Nadel hat einen Beitrag, wie man genau das tut.

Async CSS

Da Critical CSS immer wichtiger wird, wird auch das verzögerte Laden von CSS wichtiger. Es gibt auch andere Gründe, CSS verzögert zu laden (vielleicht Druck-CSS oder das Vorbereiten des Caches).

Wenn Sie CSS mit loadCSS laden (oder vielleicht einen Link-Tag einfügen), müssen Sie den angeforderten Dateinamen im JavaScript selbst aktualisieren. Anders als das Ändern des Dateinamens, aber nicht so anders.

Also

Habe ich etwas übersehen? Was ist Ihre Cache-Busting-Strategie?