Vue SPA Template
The Vue SPA template provides a modern Vue 3 development environment with TypeScript, Vite, Vue Router, and Pinia. It's perfect for building single-page applications with excellent developer experience.
Technical Stack
- Vue 3 - Progressive JavaScript framework
- TypeScript - Type-safe development
- Vite - Fast build tool and dev server
- Vue Router - Official routing library
- Pinia - State management library
- Vue i18n - Internationalization
- Tailwind CSS - Utility-first CSS framework
- SCSS - CSS preprocessor
Quick Start
1. Create Project
bash
# Initialize project
vup init my-vue-project
cd my-vue-project
# Add Vue template
vup add my-vue-app
2. Install Dependencies
bash
# Install dependencies
pnpm install
3. Start Development
bash
# Start development server
cd apps/my-vue-app
pnpm dev
The application will be available at http://localhost:9301
.
Project Structure
apps/my-vue-app/
├── src/
│ ├── assets/ # Static assets
│ │ └── images/ # Image files
│ ├── locales/ # Internationalization
│ │ ├── index.ts # i18n configuration
│ │ ├── en_US.ts # English translations
│ │ └── zh_CN.ts # Chinese translations
│ ├── router/ # Vue Router
│ │ ├── index.ts # Router configuration
│ │ └── routes.ts # Route definitions
│ ├── views/ # Page components
│ │ ├── demo/ # Demo pages
│ │ ├── docs/ # Documentation pages
│ │ ├── empty/ # Empty state pages
│ │ └── index/ # Home page
│ ├── App.vue # Root component
│ ├── main.ts # Application entry point
│ └── vue-shim.d.ts # Vue type declarations
├── public/ # Public assets
├── index.html # HTML template
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── vite.config.js # Vite configuration
Core Features
Vue 3 Composition API
vue
<template>
<div class="container">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<button @click="increment">Count: {{ count }}</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
const count = ref(0);
const title = ref('Vue 3 App');
const description = computed(() => `Current count is ${count.value}`);
const increment = () => {
count.value++;
};
</script>
Vue Router
typescript
// router/routes.ts
import type { RouteRecordRaw } from 'vue-router';
export const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('@/views/index/Index.vue'),
},
{
path: '/demo',
name: 'Demo',
component: () => import('@/views/demo/Demo.vue'),
},
];
Pinia State Management
typescript
// stores/counter.ts
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
count.value--;
};
return {
count,
increment,
decrement,
};
});
Internationalization
typescript
// locales/en_US.ts
export default {
common: {
title: 'Vue 3 Application',
description: 'A modern Vue 3 application',
},
navigation: {
home: 'Home',
demo: 'Demo',
},
};
Tailwind CSS Styling
vue
<template>
<div class="min-h-screen bg-gray-100">
<header class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold text-gray-900">
{{ $t('common.title') }}
</h1>
</div>
</header>
<main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div class="px-4 py-6 sm:px-0">
<div class="border-4 border-dashed border-gray-200 rounded-lg h-96">
<p class="text-center text-gray-500 mt-20">
{{ $t('common.description') }}
</p>
</div>
</div>
</main>
</div>
</template>
Development Tools
Vite Configuration
javascript
// vite.config.js
import path from 'path';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import AutoImport from 'unplugin-auto-import/vite';
export default defineConfig({
plugins: [
vue(),
vueJsx(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia', 'vue-i18n'],
dts: path.resolve(__dirname, 'auto-imports.d.ts'),
vueTemplate: true,
}),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@shared': path.resolve(__dirname, '../../_shared'),
},
},
css: {
postcss: path.resolve(__dirname, '../../postcss.config.js'),
},
server: {
host: '0.0.0.0',
port: 9301,
open: false,
cors: true,
},
});
TypeScript Configuration
json
// tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./.output",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@shared/*": ["../../_shared/*"]
}
},
"include": [
"src/**/*",
"src/**/*.vue",
"src/*.vue",
"./auto-imports.d.ts",
"src/vue-shim.d.ts"
]
}
Available Scripts
json
{
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"lint": "eslint src/ --ext .vue,.ts,.js",
"lint:fix": "eslint src/ --ext .vue,.ts,.js --fix",
"format": "prettier --write \"src/**/*.{js,ts,vue,json,css,scss}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,scss}\""
}
}
Best Practices
Component Structure
vue
<template>
<!-- Template content -->
</template>
<script setup lang="ts">
// Script content
</script>
<style scoped>
/* Scoped styles */
</style>
Type Safety
typescript
// Define component props
interface Props {
title: string;
description?: string;
}
const props = withDefaults(defineProps<Props>(), {
description: '',
});
// Define emits
interface Emits {
(e: 'update', value: string): void;
}
const emit = defineEmits<Emits>();
State Management
typescript
// Use Pinia stores
const counterStore = useCounterStore();
// Access state
const count = computed(() => counterStore.count);
// Call actions
const increment = () => counterStore.increment();
Deployment
Build for Production
bash
# Build the application
pnpm build
# The built files will be in the .output directory
Deploy to Vercel
See Vercel Deployment Guide for detailed deployment instructions.