Você está aqui: Home ‣ Dive Into HTML5 ‣
❧
que são aplicações web offline? Em um primeiro momento, parece uma contradição de termos. Páginas da web são coisas que você faz download e renderiza. Download implica conexão com a rede. Como você pode fazer download quando você está offline? É claro, você não pode. Mas você pode fazer download quando você está online. E é assim que as aplicacões offline da HTML5 funcionam.
De forma simples, uma aplicacão web offline é uma lista de URLs — HTML, CSS, JavaScript, imagens, ou qualquer tipo de recurso. A página inicial de uma aplicação web offline aponta para essa lista, chamado de arquivo manifesto, que é apenas um arquivo texto localizado em qualquer lugar no servidor web. Um navegador web que implementa aplicações offline em HTML5 irá ler a lista de URLs do arquivo manifesto, fazer download dos recursos, realizar o cache deles localmente, e automaticamente manter os arquivos locais atualizados à medida que são alterados. Quando chegar a hora em que você tentar acessar as aplicações web sem uma conexão de rede, seu navegador web irá automaticamente apontar para as cópias locais.
A partir disso, a maioria do trabalho está com você, desenvolvedor web. Existe uma indicação no DOM que irá dizer se você está online ou offline. Existem eventos que são disparados quando seu status offline muda (em um minuto você está offline e no próximo minuto está online, ou vice-versa). Mas é basicamento isso. Se a sua aplicação cria dados ou salvo estados, está com você a missão de armazenar dados localmente enquanto está offline e sincronizar isso com o servidor remoto uma vez estando online novamente. Em outras palavras, HTML5 pode levar suas aplicações web offline. O que você faz quando chegar lá é com você.
IE | Firefox | Safari | Chrome | Opera | iPhone | Android |
---|---|---|---|---|---|---|
· | 3.5+ | 4.0+ | 5.0+ | 10.6+ | 2.1+ | 2.0+ |
❧
Uma aplicação web offline utiliza um arquivo de manifesto cache. O que é
um arquivo manifesto? É uma lista de todos os recursos que a sua aplicação
web irá precisar acessar quando estiver desconectada de uma rede. Afim de
iniciar o processo de download e cache desses recursos, você irá precisar
apontar para o arquivo manifesto, utilizando o atributo
manifest
no seu elemento <html>
.
<!DOCTYPE HTML>
<html manifest="/cache.manifest">
<body>
...
</body>
</html>
Seu arquivo de manifesto cache pode estar localizado em qualquer lugar do
seu servidor web, mas precisa estar servido sob o tipo de conteúdo
text/cache-manifest
. Se você está rodando um servidor web
baseado no Apache, você provavelmente precisa adicionar uma
diretiva AddType
no seu arquivo .htaccess
na raíz do seu diretório web:
AddType text/cache-manifest .manifest
Depois certifique-se que o nome do seu arquivo de manifesto cache termina
com .manifest
. Se você usa um servidor web diferente ou uma
configuração diferente do Apache, consulte a documentação do seu servidor
em controle de cabeçalho Content-Type
.
☞P: Minha aplicação web abrange mais de uma página. Preciso de um atributo
manifest
em cada página, ou posso colocar apenas na home page?R: Cada página da sua aplicação web precisa de um atributo
manifest
que aponta para o manifesto cache para toda aplicação.
OK, então cada uma das suas páginas HTML apontam para seu
arquivo de manifesto cache, e seu arquivo de manifesto cache sendo
servidor com o devido cabeçalho Content-Type
. Mas o que
acontece dentro do arquivo manifesto? É aqui onde as coisas
começam a ficar interessante.
A primeira linha de todo arquivo de manifesto cache é assim:
CACHE MANIFEST
Depois disso, todos os arquivos manifesto são divididos em três partes: a seção “explícita”, a seção “fallback”, e a seção “lista branca online”. Cada seção tem um header, na sua própria linha. Se o arquivo manifesto não tiver nenhum desses cabeçalhos de seção, todos os recursos listados estão implicitamente na seção “explícita”. Tente não se debruçar sobre a terminologia, se não sua cabeça irá explodir.
Aqui está um arquivo manifesto válido. Ele lista três recursos: um arquivo CSS, um arquivo JavaScript, e uma imagem JPEG.
CACHE MANIFEST
/clock.css
/clock.js
/clock-face.jpg
Esse arquivo de manifesto cache não possui cabeçalhos de seção, então
todos os recursos listados estão na seção “explícita” por padrão. Recursos
na seção “explícita” serão feitos download e cache localmente, e serão
usados no lugar de seus respectivos semelhantes sempre que você estiver
desconectado de uma rede. Assim que for carregado esse arquivo de
manifesto cache, seu navegador irá realizar o download de
clock.css
, clock.js
, e
clock-face.jpg
do diretório raíz do seu servidor web. Então
você pode desplugar seu cabo de rede e atualizar a página, e todos aqueles
recursos estarão disponíveis offline.
☞P: Preciso listar minhas páginas HTML no meu manifesto cache?
R: Sim e não. Se a sua aplicação web inteira está contida em uma única página, apenas certifique-se que a página aponta para o manifesto cache usando o atributomanifest
. Quando você navega em uma página HTML com o atributomanifest
, a página em si assume ser parte da aplicação web, então você não precisa listá-la no arquivo manifesto. Entretanto, se a sua aplicação web agrega múltiplas páginas, você deve listar todas as páginas HTML no arquivo manifesto, caso contrário o navegador não saberá que existem outras páginas HTML que precisam fazer download e cache.
Aqui está um exemplo um pouquinho mais complicado. Suponha que você queira
que sua aplicação relógio rastreie os visitantes, usando um script
tracking.cgi que é carregado dinâmicamente por um atributo
<img src>
. Realizando o cache desse recurso irá acabar
com o propósito desse rastreamento, então esse recurso nunca deve realizar
cache e nunca deve estar disponível offline. Aqui está o que você deve
fazer:
CACHE MANIFEST
NETWORK:
/tracking.cgi
CACHE:
/clock.css
/clock.js
/clock-face.jpg
Esse arquivo de manifesto cache inclui cabeçalhos de seção. A linha
marcada com NETWORK:
é o começo dessa seção “lista branca
online”. Recursos nessa seção nunca sofrerão cache e não estarão
disponíveis offline. (Tentar carregá-los enquanto estiver offline irá
resultar em um erro.) A linha marcada com CACHE:
é o começo
da seção “explícita”. O resto do arquivo de manifesto cache é o mesmo do
exemplo anterior. Cada um dos três recursos listados estará em cache e
disponível offline.
Esse é mais um tipo de seção em um arquivo de manifesto cache: a seção fallback. Na seção fallback, você pode definir substituições para recursos online que, por uma razão qualquer, não devem realizar cache ou não realizaram cache com sucesso. A especificação da HTML5 oferece esse exemplo usando a seção fallback:
CACHE MANIFEST
FALLBACK:
/ /offline.html
NETWORK:
*
O que isso faz? Primeiro, considere um site que contém milhões de páginas, como no Wikipedia. Você não poderia fazer download do site inteiro, nem você iria querer. Mas suponha que você consiga deixar parte disso disponível offline. Como você iria decidir quais página fazer cache? Que tal isso: cada página que você já tenha visto em uma hipotética Wikipedia offline seriam feitos download e cache. Isso incluiria cada entrada da enciclopédia que você já visitou, cada página de discussão (onde você encontra discussões improvisadas sobre uma entrada particular da enciclopédia), e cada página de edição (onde você consegue, de fato, realizar alterações sobre uma entrada particular).
É isso que o manifesto cache faz. Suponha que cada página HTML (entrada, discussão, edição, histórico) no Wikipedia apontasse para esse arquivo de manifesto cache. Quando você visita qualquer página que aponta para o manifesto cache, seu navegador diz “ei, essa página é parte de uma aplicação web offline, essa é alguma que eu conheço?” Se o seu navegador nunca fez download desse arquivo de manifesto cache, ele irá definir um novo “appcache” offline; (nome curto para “aplicação cache”), fazer download de todos os recursos listados no manifesto cache, e depois adicionar a página corrente para o appcache. Se o seu navegador conhece o manifesto cache, irá simplesmente adicionar a página corrente para o appcache existente. Dessa forma, a página que você acabou de visitar acaba no appcache. Isso é importante. Significa que você pode ter uma aplicação web offline que, de forma “preguiçosa”, adiciona páginas à medida que as visita. Você não precisa listar cada uma das suas páginas HTML no seu manifesto cache.
Agora veja a seção fallback. A seção fallback nesse manifesto cache tem
apenas uma única linha. A primeira parte da linha (antes do espaço) não é
uma URL. É na verdade um padrão de URL. O único
caractere (/
) irá definir qualquer página do seu site, não
apenas a página de entrada. Quando você tentar visitar a página enquanto
estiver offline, seu navegador irá procurar por ele no appcache. Se o seu
navegador encontra a página no appcache (porque você a visitou enquanto
esteve online, e a página foi adicionada de forma implícita no appcache
naquela hora), então seu navegador irá exibir uma cópia da página em
cache. Se o seu navegador não encontrar a página no appcache, ao invés de
exibir uma mensagem de erro, irá exibir a página
/offline.html
, como especificado na segunda parte daquela
linha na seção fallback.
Finalmente, vamos examinar a seção de rede. A seção de rede nesse arquivo
de manifesto cache também tem apenas uma única linha, a linha que contém
apenas um único caractere (*
). Esse caractere tem um
significado especial na seção de rede. É chamado de “curinga da lista
branca online.” É um modo elegante de dizer que qualquer coisa que não
esteja no appcache pode ainda realizar download do endereço web original,
desde que você tenha uma conexão de internet. Isso é importante para uma
aplicação web offline sem data de volta marcada. Significa que, enquanto
você estiver navegando online nessa hipotética Wikipedia offline,
seu navegador irá buscar imagens, vídeos e outros recursos embutidos
normalmente, mesmo se estiverem em um domínio diferente. (Isso é comum em
websites grandes, mesmo se eles não fizerem parte de aplicações web
offline. Páginas HTML são geradas e servidas localmente,
enquanto que imagens e vídeos são servidos a partir de um
CDN
em outro domínio.) Sem esse curinga, nossa hipotética Wikipedia offline
iria se comportar estranhamente enquanto você estivesse online —
específicamente, não iria carregar nenhuma imagem ou vídeo hospedados
externamente!
Esse exemplo está completo? Não. A Wikipedia é mais do que arquivos
HTML. Ela comumente usa CSS, JavaScript, e
imagens em cada página. Cada um desses recursos precisariam ser listados
explicitamente na seção CACHE:
do arquivo manifesto, para que
cada página exibisse e se comportasse propriamente offline. Mas o ponto da
seção fallback é que você pode ter uma aplicação web offline sem data de
volta marcada que extende além dos recursos que você listou explicitamente
no arquivo manifesto.
❧
Até agora, falei sobre aplicações web offline, sobre cache manifest e vagamente sobre cache de aplicações offline (“appcache”), com termos quase mágicos. Coisas são carregadas, navegadores fazem decisões e tudo simplesmente funciona. Você sabe melhor que isso, certo? Quero dizer, desse desenvolvimento web que estamos falando. Nada sempre “apenas funciona”.
Primeiro, vamos falar sobre o fluxo dos eventos. Especificamente, eventos
DOM. Quando seu navegador acessa uma página que aponta para
um arquivo de cache manifest, ele aciona uma série de eventos no objeto
window.applicationCache
. Eu sei que parece complicado mas,
confie em mim, essa é a versão mais simples que eu pude pensar e que não
deixa de fora informações importantes.
manifest
no
elemento <html>
, ele dispara um evento
checking
. (Todos os eventos listados aqui são acionados pelo objeto
window.applicationCache
). O evento checking
é
sempre disparado, independente de você ter visitado esta página ou outra
página que aponte para o mesmo arquivo de cache manifest.
downloading
, e então iniciar o download dos arquivos listados no cache
manifest.
progress
, que contém informações de quantos arquivos já foram baixados e
quantos arquivos ainda estão na fila download.
cached
. Este é seu sinal de que a aplicação web offline está
completamente cacheada e pronta para ser usada sem conexão. Pronto,
você terminou.
noupdate
. E é isso, está tudo pronto.
downloading
e começar a baixar todos
os arquivos listados no cache manifest novamente.
progress
, que contém informações como quantos arquivos foram baixados até
agora e quantos arquivos ainda estão na fila para serem baixados.
updateready
. Este é o sinal de que uma nova versão de sua aplicação web
offline está totalmente cacheada e pronta para ser usada sem
conexão. A nova versão ainda não está sendo usada. Para
fazer uma “troca rápida” para a nova versão sem forçar o usuário a
atualizar a página atual, você pode chamar manualmente a função
window.applicationCache.swapCache()
.
Se, em qualquer ponto deste processo, alguma coisa terrível acontecer de
errado, seu navegador irá acionar o evento
error
e parar. Aqui está uma lista resumida
do que pode ter dado errado:
Eu quero falar sobre dois pontos importantes aqui. O primeiro é algo que
você acabou de ler, mas aposto que não absorveu muito bem, então, lá vai
novamente: mesmo que um único arquivo listado em seu arquivo de cache
manifest falhar na hora de ser carregado corretamente, todo o processo de
cache de sua aplicação web offline irá falhar. Seu navegador irá disparar
o evento error
, mas não existe nada indicando qual é o
problema. Isso pode tornar a depuração de aplicações web offline ainda
mais frustrante do que normalmente é.
O segundo ponto importante é algo que, tecnicamente falando, não é um erro, mas vai parecer um problema sério do navegador até que você descubra o que está acontecendo. Tem relação exatamente com o modo que seu navegador checa como um arquivo cache manifest foi alterado. Este é um processo de três fases. É chato mas muito importante, então preste atenção.
Expires
e Cache-Control
) dizem para seu navegador como é permitido
cachear arquivos sem ao menos ter que perguntar o que mudou pro
servidor. Este tipo de cache não tem relação nenhuma com aplicações web
offline. Isso acontece para praticamente todas as páginas
HTML, folhas de estilo, script, imagens ou qualquer outro
arquivo na web.
200 (OK)
, seguido pelo conteúdo do novo arquivo, junto de
um novo cabeçalho Cache-Control
e uma nova data de última
modificação do arquivo, então o passo 1 e 2 irão funcionar devidamente
da próxima vez. (HTTP é legal; servidores web estão sempre
preparados para o futuro. Se seu servidor web definitivamente deve te
enviar um arquivo, ele fará tudo que pode para ter certeza que ele não
lhe enviará duas vezes, atoa.) Uma vez baixado o novo arquivo de cache
manifest, seu navegador irá verificar o conteúdo do seu arquivo baixado
com o arquivo baixado da última vez. Se o conteúdo dos arquivos de cache
manifest forem iguais, seu navegador não irá fazer o download novamente
de qualquer um dos arquivos nele listados.
Qualquer um desses passos pode te confundir enquanto estiver programando e
testando sua aplicação web offline. Por exemplo, digamos que você publicou
uma versão do seu arquivo de cache manifest; então, dez minutos depois,
você percebeu que precisa adicionar outro arquivo nele. Sem problema,
certo? Apenas adicione uma linha e publique novamente. OPA! Irá acontecer
o seguinte: você atualiza a página, seu navegador percebe que existe o
atributo manifest
, ele dispara o evento
checking
, e então... nada. Seu navegador insiste que o
arquivo de cache manifest não mudou. Por que? Porque, por padrão, seu
servidor web provavelmente está configurado para avisar o navegador para
cachear arquivos estáticos por algumas horas (via semântica
HTTP, usando cabeçalhos Cache-Control
). Isso
significa que seu navegardor nunca vai passar o passo 1 daquele processo
de três passos. Certamente, o servidor web sabe que o arquivo mudou, mas
seu navegador nunca vai passar perto de fazer a solicitação ao servidor.
Por que? Porque a última vez que seu navegador baixou o arquivo de cache
manifest, o servidor pediu para cachear os arquivos por algumas horas (via
semântica HTTP, usando cabeçalhos
Cache-control
). E agora, 10 minutos depois, é exatamente isso
que seu navegador está fazendo.
Para deixar claro, isso não é um bug, é uma característica. Tudo está funcionando exatamente do jeito que deveria. Se servidores web não tivessem uma maneira de dizer aos navegadores (e intermediar proxies) a cachear coisas, a web poderia entrar em colapso do dia para noite. Mas isso não é confortante, depois de gastar horas tentando imaginar por que seu navegador não avisa sobre a atualização no arquivo de cache manifest. (E ainda melhor, se você esperar o suficiente, isso vai começar a funcionar novamente! Porque o cache HTTP expirou! Bem como deveria ser! Me mate! Me mate AGORA!)
Então aqui está uma coisa que você deveria, definitivamente, fazer:
reconfigure seu servidor web para que arquivos de cache manifest não sejam
cacheados por semânticas HTTP. Se você esta usando um
servidor baseado em Apache, estas duas linhas em seu
.htaccess
irão fazer a mágica:
ExpiresActive On
ExpiresDefault "access"
Isso vai, na verdade, desabilitar o cache para todos os arquivos desse
tipo do diretório e subdiretórios. Provavelmente, isso não é o que você
quer em produção, então você deve qualificar isso com uma diretiva
<Files>
para que, assim, irá afetar apenas seu arquivo
de cache manifest, ou criar um subdiretório que não contenha nada além
desse arquivo .htaccess
e seus arquivos de cache manifest.
Como sempre, detalhes de configuração variam dependendo do servidor, então
consulte a documentação do seu para como controlar headers de cache
HTTP.
Uma vez que tenha desabilitado o cache HTTP para arquivos de cache manifest, você ainda irá encontrar situações onde você atualiza um dos arquivos listados no appcache, mas ele irá continuar com a mesma URL em seu servidor. Aqui, o segundo passo do processo de três fases irá te sacanear. Se seu arquivo de cache manifest não mudou, o navegador nunca vai te avisar que um dos arquivos cacheados anteriormente mudou. Considere o exemplo a seguir:
CACHE MANIFEST
# rev 42
clock.js
clock.css
Se você mudou o arquivo clock.css
e publicou novamente, você
não vai ver mudanças, porque o arquivo de cache manifest não mudou. Toda
vez que você faz uma alteração em um dos arquivos da sua aplicação web
offline, você vai precisar mudar também o arquivo de cache manifest. Isso
pode ser tão fácil quanto mudar um caractere. A maneira mais fácil que
encontrei para fazer isso, é incluir uma linha de comentário com um número
de revisão. Mude o número da revisão no comentário e, então, o servidor
irá entregar as mudanças dos arquivos listados no arquivo de cache
manifest, seu navegador irá perceber que o conteúdo do arquivo mudou e irá
iniciar o processo de baixar novamente os arquivos listados no arquivo
manifest.
CACHE MANIFEST
# rev 43
clock.js
clock.css
❧
Lembra-se do jogo Halma que apresentei no capítulo de canvas, e depois foi melhorado salvando o estado com persistência de armazenamento local? Vamos deixar nosso jogo, Halma, offline.
Para fazer isso, precisamos de um arquivo manifest que liste todos os
arquivos que o jogo precisa acessar. Bem, temos a página principal em
HTML, um único arquivo JavaScript que contém todo o código do
jogo e… só. Não existem imagens, porque todos os desenhos são feitos
programaticamente via canvas API. Todo o CSS necessário está em um elemento
<style>
, no topo da página HTML. Então,
nosso arquivo de cache manifest fica assim:
CACHE MANIFEST
halma.html
../halma-localstorage.js
Uma palavrinha sobre caminhos. Criei um subdiretório
offline/
no diretório examples/
, e este arquivo
de cache manifest mora dentro desse subdiretório. Devido a página
HTML, vamos precisar acrescentar uma coisinha para que
funcione offline (mais sobre isso em um minuto), criei também uma cópia
separada do arquivo HTML, que também mora dentro do
subdiretório offline/
. Porém, graças a não haver mudanças no
código JavaScript,
adicionamos suporte a armazenamento local, então estou literalmente reutilizando o mesmo arquivo .js
,
que mora no diretório pai (examples/
). Todos juntos, os
arquivos parecem com essa estrutura:
/examples/localstorage-halma.html /examples/halma-localstorage.js /examples/offline/halma.manifest /examples/offline/halma.html
No arquivo de cache manifest
(/examples/offline/halma.manifest
), nós queremos referenciar
dois arquivos. Primeiro, a versão offline do
HTML (/examples/offline/hamla.html
). Desde que
estes dois arquivos estejam no mesmo diretório, será listado no arquivo de
manifest sem qualquer prefixo de caminho. Segundo, o arquivo JavaScript
que mora no diretório pai (/examples/hamla-localstorage.js
).
Este está listado no arquivo de manifest usando notação de
URL relativa: ../halma-localstorage.js
. Isso
está do jeito que você deve usar uma URL em um atributo
<img src>
. Como você verá no próximo exemplo, também é
possível usar caminhos absolutos (que começa na raiz do domínio atual) ou
até URLs absolutas (que apontam arquivos em outros domínios).
Agora, no arquivo HTML, precisamos adicionar o atributo
manifest
que aponta para o arquivo de cache manifest.
<!DOCTYPE html>
<html lang="en" manifest="halma.manifest">
Pronto! Quando um navegador de suporte offline carregar pela primeira vez a página HTML com suporte offline habilitado, será baixado o arquivo de cache manifest e, também baixar todos os arquivos referenciados, armazenando todos no cache da aplicação offline. Deste momento em diante, o algorítmo offline da aplicação tomará conta de tudo, sempre que a página for visitada. Você pode jogar offline, e já que o jogo lembra de seu estado localmente, você pode sair e voltar quantas vezes quiser.
Padrões:
Documentação de browser vendors:
Tutoriais e demos:
❧
Este foi “Vamos Tornar Isso Offline” O Sumário tem muito mais, se você quiser continuar a leitura.
Em parceria com Google Press, O’Reilly está distribuindo este livro e uma variadade de formatos, incluindo papel, ePub, Mobi e PDF sem DRM. A versão paga é chamada “HTML5: Up & Running,” e está disponível agora. Este capítulo está incluso na edição paga.
Se você gostar deste capítulo e quiser demonstrar, você pode comprar “HTML5: Up & Running” com este link afiliado ou comprar a edição eletrônica diretamente com a O’Reilly. Você irá ter o livro, e eu terei um trocado. Atualmente não aceito doações diretas.
Copyright MMIX–MMXI Mark Pilgrim