npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-offline

v0.0.0

Published

Zero-config offline support and update awareness for Vite apps

Readme

vite-plugin-offline

Small, framework-agnostic offline support for Vite apps. Load the app once, reopen it without a network connection, and tell users when a newer build is ready.

It precaches the complete production build, serves navigations network-first, and exposes typed connectivity and update state. It has no runtime dependencies and does not turn your app into an installable PWA.

Install

pnpm add -D vite-plugin-offline
// vite.config.ts
import { defineConfig } from "vite";
import offlineFirst from "vite-plugin-offline";

export default defineConfig({
  plugins: [offlineFirst()],
});

Build and serve the production output, visit it once online, then it can reopen offline:

pnpm exec vite build
pnpm exec vite preview

Service workers require HTTPS in production. localhost is allowed for development and previews. The plugin intentionally does not register a service worker in Vite's development server, where persistent caches tend to make HMR confusing.

Know when the app is offline or outdated

The plugin registers the service worker automatically. Import the client helpers anywhere in your app to drive UI or disable network-only features:

import {
  activateOfflineFirstUpdate,
  subscribeToOfflineFirst,
} from "vite-plugin-offline/client";

const unsubscribe = subscribeToOfflineFirst((state) => {
  offlineBanner.hidden = state.isOnline;
  updateButton.hidden = !state.isUpdateAvailable;
  readyBadge.hidden = !state.isOfflineReady;
});

updateButton.addEventListener("click", () => {
  // Activates the waiting build and reloads once it controls the page.
  void activateOfflineFirstUpdate();
});

The state contains:

  • isOnline: the browser's connectivity signal. Use it as a UI hint, not proof that a particular API is reachable.
  • isOfflineReady: the app shell has been installed and can be reopened offline.
  • isUpdateAvailable: a newer build is waiting. Prompting is the safe default because an automatic reload can discard form or application state.

For React, subscribe in an effect and keep the snapshot in state:

import { useEffect, useState } from "react";
import {
  getOfflineFirstState,
  subscribeToOfflineFirst,
} from "vite-plugin-offline/client";

export function ConnectionStatus() {
  const [status, setStatus] = useState(getOfflineFirstState);
  useEffect(() => subscribeToOfflineFirst(setStatus), []);

  if (!status.isOnline) return <p>You are offline. Network features are paused.</p>;
  if (status.isUpdateAvailable) return <p>A newer version is ready.</p>;
  return null;
}

subscribeToOfflineFirst returns an unsubscribe function. You can also call checkForOfflineFirstUpdate() manually or listen for the offline-first:update window event.

Caching behavior

  • Every emitted JS, CSS, HTML, and asset file is precached atomically.
  • Files copied from Vite's public/ directory are precached by default.
  • Navigations are network-first, then fall back to the cached URL or index.html.
  • Same-origin images, fonts, scripts, styles, media, manifests, and workers fetched at runtime are network-first cached.
  • API requests, non-GET requests, and cross-origin requests are not cached by default.
  • New builds wait until the user activates them. Old caches are removed only inside this plugin instance's namespace.

This keeps a static breath pacer, calculator, reference tool, or similar client-side app available after its first successful load. Server data is a separate concern: store user data in IndexedDB or another local database and design an explicit synchronization strategy if that data must also work offline.

Options

offlineFirst({
  cacheName: "my-app",
  precacheAssets: ["extra-data.json"],
  excludeAssets: [/\.mp4$/],
  precachePublicAssets: true,
  runtimeCaching: "assets", // "assets" | "same-origin" | false
  navigateFallback: "index.html", // or false for no app-shell fallback
  enableUpdateCheck: true,
  updateEventName: "offline-first:update",
  serviceWorkerFileName: "sw.js",
});

Relative asset paths follow Vite's configured base, so deployments under paths such as /tools/breath/ work. An absolute CDN base is rejected because a service worker cannot control another origin.

Use runtimeCaching: "same-origin" only when caching every successful same-origin GET response—including API responses—is appropriate for the app.

Scope

This project is for apps that want focused offline app-shell caching and a tiny update API. If you also need a web app manifest, install prompts, icon generation, advanced Workbox recipes, background sync, or push notifications, use vite-plugin-pwa instead.

Browser support

The plugin targets modern browsers with service worker, Cache Storage, modules, and async function support. Service worker support is the meaningful compatibility boundary; unsupported browsers keep working online without offline features.

License

MIT