🏠 Home / Hub

⚡ Vue 12 — Vite & Single File Components

← Vue Menu · ← Prev: Transitions

CDN Vue ကနေ Vite+SFC ကိုပြောင်းတော်မူ: Lessons 01-11 က CDN script tag Vue သုံးခဲ့တာ ။ Real projects မှာ Vite + .vue SFC (Single File Components) သုံးတယ်။ Hot Module Replacement, TypeScript, scoped CSS, component imports တွေ ပိုကောင်းတယ်။

1. Create Vue + Vite Project

npm create vue@latest my-vue-app
# Options:
# ✅ Add TypeScript?         → No (or Yes if comfortable)
# ✅ Add JSX Support?        → No
# ✅ Add Vue Router?         → Yes (for multi-page)
# ✅ Add Pinia?              → Yes (for state management)
# ✅ Add Vitest?             → Yes (for unit testing)
# ✅ Add ESLint?             → Yes

cd my-vue-app
npm install
npm run dev       → http://localhost:5173 (HMR enabled)
npm run build     → dist/ (production build)
npm run preview   → preview production build locally

2. .vue File Structure (SFC)

<!-- src/components/MyButton.vue -->

<template>
  <!-- 1. Template: only ONE root element (or Fragment in Vue 3) -->
  <button :class="['btn', variant]" @click="handleClick">
    <slot />   <!-- slot: content passed by parent -->
  </button>
</template>

<script setup>
// 2. Script setup: Composition API (no return needed)
import { defineProps, defineEmits } from 'vue'

const props = defineProps({
  variant: { type: String, default: 'primary' }
})
const emit = defineEmits(['click'])

function handleClick(e) {
  emit('click', e)
}
</script>

<style scoped>
/* 3. Style scoped: CSS only applies to THIS component */
.btn { padding: 10px 20px; border-radius: 8px; cursor: pointer; border: none; }
.btn.primary { background: #42b883; color: white; }
.btn.danger  { background: #ef4444; color: white; }
</style>
Scoped CSS magic: Vue adds a unique data attribute like data-v-a1b2c3 to scope CSS to just that component — no class name collisions!

3. Project File Structure

my-vue-app/
├── public/                 ← static files (favicon, robots.txt)
├── src/
│   ├── main.js             ← entry point (createApp + plugins)
│   ├── App.vue             ← root component
│   ├── assets/             ← images, global CSS
│   ├── components/         ← reusable UI components
│   │   ├── BaseButton.vue
│   │   ├── BaseInput.vue
│   │   └── AppNavbar.vue
│   ├── composables/        ← reusable logic (hooks)
│   │   ├── useAuth.js
│   │   └── useFetch.js
│   ├── layouts/            ← page layout wrappers
│   │   ├── DefaultLayout.vue
│   │   └── AuthLayout.vue
│   ├── pages/              ← route-level components
│   │   ├── HomePage.vue
│   │   ├── ProductsPage.vue
│   │   └── LoginPage.vue
│   ├── router/             ← Vue Router config
│   │   └── index.js
│   ├── stores/             ← Pinia stores
│   │   ├── useAuthStore.js
│   │   └── useCartStore.js
│   └── services/           ← API/HTTP layer
│       └── api.js
├── vite.config.js
├── package.json
└── index.html              ← Vite entry HTML

4. main.js — App Bootstrap

// src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'
import './assets/main.css'   // global CSS

const app = createApp(App)

app.use(createPinia())  // state management
app.use(router)         // routing

// Global components (used everywhere without import)
import BaseButton from './components/BaseButton.vue'
app.component('BaseButton', BaseButton)

app.mount('#app')

5. vite.config.js — Key Options

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      // Now: import Foo from '@/components/Foo.vue'  ← works everywhere
    },
  },
  server: {
    port: 5173,
    // Proxy API calls to backend (avoid CORS in dev)
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
      }
    }
  },
})

6. Environment Variables in Vite

# .env (committed — public defaults)
VITE_APP_NAME=My App

# .env.local (NOT committed — dev secrets)
VITE_API_BASE_URL=http://localhost:8000/api

# .env.production (NOT committed — production)
VITE_API_BASE_URL=https://api.yourdomain.com

# Usage in code — must prefix with VITE_
import.meta.env.VITE_API_BASE_URL
import.meta.env.MODE         // 'development' or 'production'
import.meta.env.PROD         // true in production
import.meta.env.DEV          // true in development

7. CDN → Vite: Key Differences

FeatureCDN (lessons 01-11)Vite + SFC
SetupJust a script tagnpm create vue@latest
File format.html with inline Vue.vue (SFC with template/script/style)
CSS scopingGlobal — can clashScoped per component
Hot reloadFull page refreshHMR — just changed component
TypeScriptNoYes — full TS support
Build outputNonedist/ — optimized + bundled
Tree shakingNoYes — unused code removed
Dev toolsBasicVue DevTools + Vite inspector

📌 Study Checklist