vite-preload
raw JSON → 1.0.5 verified Mon Apr 27 auth: no javascript
Vite plugin (v1.0.6) that preloads server-rendered lazy React components and their CSS to eliminate FOUC and reduce load times. Unlike vite-plugin-preload, it evaluates used modules at render time (not build time). Supports Vite 5-8 and React 18-19. Ships TypeScript types, offers lazy() wrapper and preloadAll() for server-side resolution. Compatible with 103 Early Hints via getLinkHeaders(). Active development with frequent releases.
Common errors
error Error: The 'vite-preload' plugin is not found or not configured correctly. ↓
cause Importing preloadPlugin from wrong path (e.g., import { preloadPlugin } from 'vite-preload').
fix
Use default import from 'vite-preload/plugin': import preloadPlugin from 'vite-preload/plugin'.
error TypeError: Cannot read properties of undefined (reading 'getLinkHeaders') ↓
cause createChunkCollector returned undefined because manifest path is incorrect or file not found.
fix
Ensure manifest path points to valid file (e.g., './dist/client/.vite/manifest.json') and file exists.
error [vite-preload] Chunk not found in manifest: ... ↓
cause A lazy-loaded module's chunk is missing from the manifest; possibly due to Rollup chunk merging.
fix
Remove build.rollupOptions.output.experimentalMinChunkSize or set to 0.
error Error: React.lazy is not supported without the 'lazy' wrapper from vite-preload ↓
cause Using React.lazy directly instead of the wrapper from 'vite-preload' which collects chunks.
fix
Replace React.lazy with import { lazy } from 'vite-preload'.
Warnings
gotcha Preloading does not work in development mode (vite dev). CSS is injected via inline style tags causing FOUC. ↓
fix Only rely on preloading for production builds; test CSS appearance separately in dev.
gotcha If modules are not preloaded, check that build.rollupOptions.output.experimentalMinChunkSize is not set, as Rollup may merge chunks and break manifest mapping. ↓
fix Remove experimentalMinChunkSize or set it to 0.
breaking CJS require() may fail in some environments. Package is ESM-only. ↓
fix Use import syntax or enable ESM in Node.js ("type": "module" in package.json).
deprecated React 17 is not supported as a peer dependency; only React 18 and 19 are allowed. ↓
fix Upgrade React to version 18 or later.
gotcha The 'asyncScript' option generates async entry module; React hydration must wait for DOMContentLoaded. ↓
fix Ensure you do not hydrate or render React before DOMContentLoaded if using asyncScript.
breaking The plugin import path changed: import from 'vite-preload/plugin', not 'vite-preload'. ↓
fix Use import preloadPlugin from 'vite-preload/plugin'.
Install
npm install vite-preload yarn add vite-preload pnpm add vite-preload Imports
- preloadPlugin wrong
import { preloadPlugin } from 'vite-preload/plugin'correctimport preloadPlugin from 'vite-preload/plugin' - createChunkCollector wrong
const createChunkCollector = require('vite-preload').createChunkCollectorcorrectimport { createChunkCollector } from 'vite-preload' - ChunkCollectorContext wrong
import ChunkCollectorContext from 'vite-preload'correctimport { ChunkCollectorContext } from 'vite-preload' - preloadAll wrong
import { preloadAll } from 'vite-preload/plugin'correctimport { preloadAll } from 'vite-preload' - lazy wrong
import { lazy } from 'react'correctimport { lazy } from 'vite-preload'
Quickstart
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import preloadPlugin from 'vite-preload/plugin';
export default defineConfig({
plugins: [
preloadPlugin(),
react()
]
});
// server/entry.server.tsx (simplified)
import { ChunkCollectorContext, createChunkCollector, preloadAll } from 'vite-preload';
import React from 'react';
import { renderToPipeableNodeStream } from 'react-dom/server';
// On server startup:
await preloadAll();
// In request handler:
const collector = createChunkCollector({
manifest: './dist/client/.vite/manifest.json',
entry: 'index.html'
});
// Early Hints
res.writeEarlyHints({ link: collector.getLinkHeaders() });
const { pipe } = renderToPipeableNodeStream(
<ChunkCollectorContext.Provider value={collector}>
<App />
</ChunkCollectorContext.Provider>
);
// After rendering, inject <link> tags into HTML head
const linkTags = collector.getLinkTags();
const html = template.replace('</head>', `${linkTags}</head>`);
res.write(html);