blog

vite-plugin-pwa로 Vite 앱을 PWA로 만들기

Front-end / Tooling#Vite#PWA#Service Worker#Workbox

vite-plugin-pwa는 웹 앱 매니페스트와 서비스 워커(Workbox)를 빌드 시점에 함께 생성한다. 매니페스트 파일과 서비스 워커를 따로 손으로 만들어 등록할 필요가 없다.

1. 설치

npm install -D vite-plugin-pwa @vite-pwa/assets-generator

2. 아이콘 생성

로고 SVG 하나로 PWA에 필요한 아이콘 세트(64·192·512, maskable, apple-touch-icon)를 만든다.

// package.json
{
  "scripts": {
    "generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/logo.svg"
  }
}

3. 플러그인 설정

매니페스트는 별도 manifest.json 대신 플러그인 옵션에 적는다. 빌드하면 manifest.webmanifest가 생성되고 index.html에 링크가 자동으로 들어간다.

// vite.config.ts
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';

export default defineConfig({
  plugins: [
    VitePWA({
      registerType: 'autoUpdate',
      includeAssets: ['favicon.ico', 'apple-touch-icon-180x180.png'],
      manifest: {
        name: 'PROJECT_NAME',
        short_name: 'PROJECT_SHORT_NAME',
        description: 'PROJECT_DESCRIPTION',
        lang: 'ko',
        start_url: '/',
        scope: '/',
        display: 'standalone',
        orientation: 'portrait',
        background_color: '#ffffff',
        theme_color: '#ffffff',
        icons: [
          { src: 'pwa-64x64.png', sizes: '64x64', type: 'image/png' },
          { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' },
          { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
          { src: 'maskable-icon-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
        ],
      },
      workbox: {
        // 오프라인 상태에서 페이지 이동 시 보여줄 문서
        navigateFallback: '/index.html',
      },
    }),
  ],
});

prefer_related_applications: true는 넣지 않는다. 이 값은 "네이티브 앱을 우선 설치하라"는 뜻이라 PWA 설치 안내가 뜨지 않을 수 있다.

4. 서비스 워커 등록

registerType: 'autoUpdate'이면 플러그인이 등록 스크립트를 자동으로 주입한다. 등록 시점이나 업데이트 알림을 직접 제어하고 싶을 때만 가상 모듈을 사용한다.

// main.ts
import { registerSW } from 'virtual:pwa-register';

registerSW({ immediate: true });

5. HTTPS

서비스 워커는 보안 컨텍스트에서만 동작한다. localhost는 예외로 허용되지만, 같은 네트워크의 모바일 기기에서 IP로 접속해 테스트하려면 HTTPS가 필요하다. 로컬 인증서는 mkcert로 발급하는 방법이 가장 간단하다.

참고로 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">는 페이지 안의 http 요청을 https로 바꿔 Mixed Content를 막는 설정일 뿐, 사이트를 HTTPS로 만들어 주지는 않는다.