Frontend Development 11 min read

Implementing a Persistent Cache Strategy for Vite Development Server to Boost First‑Page Performance

This article explains how to create a Vite plugin that persists the module graph cache across dev‑server restarts, uses ETag comparison to serve 304 responses, and integrates custom middleware to dramatically improve first‑page load times in development mode.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing a Persistent Cache Strategy for Vite Development Server to Boost First‑Page Performance

The article introduces a persistent caching strategy for Vite's development server, showing that normal dev‑server startup incurs heavy file requests and costly transform operations (e.g., converting less to css ), which degrade first‑page performance.

By persisting the moduleGraph —which stores modules, their transformed results, and ETags—to a local cache file when the dev server stops, and reloading it on the next start, the server can quickly return 304 responses for unchanged assets, avoiding repeated resolves, loads, and transforms.

The implementation is broken into three steps:

On dev‑server shutdown, serialize the moduleGraph (specifically each module's etag ) to node_modules/.vite/cache/cache.json .

On dev‑server startup, read the cache file and populate an in‑memory cache object.

Register a custom middleware that intercepts requests, compares the request's If-None-Match header with the cached ETag, and returns a 304 status when they match; otherwise it falls back to Vite's normal handling.

Key code snippets include the core transformMiddleware logic that checks ETags and returns 304 when appropriate, and the full plugin definition:

const persistentCachePlugin = () => {
  let _server;
  let cache = {};
  let cachePath = path.resolve('./', 'node_modules/.vite/cache/');
  return {
    name: 'persistent-cache-plugin',
    configureServer: async server => { _server = server; },
    buildStart: async () => {
      if (fs.existsSync(cachePath + '/cache.json')) {
        cache = require(cachePath + '/cache.json');
      }
      process.once('SIGINT', async () => {
        try { await server.close(); } finally { process.exit(); }
      });
    },
    buildEnd: async () => {
      if (!fs.existsSync(cachePath)) fs.mkdirSync(cachePath);
      for (let [key, value] of _server.moduleGraph.urlToModuleMap) {
        if (value.transformResult && value.transformResult.etag) {
          cache[key] = value.transformResult.etag;
        }
      }
      fs.writeFileSync(cachePath + '/cache.json', JSON.stringify(cache), err => { console.log(err); });
    }
  };
};

The middleware added in configureServer checks the in‑memory cache and either serves a 304 response (with an optional delayed transformRequest to keep HMR functional) or passes control to the next handler.

Finally, the article concludes that applying this plugin to a Vite project can noticeably reduce first‑page load times during development, and invites readers to experiment with the plugin and watch for future official implementations of persistent caching in Vite.

pluginVitefrontend performanceDev Serverpersistent cachemoduleGraph
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.