Una delle tante novità portate da HTML5 è la possibilità di memorizzare in locale un’applicazione Web. E’ vero che un sistema di caching locale delle pagine esiste già, questo è però gestito in maniera monocratica dai browsers, mentre adesso sarà lo sviluppatore stesso ad indicare quali risorse dovranno essere eventualmente memorizzate sul computer del visitatore. Saremo noi sviluppatori, quindi, ad avera la “palla in mano”. HTML5 ci offre gli strumenti per farlo.
Il meccanismo di funzionamento è molto semplice, si esegue il download delle risorse quando si è online per poterne poi usufruire quando siamo offline, e fino qui niente di nuovo.
La novità sta nella creazione di un file manifesto (cache manifest file) che non sarà altro che un elenco di URL di tutte le risorse (HTML, CSS, JavaScript ect..) che dovranno essere disponibili per la navigazione offline, forzandone quindi da parte del browser il salvataggio di una copia in locale.
Quello che dovremo fare sarà puntare al cache manifest file, che potrà trovarsi dove meglio crediamo all’interno del nostro server, attraverso l’attributo manifest
del tag html
:
<!DOCTYPE HTML> <html manifest="cache.manifest"> <body> ... </body> </html>
L’attributo manifest
può puntare a un URL assoluto oppure ad un percorso relativo, ma un URL assoluto deve essere sotto la stessa origine l’applicazione web.
manifest
che punti al file manifesto. Riassumendo, il browser non memorizzerà nella cache una pagina se questa non contiene l’attributo manifest
(a meno che non è esplicitamente elencata nel file manifesto). Inoltre se non elenchiamo tutte le pagine (che vogliamo siano disponibili in locale) nel file manifesto, il browser non saprà che vi sono altre pagine che devono essere scaricate e memorizzati nella cache e non lo farà.
Master entries
Qualunque file HTML che include l’attributo manifest
nel tag html
è un master entry. Se il file non è incluso nel manifest file, la visita della pagina (cioè del file), causerà che questa sia aggiunta alla cache come master entry.
content type
Dobbiamo tenere presente che il cache manifest file dovrà essere servito dal server Web con il content type giusto, che in questo caso è text/cache-manifest. Se stiamo utilizzando Apache per esempio, dovremo mappare l’estensione con il content type attraverso AddType directive nel file .htaccess (che è posizionato nella root della nostra web directory):
AddType text/cache-manifest .manifest
Se utilizziate un altro server Web, consultarne allora la documentazione per capire come eseguire tale operazione.
manifest file
Vediamo ora la struttura di un semplice manifest file:
CACHE MANIFEST # version 1.0 05/01/2012 index.html css/main.css scripts/main.js img/logo.png
- Il manifest file deve sempre iniziare con la riga CACHE MANIFEST
- La seconda riga inizia per # perchè è un commento. I commenti sono naturalmente opzionali tuttavia possono venirci in aiuto per forzare il refresh della cache. Difatti la cache verrà aggiornata soltanto se vi sono delle modifiche all’interno del manifesto, non se una risorsa viene modificata. Così potremmo trovarci nella situazione di modificare un file css o JavaScript senza che questo sia aggiornato nella cache. Modificando il file manifest, informeremo il browser che deve aggiornare i files presenti nella cache.
- Se non riesce il download di una risorsa specificata nel manifesto, l’intero processo di aggiornamento della cache fallisce. Il browser continuerà ad usare la vecchia cache dell’applicazione (nel caso ve ne sia una).
Un utilizzo avanzato prevede la suddivisione del manifest file in tre sezioni: CAHE, NETWORK e FALLBACK.
- CHACHE: Coincide con l’uso di default che abbiamo visto prima. I files elencati sotto questa intestazione (oppure direttamente sotto CACHE MANIFEST) saranno esplicitamente memorizzati nella cache.
- NETWORK: I files di questa sezione sono considerati risorse white-list, che richiedono una connessione al server. Tutte le richieste a queste risorse baipasseranno la cache, anche se l’utente è offline. Possono essere utilizzati caratteri jolly.
- FALLBACK: Questa sezione specifica delle pagine di ripiego se una risorsa non è accessibile. Il primo URI è la risorsa, il secondo rappresenta il fallback. Possono essere utilizzati caratteri jolly.
Vediamo ora un esempio:
CACHE MANIFEST # version 2.0 05/01/2012 # Memorizzazione espicita nella cache index.html css/style.css # risorsa di ripiego FALLBACK: / /offline.html # Risorse che richiedono di essere online. NETWORK: /api # risorse addizionali alla cache CACHE: img/logo.png scripts/main.js
Da notare che nella sezione FALLBACK è stata aggiunta una risorsa che verrà visualizzata se il browser non trova la pagina nella cache. Il primo carattere (/) della riga è un URL pattern che matcherà qualsiasi pagina nel sito, non soltanto la home come verrebbe da pensare.
Nella sezione NETWORK invece ci assicuriamo che le richieste per caricare le risorse contenute nel sottoalbero /api/ non tentino di accedere alla cache.
Formato dati
Il formato per le linee di dati varia da sezione a sezione. Nella sezione esplicita (cache), ogni riga è un URI od IRI valido (i caratteri jolly sono ammessi in questa sezione). Uno spazio bianco è ammesso prima e dopo l’URI od IRI su ogni linea. Nella sezione Fallback ogni riga è un URI od IRI valido ad una risorsa, seguito da una risorsa di fallback. Nella sezione di nertwork, ogni riga è un URI od IRI valido (il carattere jolly * è consentito in questa sezione).
Eventi
Quando un browser visita una pagina che punta ad un file manifest, vengono attivati una sequenza più o meno lunga di eventi sull’oggetto window.applicationCache
. Tutti gli eventi elencati qui sono licenziati su tale oggetto.
Nome evento | Descrizione |
---|---|
checking |
Appena il browser nota una attributo manifest sull’elemento html licenzia questo evento, che cercherà di scaricare il manifesto per la prima volta oppure controllerà per un aggiornamento nel caso il manifesto sia già stato scaricato. Questo è sempre il primo evento della sequenza.
|
noupdate |
Evento licenziato se il manifesto non è cambiato. Ultimo evento nella sequenza. |
downloading |
Questo evento viene licenziato nel caso il manifesto sia stato scaricato per la prima volta oppure sia stato modificato. L’evento inizierà rispettivamente a scaricare o riscaricare ogni singola risorsa elencata nel manifesto. |
progress |
Mentre esegue il download, il browser licenzia periodicamente l’evento progress , che contiene info su quanti files sono stati scaricati e quanti sono ancora in coda di scaricamento.
|
cached |
Evento attivato quando tutte le risorse elencate nel manifest file sono state scaricate e quindi saranno disponibili per la navigazione offline. Ultimo evento nelle sequenza. |
updateready |
In caso di aggiornamento del manifesto, quando tutte le risorse saranno state riscaricate, il browser licenzierà questo evento che indica che la nuova cache è disponibile. Per forzare la nuova versione senza costringere l’utente a ricaricare la pagine è possibile eseguire una chiamata al metodo swapCache() . Ultimo evento nelle sequenza.
|
error |
Viene licenziato nei seguenti casi:
|
Stato della cache
Ogni applicazione ha uno stato della cache, che indica la condizione attuale della cache, possiamo monitorarlo attraverso la proprietà status
dell’oggetto window.applicationCache
:
-
UNCACHED
Un valore speciale che indica che l’oggetto cache non è completamente inizializzato. -
IDLE
La cache non è attualmente in corso di aggiornamento. -
CHECKING
Il manifesto è in scaricamento e si sta controllando per gli aggiornamenti. -
DOWNLOADING
Le risorse sono in fase di download a causa di un cambiamento del manifesto. -
UPDATEREADY
E’ disponibile una nuova versione della cache. Come detto, c’è un evento corrispondenteupdateready
, che è licenziato quando un nuovo aggiornamento è stato scaricato ma non ancora attivato utilizzando il metodoswapCache()
. -
OBSOLETE
La cache è ormai obsoleta.
var appCache = window.applicationCache; switch (appCache.status) { case appCache.UNCACHED: // UNCACHED == 0 return 'UNCACHED'; break; case appCache.IDLE: // IDLE == 1 return 'IDLE'; break; case appCache.CHECKING: // CHECKING == 2 return 'CHECKING'; break; case appCache.DOWNLOADING: // DOWNLOADING == 3 return 'DOWNLOADING'; break; case appCache.UPDATEREADY: // UPDATEREADY == 4 return 'UPDATEREADY'; break; case appCache.OBSOLETE: // OBSOLETE == 5 return 'OBSOLETE'; break; default: return 'STATO SCONOSCIUTO'; break; };
obsoleted
sull’oggetto cache. Poi lo stato della cache sarà spostato su OBSOLETE.
Il processo di aggiornamento
Ora che abbiamo in mano tutte le informazioni, ricapitoliamo come si sviluppa in realtà il processo:
-
Quando il browser visita un documento che include un attributo
manifest
e se non esiste ancora la cache dell’applicazione, caricherà il documento e tutte le voci elencate nel file manifest, creando la prima versione della cache dell’applicazione. -
Le visite successive a tale documento faranno scattare il browser a caricare il documento, e le altre risorse specificate nel file manifesto, dalla cache e non dal server, in aggiunta il browser invierà un evento
checking
per l’oggettowindow.applicationCache
, poi preleverà il file manifesto, seguendo le appropriate regole di caching HTTP. -
Se la copia del manifesto nella cache è aggiornata, l’evento
noupdate
viene inviato all’applicationCache
, e il processo di aggiornamento è completo. (È per questo che se si cambia una o più risorse sul server, è necessario modificare anche il file manifesto in modo che il browser sa che deve prendere tutte le risorse ancora una volta).
Se il file manifesto è cambiato, tutti i files nel manifesto, vengono recuperati in una cache temporanea. Per ogni file recuperato in questa cache temporanea, sarà licenziato un eventoprogress
sull’oggettoapplicationCache
.
In caso di errori, un evento dierror
sarà licenziato, e la fermerà l’aggiornamento. -
Una volta che tutti i files sono stati recuperati correttamente, vengono spostati nella cache reale ed un evento
cached
viene licenziato sull’oggettoapplicationCache
. Poiché il documento è già stato caricato nella cache del browser, il documento aggiornato non sarà reso fino a quando il documento non sarà ricaricato (manualmente o programmaticamente).
Supporto dei Browsers
[browserSupport ie=10.0+ firefox=3.5+ chrome=4.0+ safari=4.0+ opera=10.6+]
Conclusioni
A mio avviso, ad oggi visto la mancanza di supporto da parte di IE (disponibile solo dalla versione 10) la tecnologia può trovare ancora delle restrizioni sull’impiego effettivo, tuttavia Google ha già provveduto a dismettere il progetto Gears per dare pieno supporto ad HTML5, e questo è un segnale.
Inoltre Hotmail sembra intenzionata a risolvere il gap nei confronti di GMAIL sull’archiviazione offline supportando l’application cache. Non mi stupirei se tra qualche tempo i client di posta saranno definitivamente archiviati e sostituiti dalle applicazioni online (consultabili anche offline :)).
Inoltre la feature oltre ad essere ideale per i dispositivi mobili (visto il tipo di connessione) e per le applicazioni progettate per funzionare in uno stato non in linea potrebbe migliorare sensibilmente le prestazioni delle applicazioni web online, fruttandola per il caching di risorse statiche.
Risorse
www.whatwg.org/specs/web-apps/current-work/multipage/offline.html