Skip to content

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.