Customizing Vite's Input and Output Directories
When working with Vite for static multipage sites, you might need to customize the default project structure for better organization. This guide covers how to change both input and output directories while ensuring all HTML pages are properly processed.
Problem: Default Structure Limitations
Vite's default structure places source files in the project root and outputs to a dist
folder:
my-app/
├─ node_modules/
├─ dist/
│ ├─ assets/
│ ├─ index.html
├─ index.html
├─ main.js
├─ style.scss
├─ package.json
You want to organize your source files in a src
directory and output to a dist
folder at the project root:
my-app/
├─ node_modules/
├─ package.json
├─ src/
│ ├─ about.html
│ ├─ index.html
│ ├─ main.js
│ ├─ style.scss
├─ dist/
│ ├─ assets/
│ ├─ about.html
│ ├─ index.html
Basic Configuration Solution
The most straightforward solution uses Vite's configuration file to define both input and output directories:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
build: {
outDir: '../dist',
emptyOutDir: true,
}
});
TIP
Always include emptyOutDir: true
to ensure the output directory is cleaned before each build, preventing stale files from accumulating.
Handling Multiple HTML Pages
For multipage applications, you need to explicitly define all entry points in the Rollup configuration:
Option 1: Manual Entry Definition
// vite.config.js
import path from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
build: {
outDir: '../dist',
rollupOptions: {
input: {
main: path.resolve(__dirname, 'src/index.html'),
about: path.resolve(__dirname, 'src/about.html')
}
}
}
});
Option 2: Dynamic Entry Discovery
For projects with many HTML files, dynamically discover all HTML files:
// vite.config.js
import path from 'path';
import glob from 'glob';
import { defineConfig } from 'vite';
export default defineConfig({
root: path.join(__dirname, "src"),
build: {
outDir: path.join(__dirname, "dist"),
rollupOptions: {
input: glob.sync(path.resolve(__dirname, "src", "*.html")),
},
},
});
WARNING
When using the glob
approach, install it as a development dependency:
npm install glob -D
Advanced Configuration Options
Custom Output Directory Names
If you want to change the output directory name from dist
to something else (e.g., build
):
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
build: {
outDir: '../build'
}
});
File Naming Patterns
Customize output file naming patterns:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
build: {
outDir: '../dist',
rollupOptions: {
output: {
assetFileNames: "[name].[ext]",
chunkFileNames: "[name].[ext]",
entryFileNames: "[name].js",
},
},
},
});
Package.json Script Updates
Update your package.json scripts to work with the new configuration:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
INFO
With the configuration file properly set up, you no longer need to specify the source directory in your scripts.
Custom Configuration File Location
If you prefer to keep your configuration file in a different location:
{
"scripts": {
"dev": "vite --config ./config/vite.config.js",
"build": "vite build --config ./config/vite.config.js",
"preview": "vite preview --config ./config/vite.config.js"
}
}
Common Issues and Solutions
Build Output Contains Only index.html
This occurs when you don't specify all HTML entry points in multi-page applications. Use the Rollup options as shown above to explicitly define all HTML files.
Assets Not Found After Build
Ensure your asset paths are relative by setting the base option:
export default defineConfig({
base: './',
root: 'src',
build: {
outDir: '../dist'
}
});
Incorrect Path Resolution
Always use path.resolve
or path.join
for reliable path resolution across different environments:
import path from 'path';
export default defineConfig({
root: path.resolve(__dirname, 'src'),
build: {
outDir: path.resolve(__dirname, 'dist')
}
});
Best Practices
- Always use absolute paths with
path.resolve()
for better cross-platform compatibility - Keep configuration file in project root for simplicity unless you have a specific organizational need
- Test both development and production builds after configuration changes
- Use TypeScript for your configuration file (
vite.config.ts
) for better type safety
By following these patterns, you can effectively customize Vite's input and output directories while maintaining a well-organized project structure for multipage applications.