Vite’s blazing fast dev server isn’t just a feature; it’s the entire point, and it achieves this by treating your .svelte files not as opaque blobs but as modules it can directly transform.
Let’s spin up a new Svelte project with Vite and see it in action. First, ensure you have Node.js installed (version 16 or higher is recommended). Then, run this command in your terminal:
npm create vite@latest my-svelte-app --template svelte
cd my-svelte-app
npm install
npm run dev
Open your browser to http://localhost:5173. You’ll see a basic Svelte app. Now, open src/App.svelte and change the <h1> text to "Hello Vite!". Save the file. Notice how the browser updates instantly without a full page reload. That’s Vite’s magic: it uses native ES modules and a pre-bundled dependency graph to serve your code directly, only recompiling changed files.
The core of Vite’s configuration lives in vite.config.js (or .ts). Let’s break down what you’ll typically find and what you can control.
Here’s a minimal vite.config.js:
import { defineConfig } from 'vite';
import svelte from '@vitejs/plugin-svelte';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svelte()],
});
This is the bare minimum to get Svelte working. The svelte() plugin handles the transformation of .svelte files into plain JavaScript that the browser can understand. It leverages svelte-preprocess under the hood, meaning your <script>, <style>, and <template> blocks are processed according to Svelte’s compiler options.
When you run npm run build, Vite orchestrates a production build using Rollup under the hood. This means your code is bundled, minified, and optimized for deployment. The output goes into the dist directory by default.
The defineConfig function from vite is a type helper that provides autocompletion and type checking for your Vite configuration object. Inside it, plugins is an array where you register all the Vite plugins your project needs. @vitejs/plugin-svelte is the essential one for Svelte projects.
You can customize the Svelte compiler options directly within the plugin. For instance, to enable Svelte’s immutable option or configure css.preprocessorCode for specific preprocessors:
import { defineConfig } from 'vite';
import svelte from '@vitejs/plugin-svelte';
export default defineConfig({
plugins: [
svelte({
compilerOptions: {
immutable: true, // Forces Svelte to treat all props as immutable
},
hot: {
// Enable or disable HMR for specific parts of Svelte components
// For example, disable HMR for <script setup> or specific event handlers
},
preprocess: {
// Example: Configure Sass for .scss files
// You'd need to npm install -D sass
// postcss: {
// plugins: [require('autoprefixer')],
// },
// scss: {
// additionalData: `$primary-color: #ff3e00;`,
// },
},
}),
],
});
The compilerOptions object passed to the svelte() plugin directly maps to Svelte’s compiler options. immutable: true is a powerful optimization if your application strictly adheres to immutability, as it allows Svelte to perform more aggressive change detection. The hot option allows fine-grained control over Hot Module Replacement (HMR) behavior, which is key to Vite’s instant updates.
The preprocess option is where you configure how your Svelte files are transformed before the Svelte compiler runs. This is crucial for using preprocessors like Sass, TypeScript, or Pug. For Sass, you’d install sass as a dev dependency (npm install -D sass) and then configure preprocess like so:
import { defineConfig } from 'vite';
import svelte from '@vitejs/plugin-svelte';
import sass from 'sass'; // Import sass if needed for configuration
export default defineConfig({
plugins: [
svelte({
preprocess: {
// Example using scss
// Ensure you have `sass` installed: npm install -D sass
// You can also configure postcss here if needed
scss: {
// You can inject global variables or mixins here
// For example:
// additionalData: `$primary: #007bff;`
},
},
}),
],
// Other Vite configuration options can go here
// server: {
// port: 3000, // Custom dev server port
// },
// build: {
// outDir: 'build', // Custom build output directory
// },
});
The additionalData in scss is particularly useful for injecting global variables, mixins, or functions into every Sass file processed. This avoids repetitive imports and keeps your styles consistent.
Vite also provides built-in support for TypeScript. If you create a project with the svelte-ts template (npm create vite@latest my-svelte-ts-app --template svelte-ts), Vite automatically configures the TypeScript plugin. You can then use TypeScript in your <script lang="ts"> blocks.
One of the most surprising aspects of Vite’s configuration is how it handles aliases. Instead of requiring a complex setup for module path resolution, you can define them directly in vite.config.js:
import { defineConfig } from 'vite';
import svelte from '@vitejs/plugin-svelte';
import path from 'path'; // Node.js path module
export default defineConfig({
plugins: [svelte()],
resolve: {
alias: {
'@': path.resolve('./src'), // Map '@' to the 'src' directory
'@components': path.resolve('./src/components'), // Map '@components' to 'src/components'
},
},
});
After setting this up, you can import modules like import MyComponent from '@/components/MyComponent.svelte'; instead of using lengthy relative paths like ../../components/MyComponent.svelte. This makes imports cleaner and more maintainable, especially in large projects.
The resolve.alias option uses Node.js’s path module to create absolute paths, making them robust across different operating systems and build environments. This is a significant quality-of-life improvement for developers.
Beyond the core configuration, Vite offers extensive options for optimizing your build, such as code splitting, dynamic imports, and asset handling. You can fine-tune the Rollup options used during the production build via the build key in vite.config.js.
The next step is often diving into environment variables and how Vite manages them, particularly for distinguishing between development and production builds.