Vue¶
Vue 3 integration with Litestar Vite using the Composition API and Single File Components.
Quick Start¶
litestar assets init --template vue
This creates a Vue 3 project with TypeScript support.
Project Structure¶
Vue applications use SPA mode - Vite serves the index.html directly:
my-app/
├── app.py # Litestar backend (API only)
├── index.html # Vite entry point (root level)
├── package.json
├── vite.config.ts
├── tsconfig.json
└── src/
├── main.ts # Vue entry point
├── App.vue # Root component
└── style.css
Backend Setup¶
In SPA mode, Litestar serves only your API endpoints. The VitePlugin handles serving the frontend automatically:
vite = VitePlugin(
config=ViteConfig(
mode="spa",
dev_mode=DEV_MODE,
paths=PathConfig(root=here),
types=TypeGenConfig(),
runtime=RuntimeConfig(port=5011),
)
)
app = Litestar(route_handlers=[LibraryController], plugins=[vite], debug=True)
Key points:
mode="spa"tells Vite to serveindex.htmlfor non-API routesNo
template_configneeded - Jinja is not used in SPA modeTypeGenConfig()enables TypeScript type generation from OpenAPI
Vite Configuration¶
import tailwindcss from "@tailwindcss/vite"
import vue from "@vitejs/plugin-vue"
import litestar from "litestar-vite-plugin"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [
tailwindcss(),
vue(),
litestar({
input: ["src/main.ts"],
resourceDir: "src",
}),
],
})
Key configuration:
input- Entry point(s) for your applicationresourceDir- Source directory (explicitly set tosrc)The plugin auto-reads
assetUrl,bundleDirfrom.litestar.json(generated by Python)
HTML Entry Point¶
In SPA mode, index.html lives at the project root and uses standard Vite syntax:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Note
Unlike template mode, SPA mode doesn’t use Jinja helpers like {{ vite() }}.
Vite processes the HTML directly.
Vue Component¶
<script setup lang="ts">
import { ref, onMounted } from "vue";
interface Summary {
app: string;
headline: string;
}
const summary = ref<Summary | null>(null);
onMounted(async () => {
const res = await fetch("/api/summary");
summary.value = await res.json();
});
</script>
<template>
<div>
<h1>Vue + Litestar</h1>
<p v-if="summary">{{ summary.headline }}</p>
</div>
</template>
Running¶
# Recommended: Litestar proxies Vite automatically in dev mode
litestar run --reload
# Alternative: Two-process setup
litestar assets serve # Vite dev server
litestar run --reload # Backend only (in another terminal)
Type Generation¶
With types=TypeGenConfig() enabled, run:
litestar assets generate-types
This generates TypeScript types from your OpenAPI schema. See Type Generation for more details.
See Also¶
Inertia.js - Vue with Inertia.js for server-side routing
Type Generation - TypeScript type generation