Contexto Service Worker
- Tipo:
object
- Origem: Contexto Nullstack
- Disponibilidade: server/client
- readwrite no contexto do server
- readonly no contexto do client
Ele te dá controle granular do comportamento do seu PWA.
Chaves do worker
serão usadas para gerar o arquivo do service worker e devem ser atribuídas durante o processo de inicialização.
As seguintes chaves estão disponíveis no objeto durante a inicialização:
- enabled:
boolean
- preload:
string array
(relative paths) - headers:
object
- cdn:
string
(absolute url) - api:
string
(absolute url) - protocol:
string
(http or https)
A chave enabled
define se o service worker será registrado automaticamente pelo Nullstack.
Por padrão a chave enabled
é setada como true
no modo de produção e false
no modo de desenvolvimento.
O array preload
é composto por caminhos que serão cacheados quando o service worker for instalado.
Os assets requeridos para inicializar a aplicação serão pré-carregados automaticamente, e você deverá apenas as páginas extras que você quer que estejam disponíveis em modo offline.
import { readdirSync } from 'fs';
import Nullstack from "nullstack";
import path from 'path';
import Application from "./src/Application";
const context = Nullstack.start(Application);
const { worker } = context;
const articles = readdirSync(path.join(__dirname, '../i18n/en-US', 'articles'));
worker.preload = [
...articles.map((article) => '/' + article.replace('.md', '')),
...illustrations.map((illustration) => '/illustrations/' + illustration),
'/arrow.webp',
'/stars.webp',
'/documentation',
'/components'
// ...
]
export default context;
💡 O exemplo acima foi extraido deste repositório e permite que a documentação esteja totalmente acessível em modo offline.
As seguintes chaves estão disponíveis como readonly no contexto do cliente:
- enabled:
boolean
- preload:
string array
(relative paths) - online:
boolean
- fetching:
boolean
- responsive:
boolean
- installation:
BeforeInstallPromptEvent
- registration:
ServiceWorkerRegistration
- queues:
object
As seguintes chaves estão disponíveis como readwrite no contexto do cliente:
- headers:
object
A chave responsive
determina se a aplicação tem todas as respostas necessárias para renderizar a página atual.
O Nullstack irá tentar manter sua aplicação respondendo o maior tempo possível e setará a chave para false
somente quando não houver mais alternativas de recuperar qualquer resposta da rede ou offline usando a estratégia de busca para o ambiente.
A chave online
irá monitorar os eventos da rede e re-renderizar a aplicação quando o valor de navigator.onLine
mudar.
Quando a aplicação voltar a ficar online o Nullstack irá tentar fazer a aplicação responder novamente e re-renderizar se necessário.
import Nullstack from 'nullstack';
// ...
class Application extends Nullstack {
// ...
render({worker}) {
if(!worker.responsive) {
return <OfflineWarning />
}
return (
<main>
<Home route="/" />
</main>
)
}
}
Você pode acessar a registration e installation do service worker atual pela chave worker
para controlar o fluxo do seu PWA.
A chave registration
se refere ao registro do service worker e só estará disponível uma vez que o processo de registro esteja completo.
A chave installation
se refere a instalação delegada no evento do prompt e apenas estará disponível se o evento beforeinstallprompt
ocorrer.
import Nullstack from 'nullstack';
class PWAInstaller extends Nullstack {
installed = false;
hidden = false;
async prompt({worker}) {
try {
worker.installation.prompt();
const {outcome} = await worker.installation.userChoice;
if (outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
} finally {
this.hidden = true;
}
}
render({worker, project}) {
if(this.hidden) return false;
if(!worker.installation) return false;
return (
<div>
<img src={project.favicon} />
<p> Do you want to add {project.name} to your home screen?</p>
<button onclick={this.prompt}> Install </button>
<button onclick={{hidden: true}}> Not Now </button>
</div>
)
}
}
export default PWAInstaller;
Telas de Carregamento
Quando uma função do servidor é chamada o fetching
será setado como true
até a requisição ser resolvida.
Quando uma função do servidor é chamada uma chave com o nome da função do servidor invocada será setada no objeto queues
até a requisição ser resolvida.
A chave será um array com todos os argumentos passados para a função do servidor.
Qualquer chave que for chamada no objeto queues
sempre irá retornar um array ao invés de undefined
por consistência.
Quando o servidor estiver emulando o contexto do cliente para renderização no lado do servidor, todas as chaves de queues
vão sempre retornar um array vazio, pulando múltiplos ciclos de render por performance.
import Nullstack from 'nullstack';
class Page extends Nullstack {
static async save({ valid }) {
// ...
}
async submit() {
await this.save({ valid: true });
}
render({ worker }) {
const loadingValidSave = !!worker.queues.save
.find(args => args.valid);
return (
<form onsubmit={this.submit}>
{worker.fetching &&
<span> carregando... </span>
}
<button disabled={loadingValidSave}>
Salvar
</button>
</form>
)
}
}
export default Page;
Headers customizadas
Você pode usar a chave headers
para configurar as headers que o worker usará na requisição para uma função do servidor
🔥 headers serão ignorados quando uma função do servidor for chamada durante o processo de renderização do lado do servidor
import Nullstack from 'nullstack';
class LoginPage extends Nullstack {
// ...
async submit({worker}) {
// ...
this.headers['Authorization'] = `Bearer ${token}`;
// ...
}
static async authorize({request}) {
const authorization = request.headers['Authorization'];
// ...
}
// ...
}
export default LoginPage;
✨ Aprenda mais sobre o requisições e respostas do servidor
Estratégia de renderização Server-side
- Requisições de diferentes origens serão realizadas normalmente;
- Requisições diferentes do método GET serão realizadas normalmente;
- Assets com Fingerprints serão carregados no cache no momento da instalação;
- Assets com Fingerprints serão carregados do cache primeiro, e só então retornados para a rede, se necessário;
- Caminhos com uma extensão serão recuperados e atualizarão o cache em segundo plano para uma requisição subsequente;
- Os caminhos navegados serão carregados da rede e se falhar serão retornados do cache para a página na qual o
worker.responsive
e oworker.online
estiverem setados comofalse
;
Estratégia de geração de site estático
- Requisições de diferentes origens serão realizadas normalmente;
- Requisições diferentes do método GET serão realizadas normalmente;
- Assets com Fingerprints serão carregados no cache no momento da instalação;
- Assets com Fingerprints serão carregados do cache primeiro, e só então retornados para a rede, se necessário;
- Caminhos com uma extensão serão recuperaados e atualizarão o cache em segundo plano para uma requisição subsequente;
- A página inicial será carregada na rede primeiro, e se necessário será retornada uma cópia em cache;
- Caminhos navegados irão carregar apenas os dados da API estática e mesclar com o template da aplicação para gerar a resposta.
- Navegar para uma rota estática irá fazer cache apenas dos dados daquela página;
- Quando os dados estiverem indisponíveis no cache ou na rede irá retornar uma página na qual
worker.responsive
eworker.online
estiverem setados comofalse
;
Estratégia customizada
O Nullstack irá instalar automaticamente seu service worker se enabled
estiver setado como true
com os seguintes eventos:
install
activate
fetch
Você pode sobreescrever qualquer um desses eventos criando um service-worker.js na pasta public;
Se qualquer uma das palavras chaves acima for encontrada o Nullstack injetará sua função no código do service worker ao invés do padrão.
Por conveniência uma chave chamada context
é injetada no self
do service worker com as seguintes chaves:
worker
project
environment
function activate(event) {
event.waitUntil(async function() {
const cacheNames = await caches.keys();
const cachesToDelete = cacheNames.filter(cacheName => cacheName !== self.context.environment.key);
await Promise.all(cachesToDelete.map((cacheName) => caches.delete(cacheName)));
if (self.registration.navigationPreload) {
await self.registration.navigationPreload.enable();
}
self.clients.claim();
}());
}
self.addEventListener('activate', activate);
💡 O exemplo acima foi extraido do service worker gerado e usa
self.context.enviroment.key