# 📘 SPA e PWA — Single Page Application e Progressive Web App ## Material Completo para Concursos — Estilo IDECAN > **Banca:** IDECAN | **Área:** Tecnologia da Informação | **Nível:** Analista > > ⚡ **Perfil da Banca:** Citado literalmente no edital UNILAB 2026. Prioridade **média** no Bloco 1 (Dev Core). A IDECAN cobra diferenças conceituais SPA×MPA×PWA, os 3 componentes obrigatórios do PWA, ciclo de vida do Service Worker e estratégias de cache por cenário. --- ## 📋 Índice 1. [MPA — Multi-Page Application](#1-mpa--multi-page-application-modelo-tradicional) 2. [SPA — Single Page Application](#2-spa--single-page-application) 3. [MPA vs SPA — Comparativo](#3-mpa-vs-spa--comparativo) 4. [SSR, SSG e Hydration](#4-ssr-ssg-e-hydration) 5. [Client-Side Routing e Code Splitting](#5-client-side-routing-e-code-splitting) 6. [PWA — Progressive Web App](#6-pwa--progressive-web-app) 7. [Service Worker — Ciclo de Vida](#7-service-worker--ciclo-de-vida) 8. [Web App Manifest](#8-web-app-manifest) 9. [Estratégias de Cache](#9-estratégias-de-cache) 10. [Pegadinhas e Pontos-Chave da IDECAN](#10-pegadinhas-e-pontos-chave-da-idecan) 11. [Questões Comentadas no Estilo IDECAN](#11-questões-comentadas-no-estilo-idecan) --- ## 1. MPA — Multi-Page Application (modelo tradicional) ### Como funciona No modelo **MPA**, cada navegação gera uma requisição HTTP ao servidor, que responde com uma página HTML **completa**. O navegador descarrega a página atual e carrega a nova inteiramente. ``` Usuário clica em link → Requisição HTTP ao servidor → Servidor gera e retorna HTML completo → Navegador recarrega a página inteira (flash branco) → Nova página é exibida ``` ### Características - Cada URL corresponde a um arquivo/rota no servidor que retorna HTML completo - Recarregamento total a cada navegação - SEO **nativo** — o servidor entrega HTML pronto para os crawlers - Mais simples de desenvolver para casos básicos - **Exemplos:** sistemas em PHP + Blade, JSP, Django templates, Ruby on Rails --- ## 2. SPA — Single Page Application ### Como funciona No modelo **SPA**, uma única página HTML é carregada na primeira visita com todo o JavaScript da aplicação. Navegações subsequentes são feitas via **JavaScript** (AJAX/Fetch) — só os dados mudam, a página **não é recarregada**. ``` Primeira visita: → Baixa app completa (HTML + JS bundle + CSS) → Renderiza UI inicial Navegações seguintes: → JS intercepta o clique no link → Busca apenas os dados necessários (JSON via API) → Atualiza apenas as partes do DOM que mudaram → URL muda via History API (sem req. ao servidor) ``` ### Frameworks SPA Populares - **React** (Meta/Facebook) — biblioteca de UI, Virtual DOM - **Angular** (Google) — framework completo, TypeScript - **Vue.js** — framework progressivo, MVVM - **Svelte** — compila para JS puro (sem Virtual DOM em runtime) ### SPA e Back-end — Separação de Responsabilidades ``` ┌─────────────────────────────┐ API REST/GraphQL ┌──────────────────────────┐ │ Front-end SPA │ ←────────────────────→ │ Back-end (API) │ │ React / Vue / Angular │ JSON via Fetch │ Spring Boot / Laravel │ │ - Renderiza UI │ │ - Retorna JSON │ │ - Gerencia estado │ │ - NÃO gera HTML │ │ - Roteamento no cliente │ │ - Reutilizável │ └─────────────────────────────┘ └──────────────────────────┘ ``` O back-end torna-se uma **API pura** — o mesmo back-end pode servir a SPA, apps mobile e terceiros. --- ## 3. MPA vs SPA — Comparativo | Característica | MPA | SPA | |---|---|---| | **Carregamento inicial** | Rápido (só a página atual) | Lento (baixa app inteira) | | **Navegação posterior** | Lenta (recarrega tudo) | Rápida (só dados JSON) | | **SEO** | Nativo (HTML pronto no servidor) | Desafiador (HTML gerado no cliente) | | **Experiência do usuário** | Flash a cada navegação | Fluida, sem recarregamento | | **Complexidade back-end** | Alta (gera HTML completo) | Baixa (só retorna JSON) | | **Complexidade front-end** | Baixa | Alta (framework JS obrigatório) | | **Roteamento** | Servidor | Cliente (History API) | | **Estado da aplicação** | No servidor (sessão) | No cliente (Redux, Zustand) | | **Exemplos** | PHP + Blade, JSP, Django | React, Angular, Vue | > ⚠️ **IDECAN cobra:** No SPA, o carregamento **inicial** é mais **lento** (baixa toda a aplicação JS). As navegações **subsequentes** são mais rápidas. O SEO é o principal **desafio** das SPAs — o HTML inicial está quase vazio, dificultando indexação por buscadores. --- ## 4. SSR, SSG e Hydration ### Por que existem — O problema de SEO do SPA O HTML inicial de uma SPA é quase vazio: ```html <!-- HTML inicial de uma SPA típica --> <html> <body> <div id="root"></div> <!-- vazio! --> <script src="/bundle.js"></script> <!-- conteúdo gerado pelo JS --> </body> </html> ``` Os crawlers de busca (Google, Bing) têm dificuldade para indexar conteúdo gerado por JavaScript. ### SSR — Server-Side Rendering O servidor **pré-renderiza** o HTML da SPA antes de enviar ao cliente. O usuário vê o conteúdo imediatamente e o JS assume o controle depois (hydration). ``` Cliente solicita /produto/123 → Servidor executa React/Vue no servidor → Gera HTML completo com os dados do produto → Envia HTML pronto ao cliente (SEO + velocidade) → JS do cliente faz hydration (torna a página interativa) ``` **Frameworks SSR:** Next.js (React), Nuxt.js (Vue), Angular Universal, SvelteKit ### SSG — Static Site Generation O HTML é gerado em **build-time** (não a cada requisição). Arquivos estáticos servidos por CDN — muito rápido. ``` Build: npm run build → gera /produto/1.html, /produto/2.html... Deploy: arquivos estáticos no CDN Requisição: CDN retorna HTML pré-gerado instantaneamente ``` **Ideal para:** blogs, documentação, landing pages (conteúdo que muda raramente). ### Hydration Processo onde o JavaScript do framework "ativa" o HTML estático pré-renderizado pelo servidor, tornando-o **interativo**. ``` 1. Servidor envia HTML pré-renderizado (página visível imediatamente) 2. Navegador recebe e exibe o HTML 3. JS da aplicação é baixado e executado 4. Framework "hidrata" — vincula eventos ao HTML existente 5. Página torna-se interativa (cliques, formulários funcionam) ``` > ⚠️ **IDECAN cobra:** SSR resolve o problema de SEO das SPAs gerando HTML no servidor. Next.js é o framework SSR mais cobrado no contexto de React. --- ## 5. Client-Side Routing e Code Splitting ### History API — Roteamento no Cliente ```javascript // O SPA usa a History API do navegador para mudar URLs sem recarregar // Adiciona uma entrada no histórico de navegação history.pushState({ pagina: 'produtos' }, '', '/produtos'); // Substitui a entrada atual (sem criar nova entrada no histórico) history.replaceState({ pagina: 'home' }, '', '/'); // Evento disparado ao clicar "Voltar"/"Avançar" no navegador window.addEventListener('popstate', (event) => { console.log('Navegou para:', event.state); }); ``` ### React Router — Roteamento em React ```jsx import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; function App() { return ( <BrowserRouter> {/* Link não recarrega a página — usa pushState internamente */} <Link to="/produtos">Produtos</Link> <Link to="/sobre">Sobre</Link> <Routes> <Route path="/" element={<Home />} /> <Route path="/produtos" element={<ListaProdutos />} /> <Route path="/produto/:id" element={<DetalheProduto />} /> <Route path="*" element={<PaginaNaoEncontrada />} /> </Routes> </BrowserRouter> ); } // Ao clicar no Link, a URL muda mas a página NÃO é recarregada ``` ### Code Splitting — Dividindo o Bundle **Problema:** SPAs podem ter bundles JS enormes (MBs), tornando o carregamento inicial muito lento. **Solução:** dividir o código em partes (chunks) que são baixadas **sob demanda**. ```jsx import React, { lazy, Suspense } from 'react'; // Carregamento lazy — o módulo só é baixado quando a rota é acessada const DetalheProduto = lazy(() => import('./pages/DetalheProduto')); const Relatorios = lazy(() => import('./pages/Relatorios')); function App() { return ( <BrowserRouter> <Suspense fallback={<div>Carregando...</div>}> <Routes> <Route path="/produto/:id" element={<DetalheProduto />} /> <Route path="/relatorios" element={<Relatorios />} /> </Routes> </Suspense> </BrowserRouter> ); } // DetalheProduto.js só é baixado quando o usuário navega para /produto/... ``` --- ## 6. PWA — Progressive Web App ### O que é PWA **PWA (Progressive Web App)** é um conjunto de **tecnologias e padrões** que permitem que uma aplicação web ofereça experiência similar a um app nativo: funciona offline, pode ser instalada na tela inicial e recebe notificações push. Termo cunhado por Alex Russell (Google) em 2015. ### Os 4 Pilares do PWA | Pilar | Descrição | |---|---| | **Confiável** | Funciona offline ou com rede instável. Service Worker cacheia recursos essenciais. | | **Rápido** | Responde imediatamente às interações. Assets cacheados localmente. | | **Envolvente (Engaging)** | Instalável na tela inicial. Push Notifications. Fullscreen. Experiência app-like. | | **Segura** | HTTPS obrigatório. Service Worker só funciona em origens seguras. | ### Os 3 Componentes Obrigatórios do PWA ⭐ ``` PWA = HTTPS + Service Worker + Web App Manifest ``` 1. **HTTPS** — obrigatório para segurança; pré-requisito para o Service Worker funcionar 2. **Service Worker** — script em background que habilita offline e cache 3. **Web App Manifest** — arquivo JSON que permite instalação e define aparência > ⚠️ **IDECAN cobra:** Os 3 componentes são **HTTPS + Service Worker + Web App Manifest**. A ausência de qualquer um impede que a aplicação seja classificada como PWA completo. HTTPS é pré-requisito para o Service Worker funcionar. ### PWA vs App Web vs App Nativo | Característica | App Web | PWA | App Nativo | |---|---|---|---| | **Funciona offline** | Não | Sim | Sim | | **Instalável** | Não | Sim (tela inicial) | Sim (App Store) | | **Push Notifications** | Não | Sim | Sim | | **Distribuição** | URL | URL (sem App Store) | App Store / Play Store | | **Atualização** | Automática | Automática | Manual (aprovação) | | **Acesso a hardware** | Limitado | Parcial (câmera, GPS) | Completo | | **Performance** | Menor | Boa | Máxima | > ⚠️ **IDECAN cobra:** PWA **não precisa** de App Store/Play Store para ser instalado — é instalado diretamente pelo navegador a partir da URL. Esta é uma das principais vantagens sobre apps nativos. --- ## 7. Service Worker — Ciclo de Vida ### O que é Service Worker Script JavaScript que roda em uma **thread separada** da página (background), **sem acesso ao DOM**. Atua como um **proxy de rede** — intercepta todas as requisições feitas pela aplicação e decide o que fazer: buscar da rede, retornar do cache, ou combinar ambos. ### Características Importantes - Roda em **background**, mesmo com a página fechada - **Não tem acesso ao DOM** — usa `postMessage` para comunicar com a página - Só funciona em **HTTPS** (exceto localhost para desenvolvimento) - É um Worker baseado em **eventos** (event-driven) - Tem acesso à **Cache API** para armazenar requisições/respostas ### Ciclo de Vida Completo ⭐ #### Fase 1 — Registration (Registro) ```javascript // Na página principal (index.html ou App.js) if ('serviceWorker' in navigator) { navigator.serviceWorker .register('/sw.js') // caminho para o arquivo do SW .then(reg => console.log('SW registrado, escopo:', reg.scope)) .catch(err => console.error('Falha no registro:', err)); } ``` #### Fase 2 — Install (Instalação) — momento do pre-caching ```javascript // Dentro do arquivo sw.js const CACHE_NAME = 'meu-app-v1'; const ARQUIVOS_PARA_CACHE = [ '/', '/index.html', '/app.js', '/styles.css', '/icons/logo.png' ]; self.addEventListener('install', event => { console.log('SW: instalando...'); event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('SW: realizando pre-caching dos arquivos essenciais'); return cache.addAll(ARQUIVOS_PARA_CACHE); }) ); // self.skipWaiting() força ativação imediata (pula a espera) }); ``` #### Fase 3 — Activate (Ativação) — momento da limpeza ```javascript self.addEventListener('activate', event => { console.log('SW: ativando...'); event.waitUntil( caches.keys().then(nomesDeCache => Promise.all( nomesDeCache .filter(nome => nome !== CACHE_NAME) // caches de versões antigas .map(nome => { console.log('SW: removendo cache antigo:', nome); return caches.delete(nome); }) ) ) ); // self.clients.claim() faz o SW assumir controle imediatamente }); ``` #### Fase 4 — Fetch (Operação Normal) — interceptação de requisições ```javascript self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(respostaDoCche => { if (respostaDoCche) { return respostaDoCche; // retorna do cache } return fetch(event.request); // busca na rede }) ); }); ``` ### Outros Eventos do Service Worker | Evento | Quando dispara | Uso | |---|---|---| | `push` | Mensagem push recebida do servidor | Exibir notificação push | | `notificationclick` | Usuário clica na notificação | Abrir URL específica | | `sync` | Conexão restabelecida | Background Sync — enviar dados enfileirados offline | | `message` | Página envia postMessage | Comunicação bidirecional com a página | ### Resumo do Ciclo de Vida ``` Register → Install (pre-caching) → Activate (limpar caches antigos) ↓ Fetch (interceptar requisições) Push (notificações) Sync (background sync) ``` > ⚠️ **IDECAN cobra:** A ordem é **Register → Install → Activate → Fetch**. O evento **install** é para **pre-caching**. O evento **activate** é para **limpeza de caches antigos**. O evento **fetch** intercepta requisições em operação normal. --- ## 8. Web App Manifest ### O que é Arquivo **JSON** (`manifest.json`) que fornece informações sobre o PWA ao navegador e ao SO: nome, ícones, cores, modo de exibição. Permite que o usuário **instale o app** na tela inicial com aparência nativa. ### Exemplo Completo ```json { "name": "Meu App Completo", "short_name": "MeuApp", "description": "Aplicação PWA de exemplo para concurso", "start_url": "/", "scope": "/", "display": "standalone", "orientation": "portrait", "background_color": "#ffffff", "theme_color": "#1D9E75", "lang": "pt-BR", "icons": [ { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }, { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" } ], "shortcuts": [ { "name": "Novo Pedido", "url": "/pedidos/novo", "icons": [{ "src": "/icons/new.png", "sizes": "96x96" }] } ] } ``` ### Propriedade `display` — Modos de Exibição ⭐ | Valor | Descrição | Uso | |---|---|---| | **`standalone`** | Remove barra de endereço. Mantém barra de status do SO. Parece app nativo. | **Mais comum em PWAs** | | `fullscreen` | Remove toda a UI do navegador e do SO. Tela inteira. | Jogos | | `minimal-ui` | Controles mínimos de navegação (voltar, recarregar). Sem barra de endereço. | Intermediário | | `browser` | Abre no navegador normalmente, com interface completa. | Padrão — sem experiência app-like | > ⚠️ **IDECAN cobra:** O modo **`standalone`** é o que dá a experiência "app-like" ao PWA — remove a barra de endereço do navegador. É o valor mais cobrado. `fullscreen` é para jogos e remove absolutamente tudo. ### Como Referenciar no HTML ```html <!-- No <head> do index.html --> <link rel="manifest" href="/manifest.json"> <meta name="theme-color" content="#1D9E75"> <!-- Meta tags para iOS (Safari tem suporte parcial ao manifest) --> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="MeuApp"> <link rel="apple-touch-icon" href="/icons/icon-192.png"> ``` --- ## 9. Estratégias de Cache ### Cache API — Armazenamento de Requisições ```javascript // Abrir/criar um cache pelo nome const cache = await caches.open('meu-cache-v1'); // Armazenar uma resposta manualmente await cache.put(request, response); // Buscar e armazenar automaticamente await cache.add('/pagina.html'); await cache.addAll(['/app.js', '/styles.css', '/logo.png']); // Buscar no cache const resposta = await cache.match(request); // Remover um item await cache.delete(request); // Listar todos os caches existentes const nomesDosCaches = await caches.keys(); // Deletar um cache inteiro await caches.delete('meu-cache-v1'); ``` ### As 5 Estratégias de Cache ⭐ #### 1. Cache First (cache → rede) Busca no cache primeiro. Se não encontrar, vai à rede. Ideal para assets **estáticos** que raramente mudam. ```javascript self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(cached => { return cached || fetch(event.request).then(response => { // opcional: salvar no cache ao buscar da rede caches.open(CACHE_NAME).then(cache => cache.put(event.request, response.clone())); return response; }); }) ); }); ``` **Quando usar:** imagens, fontes, CSS, JS da aplicação, ícones. #### 2. Network First (rede → cache) Tenta a rede primeiro. Se falhar (offline), usa o cache como fallback. ```javascript self.addEventListener('fetch', event => { event.respondWith( fetch(event.request) .then(response => { // salva a resposta no cache para uso offline const responseClone = response.clone(); caches.open(CACHE_NAME).then(cache => cache.put(event.request, responseClone)); return response; }) .catch(() => caches.match(event.request)) // fallback offline ); }); ``` **Quando usar:** feeds de notícias, dados de perfil, conteúdo dinâmico que precisa estar atualizado. #### 3. Stale While Revalidate Retorna do cache **imediatamente** (rápido) e, em paralelo, atualiza o cache com a versão mais recente da rede. Na próxima requisição, o conteúdo já estará atualizado. ```javascript self.addEventListener('fetch', event => { event.respondWith( caches.open(CACHE_NAME).then(cache => cache.match(event.request).then(cached => { // atualiza o cache em segundo plano const networkFetch = fetch(event.request).then(response => { cache.put(event.request, response.clone()); return response; }); // retorna o cache imediatamente (se existir) ou aguarda a rede return cached || networkFetch; }) ) ); }); ``` **Quando usar:** avatares de usuário, páginas que mudam com frequência moderada, APIs que toleram dados ligeiramente desatualizados. #### 4. Cache Only Sempre usa o cache. Nunca vai à rede. Para recursos **pre-cacheados** no install que não mudam. ```javascript self.addEventListener('fetch', event => { event.respondWith(caches.match(event.request)); }); ``` **Quando usar:** app shell (HTML/CSS/JS core), assets de versão fixada. #### 5. Network Only Sempre usa a rede. Nunca cacheia. Para requisições que **não devem** ser cacheadas. ```javascript self.addEventListener('fetch', event => { event.respondWith(fetch(event.request)); }); ``` **Quando usar:** analytics, pagamentos, dados em tempo real críticos, requisições POST de escrita. ### Tabela de Decisão — Qual Estratégia Usar? | Cenário | Estratégia Recomendada | |---|---| | Imagens, fontes, CSS, JS | Cache First | | Feed de notícias, dados dinâmicos | Network First | | Perfil do usuário, thumbnails | Stale While Revalidate | | HTML/CSS do app shell (core) | Cache Only | | Pagamentos, analytics, POST | Network Only | | Offline + dados mais recentes possíveis | Network First | | Velocidade máxima + eventual atualização | Stale While Revalidate | > ⚠️ **IDECAN cobra:** Questões apresentam cenários e pedem qual estratégia aplicar. "Usuário offline, precisa ver último conteúdo" → **Network First**. "Assets estáticos, raramente mudam" → **Cache First**. "Equilíbrio velocidade + atualização" → **Stale While Revalidate**. ### Workbox — Biblioteca do Google para Service Workers ```javascript import { registerRoute } from 'workbox-routing'; import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies'; import { ExpirationPlugin } from 'workbox-expiration'; // Imagens — Cache First com expiração de 30 dias registerRoute( ({ request }) => request.destination === 'image', new CacheFirst({ cacheName: 'imagens', plugins: [new ExpirationPlugin({ maxAgeSeconds: 30 * 24 * 60 * 60 })] }) ); // API REST — Network First registerRoute( ({ url }) => url.pathname.startsWith('/api/'), new NetworkFirst({ cacheName: 'api-cache' }) ); // CSS e JS — Stale While Revalidate registerRoute( ({ request }) => request.destination === 'style' || request.destination === 'script', new StaleWhileRevalidate({ cacheName: 'assets' }) ); ``` --- ## 10. Pegadinhas e Pontos-Chave da IDECAN ### ❌ Afirmações FALSAS (distratores clássicos) 1. ~~"No SPA, o carregamento inicial é mais rápido que no MPA"~~ → **FALSO**. O carregamento **inicial** do SPA é mais **lento** (baixa toda a aplicação JS). As navegações **subsequentes** são mais rápidas. 2. ~~"Um PWA precisa ser publicado na App Store ou Google Play para ser instalado"~~ → **FALSO**. PWA é instalado **diretamente pelo navegador** a partir da URL, sem loja de apps. 3. ~~"O Service Worker tem acesso direto ao DOM para manipulá-lo"~~ → **FALSO**. Service Worker **não tem acesso ao DOM** — roda em thread separada. Para comunicar com a página usa **`postMessage`**. 4. ~~"Service Workers podem ser registrados em origens HTTP simples"~~ → **FALSO**. Service Workers **só funcionam em HTTPS** (exceto localhost para desenvolvimento). 5. ~~"O evento 'install' do SW é o momento para limpar caches antigos"~~ → **FALSO**. Limpeza de caches antigos deve ocorrer no **'activate'**. O **'install'** é para **pre-caching** dos arquivos essenciais. 6. ~~"O modo 'fullscreen' no manifest é o mais usado para dar experiência app-like"~~ → **FALSO**. O modo mais comum em PWAs é **'standalone'**. `fullscreen` é para jogos. 7. ~~"Cache First é ideal para APIs REST com dados dinâmicos"~~ → **FALSO**. Cache First é para **assets estáticos**. Para APIs dinâmicas usa-se **Network First** ou Stale While Revalidate. 8. ~~"SPA e PWA são a mesma coisa"~~ → **FALSO**. São conceitos **independentes e complementares**. SPA = arquitetura de navegação. PWA = conjunto de tecnologias para offline/app-like. Um SPA pode ou não ser um PWA. 9. ~~"O carregamento SSR é exclusivo de MPAs — SPAs não podem usar SSR"~~ → **FALSO**. **Next.js** e **Nuxt.js** fazem SSR de SPAs React e Vue, respectivamente, resolvendo o problema de SEO. 10. ~~"Service Worker é um componente opcional do PWA"~~ → **FALSO**. Service Worker é um dos **3 componentes obrigatórios** — sem ele não há offline e a aplicação não é um PWA completo. ### ✅ Afirmações VERDADEIRAS (fixe!) 1. Os 3 componentes obrigatórios do PWA são **HTTPS + Service Worker + Web App Manifest**. 2. O ciclo de vida do Service Worker é **Register → Install → Activate → Fetch**. 3. O evento **`install`** é o momento do **pre-caching** (cachear assets essenciais). 4. O evento **`activate`** é o momento de **limpar caches antigos**. 5. O modo **`standalone`** no manifest remove a barra de endereço e dá experiência app-like. 6. SPA tem SEO desafiador porque o HTML inicial está quase vazio — conteúdo é gerado por JS no cliente. 7. **Next.js** resolve o SEO das SPAs React usando SSR (Server-Side Rendering). 8. **Stale While Revalidate**: retorna do cache imediatamente E atualiza o cache em segundo plano. 9. PWA não requer App Store — é instalado pelo navegador diretamente a partir da URL. 10. Service Worker só funciona em **HTTPS** (ou localhost para desenvolvimento). 11. **Code splitting** divide o bundle JS em chunks carregados sob demanda — reduz tempo de carregamento inicial do SPA. 12. No Web App Manifest, o campo **`start_url`** define qual URL abre quando o usuário lança o app instalado. --- ## 11. Questões Comentadas no Estilo IDECAN --- ### Questão 1 **Qual é a principal diferença entre SPA e MPA no carregamento de páginas?** - A) No SPA, cada navegação gera uma requisição HTTP que retorna HTML completo do servidor. - B) No SPA, uma única página HTML é carregada inicialmente e o JS atualiza o DOM com dados via AJAX; no MPA, cada navegação recarrega a página completa do servidor. - C) SPA e MPA são equivalentes — a diferença é apenas o framework utilizado. - D) No SPA, o SEO é mais eficiente que no MPA porque o conteúdo é gerado no cliente. - E) No MPA, o JavaScript controla toda a navegação sem recarregar páginas. <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: B** **Comentário:** No SPA, uma única página HTML é carregada com todo o JavaScript. Navegações subsequentes atualizam apenas partes do DOM via AJAX/Fetch, sem recarregar a página. No MPA, cada clique gera uma requisição HTTP ao servidor que retorna HTML completo — a página recarrega inteiramente. O SEO é o principal **desafio** (não vantagem) do SPA, pois o HTML inicial está quase vazio. </details> --- ### Questão 2 **Quais são os 3 componentes obrigatórios para que uma aplicação seja classificada como PWA completa?** - A) React.js, Service Worker e localStorage - B) HTTPS, Service Worker e Web App Manifest - C) Service Worker, WebSocket e IndexedDB - D) Web App Manifest, Push Notifications e HTTPS - E) Angular, Service Worker e Cache API <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: B** **Comentário:** Os 3 componentes obrigatórios são: (1) **HTTPS** — obrigatório para segurança e pré-requisito do Service Worker; (2) **Service Worker** — proxy de rede que habilita offline e cache; (3) **Web App Manifest** — arquivo JSON que permite instalação e define aparência app-like. React, WebSocket, Push Notifications e IndexedDB são opcionais. A alternativa D troca Service Worker por Push Notifications, que é apenas uma funcionalidade do SW. </details> --- ### Questão 3 **Sobre o Service Worker, assinale a alternativa CORRETA:** - A) O Service Worker tem acesso direto ao DOM para atualizar elementos da página. - B) O Service Worker pode ser registrado em origens HTTP simples para facilitar o desenvolvimento. - C) O Service Worker roda em thread separada, sem acesso ao DOM, e intercepta requisições de rede. - D) O Service Worker substitui o localStorage para armazenamento persistente offline. - E) O Service Worker é executado na mesma thread da página, compartilhando o contexto JavaScript. <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: C** **Comentário:** O Service Worker roda em uma thread separada (background), completamente independente da página. **Não tem acesso ao DOM** — usa `postMessage` para comunicar com a página. Intercepta requisições de rede (evento `fetch`) e decide o que retornar (cache ou rede). Só funciona em **HTTPS** (exceto localhost). Não é substituto do localStorage — é um proxy de rede com Cache API. </details> --- ### Questão 4 **No ciclo de vida do Service Worker, em qual evento deve ser realizado o pre-caching dos arquivos essenciais da aplicação?** - A) No evento `register` — antes de instalar o SW - B) No evento `install` — quando o SW é instalado pela primeira vez - C) No evento `activate` — quando o SW assume o controle das páginas - D) No evento `fetch` — quando a primeira requisição é interceptada - E) No evento `push` — quando uma notificação push é recebida <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: B** **Comentário:** O evento **`install`** é disparado quando o Service Worker é instalado pela primeira vez — é o momento ideal para o **pre-caching** dos arquivos essenciais (HTML, CSS, JS, ícones) usando `event.waitUntil()` com `caches.addAll()`. O evento **`activate`** é para limpar caches de versões anteriores. O evento **`fetch`** é para interceptar requisições durante o uso normal. </details> --- ### Questão 5 **Uma aplicação de notícias deve exibir conteúdo atualizado sempre que online, mas também mostrar as últimas notícias quando offline. Qual estratégia de cache é mais adequada?** - A) Cache First — retorna do cache, nunca vai à rede - B) Cache Only — usa apenas o cache pré-definido - C) Network First — tenta a rede primeiro, usa o cache como fallback quando offline - D) Stale While Revalidate — retorna do cache e atualiza em segundo plano - E) Network Only — sempre usa a rede, sem fallback <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: C** **Comentário:** **Network First** é a estratégia correta para conteúdo dinâmico (notícias) que precisa estar atualizado quando online, mas disponível offline. O SW tenta a rede primeiro — com conexão, retorna dados frescos e atualiza o cache. Sem conexão, usa o cache como fallback. Cache First priorizaria dados antigos mesmo com internet. Stale While Revalidate retornaria o cache imediatamente (possivelmente desatualizado) mesmo estando online. </details> --- ### Questão 6 **Sobre o campo `display` no Web App Manifest, qual valor remove a barra de endereço do navegador e dá ao PWA aparência de aplicativo nativo?** - A) `fullscreen` — remove toda a UI do navegador e do sistema operacional - B) `browser` — abre no navegador com interface completa - C) `standalone` — remove a barra de endereço mas mantém barra de status do SO - D) `minimal-ui` — exibe apenas controles básicos de navegação - E) `native` — emula completamente a experiência de app nativo <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: C** **Comentário:** **`standalone`** é o modo mais usado em PWAs — remove a barra de endereço do navegador, dando experiência app-like, mas mantém a barra de status do SO (horário, bateria). `fullscreen` remove **toda** a UI (inclusive SO) e é usado em jogos. `browser` é o padrão sem experiência app-like. `minimal-ui` mantém controles básicos de navegação. `native` não é um valor válido do manifest. </details> --- ### Questão 7 (Certo/Errado — estilo IDECAN) *"SPA e PWA são conceitos equivalentes — uma SPA é necessariamente uma PWA, pois ambas dispensam o recarregamento de página e oferecem experiência similar a aplicativos nativos."* <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: ERRADO** **Comentário:** SPA e PWA são conceitos **independentes e complementares**, não equivalentes. **SPA** é uma arquitetura de navegação — uma página HTML com roteamento no cliente via JavaScript. **PWA** é um conjunto de tecnologias (HTTPS + Service Worker + Manifest) que adiciona capacidades offline, instalação e notificações push. Uma SPA pode ser um PWA (Twitter Lite, por exemplo), mas não necessariamente. Uma MPA tradicional também pode ser um PWA se adicionar Service Worker e Manifest. São dimensões diferentes: SPA descreve *como a navegação funciona*; PWA descreve *quais capacidades a aplicação possui*. </details> --- ### Questão 8 (Certo/Errado) *"O evento `activate` do Service Worker é o momento recomendado para limpar caches de versões anteriores, pois nesta fase o SW já assumiu o controle das páginas e é seguro remover recursos que não serão mais usados."* <details> <summary>🔎 Ver resposta e comentário</summary> **✅ Resposta: CERTO** **Comentário:** Afirmação correta. O evento `activate` é disparado após o SW ser instalado e estar pronto para assumir o controle. É o momento ideal para remover caches de versões anteriores (ex: `meu-app-v1` quando a versão atual é `meu-app-v2`), garantindo que o espaço de armazenamento não seja desperdiçado com recursos obsoletos. O evento `install` (fase anterior) é para criar o novo cache com os arquivos da versão atual. Tentar deletar caches antigos no `install` pode causar problemas de concorrência com o SW anterior ainda em execução. </details> --- ## 📌 Resumo Visual — Comparativo Final ``` SPA PWA ┌──────────────────┐ ┌──────────────────┐ │ Uma página HTML │ │ HTTPS obrigatório│ │ Roteamento no JS │ │ Service Worker │ │ AJAX para dados │ │ Web App Manifest │ │ React/Vue/Angular│ │ Offline-first │ │ Desafio: SEO │ │ Instalável │ └──────────────────┘ └──────────────────┘ ↑ ↑ └──────────┬────────────────┘ │ Podem ser usados juntos (SPA + PWA) ou separadamente ``` --- ## 📚 Tabela de Referência Rápida | Conceito | Resumo | |---|---| | SPA | Uma página HTML + JS atualiza DOM via AJAX — sem recarregamento | | MPA | Cada navegação = nova requisição HTTP + HTML completo do servidor | | SEO no SPA | Desafiador (HTML inicial vazio) — solução: SSR com Next.js/Nuxt | | SSR | Servidor pré-renderiza HTML da SPA — combina SEO + experiência SPA | | Code Splitting | Divide bundle JS em chunks carregados sob demanda | | PWA | HTTPS + Service Worker + Web App Manifest | | Service Worker | Proxy de rede em thread separada, sem acesso ao DOM, só HTTPS | | SW — install | Pre-caching dos arquivos essenciais | | SW — activate | Limpeza de caches de versões antigas | | SW — fetch | Interceptação de requisições em operação normal | | Cache First | Cache → rede. Para assets estáticos. | | Network First | Rede → cache (fallback offline). Para dados dinâmicos. | | Stale While Revalidate | Cache imediato + atualiza em background. Para equilíbrio. | | manifest display | `standalone` = app-like (sem barra de endereço) | | PWA instalação | Via navegador, sem App Store / Play Store | | Workbox | Biblioteca Google que abstrai Service Worker e estratégias de cache | --- *Material elaborado com base no perfil de cobrança histórico da banca IDECAN (2006–2026).* *Última atualização: 2026*