Vue 49: Single-File Components & Vite
easy⏱ 5 mincoursevue
Anatomy of a .vue file
A Single-File Component has up to three blocks: <template> (the markup), <script setup> (the logic, using the Composition API), and <style scoped> (CSS that Vite scopes to this component only). Vite's compiler splits these apart, compiles the template into a render function, and rewrites the CSS selectors so they can't leak into other components.
<!-- Card.vue -->
<template>
<div class="card">
<p class="title">{{ label }}</p>
</div>
</template>
<script setup lang="ts">
defineProps<{ label: string }>()
</script>
<style scoped>
.card { padding: 16px; border-radius: 12px; background: #1e2a4a; }
.title { color: #42b883; font-weight: 700; }
</style>
Dev server vs. production build
vite (dev) serves your source files over native browser ESM, pre-bundling only your dependencies with esbuild — there's no full bundling of your own code, which is why startup and hot updates are near-instant. vite build is a different pipeline: it runs everything through Rollup to produce optimized, hashed, tree-shaken static assets in a dist/ folder, ready to deploy.
# terminal
npm run dev # vite dev server: native ESM + esbuild pre-bundling
npm run build # rollup production bundle -> dist/
No bundler in this sandbox
This browser sandbox can only run plain JavaScript/TypeScript objects passed straight to createApp — it has no compiler for .vue files. So instead of loading real SFCs, the live demo below reproduces the effect of <style scoped> by hand: injecting real <style> tags whose selectors are scoped with a unique attribute per component, exactly like Vite's compiler output does under the hood.