Zero-config PWA plugin for Vite that enables offline functionality, service workers, and web app manifest generation.
npx @tessl/cli install tessl/npm-vite-plugin-pwa@1.0.0Vite Plugin PWA is a zero-configuration Progressive Web App (PWA) plugin for Vite that provides comprehensive PWA support including automatic service worker generation, web app manifest injection, and framework integrations. It offers offline functionality via Workbox, built-in framework support for React, Vue, Svelte, SolidJS, and Preact, and PWA assets generation for icons and splash screens.
npm install vite-plugin-pwaimport { VitePWA } from "vite-plugin-pwa";For cache presets and constants:
import { VitePWA, cachePreset, defaultInjectManifestVitePlugins } from "vite-plugin-pwa";For TypeScript types:
import type { VitePWAOptions, ManifestOptions, RegisterSWOptions } from "vite-plugin-pwa";// vite.config.ts
import { defineConfig } from "vite";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [
VitePWA({
registerType: "autoUpdate",
workbox: {
globPatterns: ["**/*.{js,css,html,ico,png,svg}"],
},
manifest: {
name: "My PWA App",
short_name: "PWA App",
description: "My Progressive Web Application",
theme_color: "#ffffff",
icons: [
{
src: "pwa-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "pwa-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
}),
],
});Vite Plugin PWA is built around several key components:
VitePWA function returns array of Vite plugins (MainPlugin, InfoPlugin, BuildPlugin, DevPlugin, AssetsPlugin)generateSW (automatic) and injectManifest (custom)Main plugin factory function and configuration options for setting up PWA functionality in Vite applications.
function VitePWA(userOptions?: Partial<VitePWAOptions>): Plugin[];Framework-specific service worker registration modules that provide reactive integration with React, Vue, Svelte, SolidJS, and Preact applications.
// Virtual module: virtual:pwa-register
function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>;
// Framework-specific virtual modules return reactive state
function useRegisterSW(options?: RegisterSWOptions): {
needRefresh: ReactiveState<boolean>;
offlineReady: ReactiveState<boolean>;
updateServiceWorker: (reloadPage?: boolean) => Promise<void>;
};Virtual modules providing access to PWA information and generated assets for integrations and custom implementations.
// Virtual module: virtual:pwa-info
const pwaInfo: PwaInfo | undefined;
// Virtual module: virtual:pwa-assets/head
const pwaAssetsHead: PWAAssetsHead;
// Virtual module: virtual:pwa-assets/icons
const pwaAssetsIcons: PWAAssetsIcons;interface VitePWAOptions {
/** Build mode @default process.env.NODE_ENV or "production" */
mode?: 'development' | 'production';
/** @default 'public' */
srcDir?: string;
/** @default 'dist' */
outDir?: string;
/** @default 'sw.js' */
filename?: string;
/** @default 'manifest.webmanifest' */
manifestFilename?: string;
/** @default 'generateSW' */
strategies?: 'generateSW' | 'injectManifest';
/** The scope to register the Service Worker @default same as base of Vite's config */
scope?: string;
/** Service worker registration method @default 'auto' */
injectRegister?: 'inline' | 'script' | 'script-defer' | 'auto' | null | false;
/** Mode for the virtual register @default 'prompt' */
registerType?: 'prompt' | 'autoUpdate';
/** Minify the generated manifest @default true */
minify?: boolean;
/** The manifest object */
manifest?: Partial<ManifestOptions> | false;
/** Whether to add crossorigin="use-credentials" to manifest link @default false */
useCredentials?: boolean;
/** The workbox object for generateSW */
workbox?: Partial<GenerateSWOptions>;
/** The workbox object for injectManifest */
injectManifest?: Partial<CustomInjectManifestOptions>;
/** Override Vite's base options only for PWA @default base options from Vite */
base?: string;
/** Public resources to be added to the PWA manifest */
includeAssets?: string | string[];
/** Include manifest icons in service worker precache @default true */
includeManifestIcons?: boolean;
/** Disable service worker registration and generation @default false */
disable?: boolean;
/** Vite PWA Integration */
integration?: PWAIntegration;
/** Development options */
devOptions?: DevOptions;
/** Unregister the service worker @default false */
selfDestroying?: boolean;
/** Configure build path for Laravel integrations @default vite.base */
buildBase?: string;
/** PWA assets generation and injection @experimental */
pwaAssets?: PWAAssetsOptions;
/** Show maximumFileSizeToCacheInBytes warning @default false */
showMaximumFileSizeToCacheInBytesWarning?: boolean;
}
interface RegisterSWOptions {
immediate?: boolean;
onNeedRefresh?: () => void;
onOfflineReady?: () => void;
onRegistered?: (registration?: ServiceWorkerRegistration) => void;
onRegisteredSW?: (swScriptUrl: string, registration?: ServiceWorkerRegistration) => void;
onRegisterError?: (error: any) => void;
}
interface ManifestOptions {
/** @default _npm_package_name_ */
name?: string;
/** @default _npm_package_name_ */
short_name?: string;
/** @default _npm_package_description_ */
description?: string;
/** @default [] */
icons?: IconResource[];
/** File handlers configuration @default [] */
file_handlers?: {
action: string;
accept: Record<string, string[]>;
}[];
/** @default routerBase */
start_url?: string;
/** Restricts what web pages can be viewed while the manifest is applied */
scope?: string;
/** A string that represents the identity for the application */
id?: string;
/** @default 'standalone' */
display?: Display;
/** @default [] */
display_override?: DisplayOverride[];
/** Defines the default orientation for all the website's top-level */
orientation?: 'any' | 'natural' | 'landscape' | 'landscape-primary' | 'landscape-secondary' | 'portrait' | 'portrait-primary' | 'portrait-secondary';
/** @default '#42b883' */
theme_color?: string;
/** @default '#ffffff' */
background_color?: string;
/** @default 'en' */
lang?: string;
/** @default 'ltr' */
dir?: 'ltr' | 'rtl';
categories?: string[];
screenshots?: ScreenshotResource[];
shortcuts?: ShortcutResource[];
related_applications?: RelatedApplication[];
prefer_related_applications?: boolean;
}
interface IconResource {
src: string;
sizes?: string;
type?: string;
purpose?: 'monochrome' | 'maskable' | 'any' | string | ('monochrome' | 'maskable' | 'any')[];
}
type Display = 'fullscreen' | 'standalone' | 'minimal-ui' | 'browser';
type DisplayOverride = Display | 'window-controls-overlay';const cachePreset: RuntimeCaching[];
const defaultInjectManifestVitePlugins: string[];