Building and deploying
During development the Vite server processes .vue files on the fly. For deployment the project is built: Vite turns components into plain HTML, CSS and JavaScript files, minifies them and puts them into the dist/ folder. That folder can be uploaded to any static file hosting.
Building
In the blog project folder run:
npm run buildThe terminal lists the created files with their sizes, and a dist/ folder appears in the project:
dist/
├── index.html
├── favicon.ico
└── assets/
├── index-BkX3c9aQ.js
├── index-D1f8Lw2e.css
└── AdminLayout-Cq7nR0sd.jsThe odd endings in the names are content hashes. When the code changes, the file name changes, and the visitor's browser does not take the old version from its cache. Separate files for pages exist thanks to lazy-loaded routes.
Checking the build
npm run previewThe command starts a simple server for the dist/ folder at http://localhost:4173. Walk through the blog pages: this way you check exactly what will end up on the server.
Environment variables
The API address is better kept out of the code, in a .env file at the project root. Only variables with the VITE_ prefix reach the code:
VITE_API_URL=https://jsonplaceholder.typicode.com// src/stores/posts.js
const API = `${import.meta.env.VITE_API_URL}/posts`For the build you can create a separate .env.production file — Vite uses it on npm run build. Values are inserted into the code at build time, so never keep secret keys in such variables: any visitor can see them in the JavaScript files.
The base path
If the site is served not from the domain root but, for example, from https://example.com/blog/, set this in vite.config.js:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
base: '/blog/',
})Vite prefixes all file paths with /blog/, and the router gets this path through import.meta.env.BASE_URL — it is already passed to createWebHistory.
Server setup
The router in createWebHistory mode uses ordinary addresses like /posts/5, but there is no such file on the server. The server must return index.html for any unknown address, and the router then picks the page. For nginx it is one line in the location block:
location / {
try_files $uri $uri/ /index.html;
}Static site hosts — Netlify, Vercel, Cloudflare Pages — usually offer such a rule in their settings for Vite projects or detect it themselves.
Common mistake
You deploy the site, open the home page — everything works, but reloading /posts/5 gives a 404 error. The server looks for a file posts/5 and cannot find it, because the routes exist only in JavaScript. Set up returning index.html for every address, as in the section above, and check it by reloading a nested page after deploying.