Magento Browser Cache Problem lösen

Beitrag vom: 03.03.2014, 13:00:33

Wir beschreiben im folgenden Artikel wie die Magento Browser Cache-Problematik bei CSS- und JavaScript-Dateien gelöst werden kann.

Bekanntermaßen bietet Magento die Möglichkeit, CSS- und JavaScript-Dateien im Frontend zu einer einzigen zusammefassen. Das spart Servercalls und lässt die Seite beim ersten Aufruf schneller laden. Funktioniert mittlerweile auch gut und kann ohne größere Bedenken eingesetzt werden. Allerdings mit einem Haken.

Problem:
Denn die zusammengefassten Dateien haben auch nach Änderungen in den Ursprungsdateien immer noch denselben Namen, was zu Problemen mit den Browsercaches führen kann. D.h. wenn jemand schon vorher auf der Seite war, bekommt der Browser die neuen CSS-Anweisungen oder JavaScript-Codezeilen erst mit, wenn der Browser-Cache geleert wird (manuell oder automatisch).
Bei relativ größeren Veränderungen der Seite kann es (wie wir selbst erfahren mussten) zu ziemliech zerschossenen Seiten führen.
Auch das Löschen der Caches im Magento-Backend hilft nicht, denn der Dateiname ändert sich ja nicht und der Browser hat keinen Anlass für ein Neuladen.

Ursache:
Die Core-Klasse Mage_Core_Model_Design_Package beinhaltet zwei Methoden, um die entsprechenden Dateien zusammenzuführen:

getMergedJsUrl() und getMergedCssUrl()

Der Inhalt ist ähnlich (getMergedCssUrl() berücksichtigt zusätzlich eventuelle SSL-Verbindungen) und sammelt im Prinzip alle entsprechenden Dateien um sie zu verschmelzen. Was genau passiert verrät euch der Blick in die Methoden.

Der Knackpunkt ist, dass beide Methoden aus den Serverpfaden der Dateien per md5() einen neuen Dateinamen generieren. Diese nennt sich dann z. B.:
http://www.test-shop.de/media/css/418841977458349457c0c30a47dac83d.css.

Der Dateiname wird also nicht etwa aus dem Inhalt generiert, sondern nur aus den Dateinamen selbst. Der neue Dateiname kann sich also nur ändern, falls z. B. eine neue JavaSctipt-Datei erstellt wird. Inhaltsänderung werden demnach ignoriert.

Dadurch denkt der Browser also immer noch es ist dieselbe Datei und lädt diese nicht vom Server, sonder aus dem eigenen Cache.

Lösung:
Um das zu umgehen (wir können ja den Browser des Client nicht direkt beeinflussen) kann einfach ein sich ändernder Parameter an die Datei gehängt werden, um dem Browser eine neue Datei vorzugaukeln. Dieser Parameter sollte sich natürlich nur dann ändern, wenn auch der Inhalt sich ändert, sondern würde der Browser die Datei bei jedem Aufruf neu laden.

Die url zur Datei könnte dann z. B. so aussehen:
http://www.test-shop.de/media/css/418841977458349457c0c30a47dac83d.css?2deb58dc7a163341242303e076032abb1a164121

Unsere ganz spezielle Lösung (die fast schon auf der Hand liegt wenn man mit git arbeitet): bei jeder Änderung den Hash des jeweiligen git-Commits dafür verwenden.

Konkret heißt das, wir machen einen rewrite auf die Klasse Mage_Core_Model_Design_Package und schreiben unsere eigene Klasse die das erledigt:

<?php
class Mitho_Tweaks_Model_Design_Package extends Mage_Core_Model_Design_Package {

/**
* Merge specified css files and return URL to the merged file on success
*
* @param $files
*
* @return string
*/
public function getMergedCssUrl($files) {

return parent::getMergedCssUrl($files) . '?' . $this->getGitHash();

}

/**
* Merge specified javascript files and return URL to the merged file on success
*
* @param $files
*
* @return string
*/
public function getMergedJsUrl($files) {

return parent::getMergedJsUrl($files) . '?' . $this->getGitHash();

}

private function getGitHash() {

$file     = getcwd() . '/.git/logs/HEAD';
$data     = file($file);
$lastline = $data[count($data) - 1];

$gitHash = explode(' ', $lastline);
$gitHash = $gitHash[1];

return $gitHash;

}
}

Die beiden schon erwähnten Methoden aus der Elternklasse werden immer noch aufgerufen, aber durch die eigene Methode getGitHash() ergänzt. Diese liest den aktuellen Hash aus dem git-Ordner und hängt ihn an als Parameter an die Dateien. Damit lädt der Browser die Datei auch wirklich nur dann neu, wenn es auch etwas Neues zu laden gibt.
Fortan braucht ihr euch also keine Sorgen mehr um Browsercaches machen.

Wer git nicht benutzt kann den Lösungsvorschlag natürlich auch gerne als Basis für eigene Ideen verwenden. Lasst es uns wissen, Kommentare sind sehr willkommen!


Kontakt