Kešování externích stylů a skriptů: věčné a zároveň flexibilní

Stručně navážu na nedávnoý článek GZipování podruhé: skripty a styly, kde jsem zveřejnil svůj způsob komprese externích CSS a JS souborů a na základě podnětných připomínek z komentářů ho podstatně vylepšil. Byl napůl vysloven problém s kešováním pomocí expires, a zde přináším intuitivní odpověď v php kódu.

Jen pro vysvětlenou, v čem spočívá problém: nastavením hlavičky expires dáváme (většinou) prohlížeči na vědomí, jak dlouho se má spokojit s aktuální verzí souboru, jak dlouho si nemá zjišťovat existenci změn (potažmo stahovat ze serveru aktuální verzi). Problém nastává, když v souboru na serveru změny nastanou a zároveň klient o této změně nemá informaci, neboť lhůta dosud nevypršela.

Z této nesladěnosti mohou vyplynout více či méně problematické chyby, obecně známá je například situace, kdy na webu nastane aktualizace jak v HTML kódu, tak v CSS kódu: zatímco HTML obsah je typicky kešován po kratší dobu a se vší pravděpodobností k jeho znovnačtení ze serveru dojde, u CSS se může použít verze z lokální cache. V této situaci klient nevidí web v jeho zamýšlené podobě.

Jak to nyní řeším? (v 1.0)

PHP funkce

function getModStamp ($path) {
        return (is_file($path)) ? subStr(md5(fileMTime($path)), 0, 10) : '404-' . $path;
}

Tzn.: Pokud v parametru uvedený soubor existuje → Vezme se datum poslední změny souboru (unix timestamp) → Datum se zahashuje → Z hashe se vezme prvních 10 znaků, které se returnují. Pokud soubor neexistuje → funkce vrátí řetězec 404-zadaná cesta (pro snažší debug).

Šablona

<script src="scripts/_zip.php?file=jq.js&amp;<?php echo getModStamp(PATH . '/scripts/jq.js'); ?>" type="text/javascript"></script>

Produkt

<script src="scripts/_zip.php?file=jq.js&amp;b526d9b2b7" type="text/javascript"></script>

Jak mile nastane změna v linkovaném souboru (resp. změní se datum poslední změny souboru), změní se i generovaný otisk (b526d9b2b7), a prohlížeč zareaguje načtením aktuální verze.

Uznávám, že používání tohoto postupu může být v některých situacích chápáno jako zbytečně pracná metoda a raději se rozhodnete nastavit „optimální“ hodnotu expires. Ale mně to vyhovuje. Mohu takto uživateli posílat soubory s nekonečnou trvanlivostí a zároveň mít jistotu, že jen co provedu sebemenší změnu, bude obratem zaregistrována.

Dodatek: Tuto fičúru oceníte zvláště vy, kdo jste už někdy vysvětloval klientovi, že musí zmáčknout F5 a nebo CTRL-R a ono to né a né…


Komentáře (10)

k formuláři

RSS kanál komentářů

    • Komentář číslo: 1
    • *
    • Jméno: David Majda
    • Odesláno:
      24.12. 2007 — 12:01

    Na co ta MD5? Číslo, co vypadne z filemtime by mělo stačit, nebo ne?

    Kód v sekci „Šablona“ by šel vylepšit, je v něm zbytečně 2× jméno skriptu. Já bych si asi napsal fci na vygenerování celého tagu, která by to jméno dostala jen jednou jako parametr.

    • Komentář číslo: 2
    • *
    • Jméno: Peter
    • Odesláno:
      24.12. 2007 — 12:03

    Tohle se mi bude určitě hodit, díky.
    (nepíše se jak mile dohro mady?)

    • Komentář číslo: 3
    • *
    • Jméno: Kahi
    • Odesláno:
      24.12. 2007 — 17:41

    [1] David Majda: – proč MD5? Dobrá otázka :-). Neumím na ni odpovědět.

    Kód v šabloně by jistě šel vylepšit, ale v demonstracích dávám přednost pochopitelnosti před estetickými optimalizacemi, ke kterým jednak každý přistupuje odlišně a druhak jejich opodstatnění je znatelné až v kontextu kódu celé šablony…

    [2] Peter: – nene, jak mile se píše zvlášť. Prosím neplést s jakmile, které se naopak píše dohromady!

    • Komentář číslo: 4
    • *
    • Jméno: Věroš
    • Odesláno:
      26.12. 2007 — 12:04

    Nechca být za rejpala, ptám se je tam něco, co se nedá udělat vhodným nastavením Apache?

    Zkoušel jsem si teď hrát s nastavením cachovacích hlaviček a moc se mi to líbí :-) Pokud bude zájem, tak můžu zusit sjet nějaké statistiky.

    A sám si odpovím: jo, ušetří se tím několik HTTP dotazů.

    • Komentář číslo: 5
    • *
    • Jméno: Kahi
    • Odesláno:
      26.12. 2007 — 19:33

    [4] Věroš: Nechca být za rejpala, ptám se je tam něco, co se nedá udělat vhodným nastavením Apache?

    Ať už tam znamená cokoliv, nevím :-). O statistiky nějak zvlášť nestojím, ale pokud si je budeš dělat pro sebe, tak pošli link ;).

    • Komentář číslo: 6
    • *
    • Jméno: Yuhů
    • Odesláno:
      27.12. 2007 — 17:03

    Možná by bylo lepší poskytnout radu v jednodušší podobě:

    Jakmile se změní CSS, je potřeba změnit mu adresu.

    To, že se na změnu adresy používá PHP, je celkem elegantní. Bál bych se ale, že to povede k nějakým chybám. Minimálně doporučuju celou akci důkladně okomentovat, aby bylo každému jasné, co dělá.

    Já považuju za jistější osvojit si rutinu:

    • jestliže posílám na server nové CSS nebo skript,
    • ihned v šabloně měním odkaz (například připojením data za otazník)
    • Komentář číslo: 7
    • *
    • Jméno: Kahi
    • Odesláno:
      27.12. 2007 — 19:34

    [6] Yuhů: – Ačkoli myslím, že ta funkce je dostatečně sama-o-sobě-mluvící, přidal jsem k ní pro klid duše v dvou větách vysvětlení…

    Dále říkáš, že se bojíš chyb. Hm, mohl bys to nějak specifikovat? Neumím si představit představitelnou situaci, kdy by ten skript selhal…

    • Komentář číslo: 8
    • *
    • Jméno: Majkee
    • Odesláno:
      31.12. 2007 — 1:52

    Je to moc dobrá věcička. Thx. Ale pořád se nemůžu zbavit dojmu že jakmile se píše dohromady. Jakmile = hned až, kdežto jak mile = jak přívětivě.

    • Komentář číslo: 9
    • *
    • Jméno: Kahi
    • Odesláno:
      31.12. 2007 — 6:26

    8 – Bohužel musím nesouhlasit a kontraargumentovat: jsem (podobně jako tento skript) bezchybnatý!

    • Komentář číslo: 10
    • *
    • Jméno: Honza
    • Odesláno:
      7.1. 2008 — 15:57

    [9] Kahi: – Ohledně jak mile zkusim jinou argumentaci…

    Bezchybnatý zní jako vodnatelná kedlubna!

Přidat komentář

Nápověda ke psaní komentářů

Zde formátuje Texy!

  • *zvýraznění*
  • **silné zvýraznění**
  • > citace
  • "odkaz":http://kam
  • [4] reakce na komentář
  • zdrojové kódy a více

komentáře

úplně nahoru