Vite 13 ⚡ Framework Plugins — React, Vue & Svelte integrations
Vite is framework-agnostic at its core. The framework-specific features—Fast Refresh for React, Single File Component compilation for Vue, and the Svelte compiler integration—are provided by official plugins that sit in the plugins array alongside any Rollup plugins. Each plugin wraps the framework’s compiler and wires it into Vite’s transform pipeline, dev server, and production build. The plugins are the reason a React project, a Vue project, and a Svelte project can all use the same Vite config file structure while getting framework-specific HMR and build behavior.
This chapter covers the three official framework plugins: @vitejs/plugin-react and its SWC variant, @vitejs/plugin-vue, and @sveltejs/vite-plugin-svelte. It explains the installation, the core options, and the framework-specific behavior each plugin injects.
Key point: The framework plugin is what makes HMR work for the framework’s components. @vitejs/plugin-react enables Fast Refresh, @vitejs/plugin-vue compiles SFCs into virtual modules, and @sveltejs/vite-plugin-svelte runs the Svelte compiler. Without the plugin, the framework’s component syntax is not transformed, and the dev server cannot apply updates at the component level.
Why framework plugins exist
The transform problem. Vite’s core transform handles JavaScript, TypeScript, CSS, and assets. It does not know how to compile a .vue file, which contains a <script>, a <template>, and a <style> block that each need separate compilation. It does not know how to inject the React Fast Refresh runtime into a module that exports a component. The framework plugin is the component that adds this knowledge to Vite’s pipeline.
The HMR problem. Generic HMR works at the module level. If a module changes, the module is replaced. For a framework component, the desired behavior is more specific: preserve the component’s state, re-render only the changed component, and update the styles without a reload. The framework plugin implements the HMR boundary that makes this possible. @vitejs/plugin-react injects the Fast Refresh runtime , @vitejs/plugin-vue splits the SFC into virtual modules that can be updated independently , and @sveltejs/vite-plugin-svelte handles the component update with a documented state-preservation caveat .
The production problem. During development, the plugin uses the fastest available transformer. During production, it uses the framework’s full compiler to produce the optimized output. @vitejs/plugin-react uses Oxc for the transform and only invokes Babel when custom plugins are configured . This distinction is why the plugin is fast in development and correct in production.
a. React: @vitejs/plugin-react
The React plugin is installed as a dev dependency and added to the plugins array.
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
The plugin enables Fast Refresh in development, uses the automatic JSX runtime, and supports custom Babel plugins and presets . The include and exclude options control which files the plugin processes; the default includes .js, .jsx, .ts, and .tsx, and excludes node_modules . The jsxImportSource option points the JSX factory at a different library, such as @emotion/react. The jsxRuntime option can revert to the classic runtime when the automatic runtime causes issues . The babel option adds plugins and presets to the Babel transform, but when no Babel plugins are configured, only Oxc is used for production builds, which keeps the build fast .
For projects that need SWC instead of Oxc, @vitejs/plugin-react-swc replaces the transformer during development. The Vite documentation notes that for large projects that require custom plugins, cold start and HMR can be significantly faster if the plugin is also available for SWC . The SWC variant does not support the same Babel plugin configuration.
A third React plugin, @vitejs/plugin-rsc, provides React Server Components support through Vite’s Environment API. It is a lower-level primitive intended for frameworks, and a minimal standalone RSC application can be created with npm create vite@latest -- --template rsc .
b. Vue: @vitejs/plugin-vue
The Vue plugin compiles Vue 3 Single File Components. It is installed and added to the plugins array.
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [vue()],
}
The plugin converts the asset URLs inside the <template> block into ESM imports, so an <img src="../image.png"> in the template becomes an imported module . The features option controls the compiler behavior: propsDestructure enables reactive destructure for defineProps, customElement transforms matched SFCs into custom elements, and optionsAPI can be set to false to drop the Options API support and reduce the production bundle . The script, template, and style options pass lower-level compiler options to the corresponding vue/compiler-sfc APIs .
For JSX and TSX support in Vue, the separate @vitejs/plugin-vue-jsx plugin is required . The Vue 2.7 line uses @vitejs/plugin-vue2 and its JSX variant .
c. Svelte: @sveltejs/vite-plugin-svelte
The Svelte plugin runs the Svelte compiler and reads the project’s svelte.config.js automatically.
// vite.config.js
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
plugins: [svelte()],
})
The plugin merges options from three sources in order: the plugin defaults, the svelte.config.js file in the Vite root, and the inline options passed to the plugin . The compilerOptions, preprocess, extensions, and onwarn options are passed to the Svelte compiler. The preprocess option accepts a preprocessor group, such as svelte-preprocess for TypeScript support .
A known limitation: third-party Svelte libraries that use the lifecycle API (onMount, setContext) must be added to optimizeDeps.exclude in the Vite config. Vite’s dependency pre-bundling does not deduplicate the Svelte instance, and multiple instances cause errors like “Function called outside component initialization” . The plugin documentation also notes that local component state is not preserved on HMR updates for JS changes, to avoid unpredictable behavior; style-only updates do preserve state .
Complete Example Session
// ============================================
// PART 1: REACT PLUGIN
// ============================================
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
// ============================================
// PART 2: REACT PLUGIN OPTIONS
// ============================================
react({
include: /\.(mdx|js|jsx|ts|tsx)$/,
jsxImportSource: '@emotion/react',
babel: {
plugins: ['babel-plugin-react-compiler'],
},
})
// ============================================
// PART 3: REACT SWC VARIANT
// ============================================
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()],
})
// ============================================
// PART 4: VUE PLUGIN
// ============================================
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [vue()],
}
// ============================================
// PART 5: VUE PLUGIN OPTIONS
// ============================================
vue({
features: {
propsDestructure: true,
optionsAPI: false,
},
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('my-'),
},
},
})
// ============================================
// PART 6: VUE JSX
// ============================================
import vueJsx from '@vitejs/plugin-vue-jsx'
export default {
plugins: [vue(), vueJsx()],
}
// ============================================
// PART 7: SVELTE PLUGIN
// ============================================
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
plugins: [svelte()],
})
// ============================================
// PART 8: SVELTE CONFIG FILE
// ============================================
// svelte.config.js
export default {
preprocess: [sveltePreprocess({ typescript: true })],
compilerOptions: {},
}
// ============================================
// PART 9: SVELTE DEP EXCLUSION
// ============================================
export default defineConfig({
plugins: [svelte()],
optimizeDeps: {
exclude: ['svelte-library'],
},
})
// ============================================
// PART 10: THE COMPLETE REACT CONFIG
// ============================================
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
react({
jsxImportSource: '@emotion/react',
}),
],
})
The ten parts covered the React plugin, its options, the SWC variant, the Vue plugin, its options, Vue JSX, the Svelte plugin, the Svelte config file, the dependency exclusion, and the complete React config.
Quick Reference
Framework plugins
| Framework | Plugin | Purpose |
|---|---|---|
| React | @vitejs/plugin-react | Fast Refresh, JSX, Babel |
| React (SWC) | @vitejs/plugin-react-swc | SWC-based Fast Refresh |
| React (RSC) | @vitejs/plugin-rsc | React Server Components |
| Vue 3 | @vitejs/plugin-vue | SFC compilation |
| Vue 3 JSX | @vitejs/plugin-vue-jsx | JSX/TSX support |
| Vue 2.7 | @vitejs/plugin-vue2 | Vue 2 SFC compilation |
| Svelte | @sveltejs/vite-plugin-svelte | Svelte compiler |
React plugin options
| Option | Default | Purpose |
|---|---|---|
include | .js, .jsx, .ts, .tsx | Files to process |
jsxImportSource | react | JSX factory source |
jsxRuntime | automatic | JSX runtime |
babel | — | Babel plugins/presets |
reactRefreshHost | — | Module federation HMR |
Vue plugin options
| Option | Default | Purpose |
|---|---|---|
features.propsDestructure | false (Vue 3.4), true (3.5+) | Reactive defineProps destructure |
features.customElement | /\.ce\.vue$/ | Custom element mode |
features.optionsAPI | true | Drop Options API in production |
script/template/style | — | Compiler options |
Svelte plugin options
| Option | Default | Purpose |
|---|---|---|
preprocess | — | Preprocessor groups |
compilerOptions | — | Svelte compiler options |
extensions | ['.svelte'] | File extensions |
onwarn | — | Warning handler |
configFile | svelte.config.js | Config file path |
Best Practices
✅ Do This:
// Install the plugin as a dev dependency
npm install -D @vitejs/plugin-react // ✅
// Add the plugin to the plugins array
plugins: [react()] // ✅
// Use the SWC variant for large React projects
plugins: [react({ plugins: [] })] // @vitejs/plugin-react-swc // ✅
// Exclude Svelte libraries that use lifecycle APIs
optimizeDeps: { exclude: ['svelte-library'] } // ✅
❌ Don’t Do This:
// Use a framework plugin without installing it
plugins: [react()] // ❌ (module not found)
// Use @vitejs/plugin-vue for Vue 2.7
plugins: [vue()] // ❌ (use @vitejs/plugin-vue2)
// Assume Svelte state is preserved on JS HMR
// It is not preserved by design // ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| React Fast Refresh not working | Plugin not installed or not in plugins | Add react() to the array |
createContext error in React | Plugin version mismatch | Update @vitejs/plugin-react |
| Vue SFC not compiled | Plugin missing | Add vue() to the array |
| Vue JSX not working | @vitejs/plugin-vue-jsx not installed | Install and add the JSX plugin |
| Svelte lifecycle error | Multiple Svelte instances | Add the library to optimizeDeps.exclude |
| Svelte state reset on HMR | Design limitation for JS updates | Style-only updates preserve state |
Real-World Examples
1. React plugin
plugins: [react()]
2. React with Emotion
plugins: [react({ jsxImportSource: '@emotion/react' })]
3. React SWC
plugins: [react()] // from @vitejs/plugin-react-swc
4. Vue plugin
plugins: [vue()]
5. Vue with Options API dropped
plugins: [vue({ features: { optionsAPI: false } })]
6. Vue JSX
plugins: [vue(), vueJsx()]
7. Svelte plugin
plugins: [svelte()]
8. Svelte with preprocessor
plugins: [svelte({ preprocess: [sveltePreprocess()] })]
9. Svelte dep exclusion
optimizeDeps: { exclude: ['svelte-library'] }
10. The complete Vue config
import vue from '@vitejs/plugin-vue'
export default { plugins: [vue()] }
Visual
The framework plugin pipeline
┌─────────────────────────────────────────────────────────────┐
│ Vite core transform │
│ │ │
│ ▼ │
│ Framework plugin │
│ ├── React: Fast Refresh + JSX │
│ ├── Vue: SFC compiler │
│ └── Svelte: Svelte compiler │
│ │ │
│ ▼ │
│ Module graph with framework-specific HMR boundaries │
└─────────────────────────────────────────────────────────────┘
React Fast Refresh
┌─────────────────────────────────────────────────────────────┐
│ @vitejs/plugin-react │
│ ├── injects Fast Refresh runtime │
│ ├── uses automatic JSX runtime │
│ └── uses Oxc for transform │
│ │
│ Component changes ──► state preserved ──► re-render │
└─────────────────────────────────────────────────────────────┘
Vue SFC compilation
┌─────────────────────────────────────────────────────────────┐
│ Component.vue │
│ ├── <script> ──► JS module │
│ ├── <template> ──► render function │
│ └── <style> ──► CSS module │
│ │
│ @vitejs/plugin-vue splits and compiles each block. │
└─────────────────────────────────────────────────────────────┘
Svelte config resolution
┌─────────────────────────────────────────────────────────────┐
│ vite-plugin-svelte defaults │
│ │ │
│ ▼ │
│ svelte.config.js in Vite root │
│ │ │
│ ▼ │
│ inline options in vite.config.js │
│ │
│ Later sources override earlier ones. │
└─────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| React plugin | @vitejs/plugin-react |
| React SWC variant | @vitejs/plugin-react-swc |
| React RSC plugin | @vitejs/plugin-rsc |
| Vue plugin | @vitejs/plugin-vue |
| Vue JSX plugin | @vitejs/plugin-vue-jsx |
| Svelte plugin | @sveltejs/vite-plugin-svelte |
| Svelte config file | svelte.config.js (auto-resolved) |
| Svelte dep exclusion | optimizeDeps.exclude for lifecycle libraries |
Key takeaways:
- The framework plugin is what makes the framework’s component syntax work in Vite. Vite’s core transform does not know how to compile a Vue SFC or inject the React Fast Refresh runtime. The plugin adds that knowledge to the transform pipeline.
@vitejs/plugin-reactenables Fast Refresh and uses Oxc for the transform. Thebabeloption adds custom Babel plugins when needed, but without them only Oxc is used, which keeps the build fast . The@vitejs/plugin-react-swcvariant replaces Oxc with SWC for faster cold start and HMR in large projects .@vitejs/plugin-vuecompiles SFCs and converts template asset URLs into ESM imports. Thefeaturesoption controls the compiler behavior, includingpropsDestructure,customElement, andoptionsAPI. The@vitejs/plugin-vue-jsxplugin is required for JSX support .@sveltejs/vite-plugin-svelteruns the Svelte compiler and readssvelte.config.jsautomatically. The options are merged from the plugin defaults, the config file, and the inline options, in that order . Thepreprocessoption accepts preprocessor groups for TypeScript and other languages .- Svelte libraries that use lifecycle APIs must be excluded from dependency pre-bundling. Vite’s pre-bundling does not deduplicate the Svelte instance, and multiple instances cause runtime errors. The
optimizeDeps.excludearray is the fix . - Svelte local component state is not preserved on HMR for JS updates. The plugin disables state preservation to avoid unpredictable behavior. Style-only updates do preserve state .
Remember: A framework plugin is not optional for a framework project. It is the component that compiles the framework’s component format, injects the framework’s HMR runtime, and produces the optimized production output. React uses @vitejs/plugin-react (or the SWC variant), Vue uses @vitejs/plugin-vue (plus @vitejs/plugin-vue-jsx for JSX), and Svelte uses @sveltejs/vite-plugin-svelte. Each plugin has its own options, its own config file conventions, and its own limitations. Install the plugin, add it to the plugins array, and read its options when the default behavior does not match the project’s needs.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!