Nuxt 3 e PWA
Tags: nuxt, vue, pwa, braziliandevs
Published: 2024-03-08 19:15:09

Sabemos que existem muitas maneiras de desenvolver aplicativos. Hoje, vamos falar sobre PWA, uma abordagem muito interessante tanto em termos de tecnologia quanto em custo-benefício.

Vamos agitar as coisas neste exemplo usando o framework front-end Nuxt 3 com PWA! 🚀

## 1º Etapa - Instalação.

Entre no seu projeto feito em nuxt3 e instale o PWA Vite Plugin em seu projeto.

```
npm i @vite-pwa/nuxt -D 
```

Adicione no `nuxt.config.ts` configure-o:

```
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
  modules: [
    '@vite-pwa/nuxt'
  ],
  pwa: {
    /* PWA options */
  }
})
```

## 2º Etapa  - Configurar manifest.

É hora de configurar seu projeto para PWA! Vou explicar detalhadamente cada parte que precisa ser configurada no seu projeto.

vamos começar com o **manifest** ele define critérios como resiliência, responsividade, conectividade e facilidade de instalação, permitindo que os desenvolvedores criem aplicativos que se comportem de forma semelhante a aplicativos nativos.

Dentro da pasta `public` crie uma pasta chamada `manifest` e adicione sua logo do projeto, as imagens devem conter o tamanho descrito dentro do **sizes**.

```
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
  modules: [
    '@vite-pwa/nuxt'
  ],
  pwa: {
   manifest: {
      name: 'nome do seu APP',
      short_name: 'nome simplificado do APP',
      theme_color: '#ffffff',
      start_url:'/',
      lang: 'pt-br',
      description: 'descrição do seu APP',
      screenshots: [
        {
          src: "manifest/home-screen.png",
          sizes: "320x320",
          type: "image/png",
          form_factor: "wide",
          label: "nome simplificado do APP"
        }
      ],
      icons: [
        {
          src: 'manifest/android-chrome-192x192.png',
          sizes: '192x192',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
      ],
    },
  }
})
```
Uma dica super legal é usar o site: https://realfavicongenerator.net/
Ele facilita todo o processo de configurar as medidas necessárias para suas imagens, tudo a partir do logo principal do seu projeto.

## 3º Etapa  - Configuração de strategies.

Na configuração de um PWA com o Workbox, existem duas estratégias principais que podem ser usadas para gerenciar o Service Worker:

**generateSW**: Esta estratégia é usada para gerar automaticamente um arquivo de Service Worker a partir de uma configuração simples. Ela é mais fácil de configurar, mas pode não oferecer o mesmo nível de controle que a estratégia injectManifest.

**injectManifest**: Esta estratégia permite injetar manualmente uma lista de arquivos para serem precacheados pelo Service Worker. Ela oferece um controle mais granular sobre quais arquivos são armazenados em cache, permitindo uma maior otimização do desempenho e uma experiência offline mais personalizada.

Neste exemplo iremos configurar na "mão" nossa estrategia para service workers, então usaremos o **injectManifest**.

Esta configuração indica que o método de injeção do manifest deve ser usado para gerar o service worker. O método de injeção do manifest permite que você adicione manualmente arquivos ao cache, dando mais controle sobre quais recursos são armazenados em cache. No exemplo dado, globPatterns define os padrões de arquivos que devem ser incluídos no cache. O padrão '**/*.{js,css,html,png,svg,ico}' significa que o Workbox deve considerar todos os arquivos com extensões .js, .css, .html, .png, .svg e .ico para o cache.

```
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
  modules: [
    '@vite-pwa/nuxt'
  ],
  pwa: {
   strategies:'injectManifest',
   srcDir: 'service-worker',
   filename: 'sw.ts',
   registerType: 'autoUpdate',
   manifest: {
      name: 'nome do seu APP',
      short_name: 'nome simplificado do APP',
      theme_color: '#ffffff',
      start_url:'/',
      lang: 'pt-br',
      description: 'descrição do seu APP',
      screenshots: [
        {
          src: "manifest/home-screen.png",
          sizes: "320x320",
          type: "image/png",
          form_factor: "wide",
          label: "nome simplificado do APP"
        }
      ],
      icons: [
        {
          src: 'manifest/android-chrome-192x192.png',
          sizes: '192x192',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
      ],
    },
    workbox: {
      globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
    },
    injectManifest: {
      globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
    },
  }
})
```
Criaremos a pasta chamada: `service-worker` com o arquivo: `sw.ts`

Dentro do arquivo `sw.ts`, iremos chamar o workbox é uma biblioteca JavaScript criada pelo google que simplifica o desenvolvimento de PWAs que utilizam Service Workers. 

Basicamente esse código **precacheAndRoute** do Workbox serve para precachear e rotear os recursos listados em **self.__WB_MANIFEST**, que é uma lista gerada automaticamente pelo Workbox durante a compilação.

Colocaremos esse código:
```
/// <reference lib="WebWorker" />
/// <reference types="vite/client" />

import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching'
import { clientsClaim } from 'workbox-core'
import { NavigationRoute, registerRoute } from 'workbox-routing'

declare let self: ServiceWorkerGlobalScope

precacheAndRoute(self.__WB_MANIFEST);

cleanupOutdatedCaches();

let allowlist: undefined | RegExp[]

if (import.meta.env.DEV)
  allowlist = [/^\/$/]

registerRoute(new NavigationRoute(
  createHandlerBoundToURL('/'),
  { allowlist },
))

self.skipWaiting();
clientsClaim();
```

**Observação:** Como estamos usando **typeScript** para escrever seu service worker personalizado. Para resolver os tipos de service workers, basta adicionar WebWorkera no seu `tsconfig.json` arquivo:

```
{
  "compilerOptions": {
    "lib": ["ESNext", "DOM", "WebWorker"]
  }
}
```

## 4º Etapa  - Configurar client e devOptions.

**Configurar client:** Esse trecho de código está relacionado à configuração de um cliente, indica que o aplicativo deve exibir o prompt de instalação quando for detectado que ele pode ser instalado no dispositivo do usuário.

**Configurar devOptions**: Habilita as opções de desenvolvimento. Define a rota de fallback para a navegação. Isso significa que se o servidor não encontrar um recurso específico, ele retornará o arquivo especificado, neste caso, a rota raiz.

```
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
  modules: [
    '@vite-pwa/nuxt'
  ],
  pwa: {
   strategies:'injectManifest',
   srcDir: 'service-worker',
   filename: 'sw.ts',
   registerType: 'autoUpdate',
   manifest: {
      name: 'nome do seu APP',
      short_name: 'nome simplificado do APP',
      theme_color: '#ffffff',
      start_url:'/',
      lang: 'pt-br',
      description: 'descrição do seu APP',
      screenshots: [
        {
          src: "manifest/home-screen.png",
          sizes: "320x320",
          type: "image/png",
          form_factor: "wide",
          label: "nome simplificado do APP"
        }
      ],
      icons: [
        {
          src: 'manifest/android-chrome-192x192.png',
          sizes: '192x192',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
        {
          src: 'manifest/android-chrome-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
      ],
    },
    workbox: {
      globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
    },
    injectManifest: {
      globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
    },
    client: {
      installPrompt: true,
      periodicSyncForUpdates: 20,
    },
    devOptions: {
      enabled: true,
      suppressWarnings: true,
      navigateFallback: '/',
      navigateFallbackAllowlist: [/^\/$/],
      type: 'module',
    },
  }
})
```

Quero agradecer a todos que chegaram ate aqui!
linkedin:
https://www.linkedin.com/in/helton-brito-856ba516b/