{{ item.name }} - {{ item.status }}
Vue3 Taskhub
## Vue3 Task Management System (Taskhub)
In this tutorial, we will build a comprehensive **Vue 3 Task Management System (Taskhub)**. This hands-on project is designed to consolidate your knowledge of Vue 3 and its modern ecosystem by building a production-ready application.
* **Core Features**: Interactive task board, category filtering, persistent data storage, dark mode toggle, and responsive design.
* **Tech Stack**: Vue 3 (Script Setup) + Vite + Pinia + Vue Router + Element Plus + Tailwind CSS.
---
## Learning Objectives & Practical Value
Building this task management system will help you master the following core concepts of the modern Vue ecosystem:
| Learning Point | Practical Value in Production |
| :--- | :--- |
| **Composition API** | Move away from the fragmented Options API and organize code logically by feature. |
| **Pinia** | Replace Vuex with a simpler API, better TypeScript support, and zero boilerplate. |
| **Composables** | Master Vue 3's core design pattern for extracting and reusing stateful logic. |
| **Tailwind CSS** | Utilize the industry-standard utility-first CSS framework to build beautiful, responsive UIs rapidly. |
> **Source Code**: (https://static.jyshare.com/download/vue-task-hub-project.zip)
---
## Phase 1: Project Architecture & Environment Setup
### 1. Vite Configuration
To ensure clean imports and optimal developer experience, we configure path aliases and auto-import plugins in `vite.config.js`:
```javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
// Auto-import Vue, Vue Router, and Pinia APIs globally
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
resolvers: [ElementPlusResolver()],
dts: 'src/auto-imports.d.mjs',
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
resolve: {
alias: {
// Configure '@' to point to the 'src' directory
'@': path.resolve(__dirname, './src'),
},
},
})
```
### 2. Project Standardization
To maintain code quality across team environments, integrate ESLint, Prettier, and Husky:
* **ESLint**: Enforces code quality rules and catches potential bugs.
* **Prettier**: Formats code consistently on save.
* **Husky**: Runs pre-commit hooks to ensure only linted, formatted code is committed to Git.
### 3. Styling with Tailwind CSS
Tailwind CSS is integrated to enable rapid UI development using utility classes. Add Tailwind to your project styles:
```css
/* src/assets/main.css */
@import "tailwindcss";
/* Custom global styles and theme variables */
:root {
--el-color-primary: #4f46e5; /* Match Element Plus with Tailwind Indigo */
}
```
---
## Phase 2: Deep Dive into Composition API
### 1. `ref` vs `reactive`
Understanding when to use each reactive API is crucial for clean state management:
* Use `ref()` for primitive values (`String`, `Number`, `Boolean`) and when you need to reassign entire arrays or objects.
* Use `reactive()` for deeply nested objects or form states where the reference to the object never changes.
```typescript
// Best Practice Example
const searchKeyword = ref(''); // Use ref for primitives
const taskForm = reactive({ // Use reactive for form groups
title: '',
description: '',
priority: 'medium',
dueDate: ''
});
```
### 2. Computed Properties and Watchers
* **`computed`**: Used to filter the task list in real-time based on selected categories or search queries.
* **`watchEffect`**: Automatically tracks dependencies and synchronizes state (e.g., saving to local storage or fetching data when filters change).
```typescript
// Real-time task filtering
const filteredTasks = computed(() => {
return tasks.value.filter(task => {
const matchesSearch = task.title.toLowerCase().includes(searchKeyword.value.toLowerCase());
const matchesCategory = currentCategory.value === 'All' || task.category === currentCategory.value;
return matchesSearch && matchesCategory;
});
});
// Auto-sync state to localStorage
watchEffect(() => {
localStorage.setItem('taskhub_tasks', JSON.stringify(tasks.value));
});
```
### 3. Lifecycle Hooks
Initialize resources when the component mounts and clean them up when it is destroyed to prevent memory leaks.
```typescript
onMounted(() => {
console.log('Taskhub initialized. Loading tasks...');
// Fetch initial data or set up event listeners
});
onUnmounted(() => {
console.log('Cleaning up event listeners...');
// Clear timers, cancel API requests, or remove global event listeners
});
```
---
## Phase 3: Advanced Component Architecture
### 1. Component Communication
Modern Vue uses compiler macros to define component interfaces:
* `defineProps`: Receives data from parent components.
* `defineEmits`: Sends events back to parent components.
* `defineExpose`: Explicitly exposes methods or properties to parent components using `ref`.
```vue
```
### 2. Dependency Injection (`provide` / `inject`)
Avoid "prop drilling" in deeply nested component trees by providing state at the root level and injecting it where needed.
```javascript
// Parent Component (App.vue)
provide('theme', {
isDarkMode,
toggleTheme: () => { isDarkMode.value = !isDarkMode.value }
});
// Deep Child Component (ThemeButton.vue)
const { isDarkMode, toggleTheme } = inject('theme');
```
### 3. Slots (Named & Scoped Slots)
Build highly reusable UI components like Modals and Lists by delegating layout and data rendering to the parent.
```vue
```
### 4. Async Components
Optimize initial page load times by lazy-loading heavy components (like charts or rich text editors) only when they are needed.
```javascript
import { defineAsyncComponent } from 'vue';
const AsyncAnalyticsChart = defineAsyncComponent(() =>
import('@/components/AnalyticsChart.vue')
);
```
---
## Phase 4: State Management & Routing
### 1. Pinia State Management
Pinia acts as the central brain of the application. We split our state into modular stores: `UserStore` and `TaskStore`.
```javascript
// src/stores/taskStore.js
import { defineStore } from 'pinia';
export const useTaskStore = defineStore('tasks', {
state: () => ({
tasks: JSON.parse(localStorage.getItem('tasks')) || [],
loading: false
}),
getters: {
completedTasksCount: (state) => state.tasks.filter(t => t.completed).length,
},
actions: {
addTask(task) {
this.tasks.push({ ...task, id: Date.now(), completed: false });
},
deleteTask(id) {
this.tasks = this.tasks.filter(t => t.id !== id);
}
}
});
```
#### β οΈ The Destructuring Trap (`storeToRefs`)
When destructuring state from a Pinia store, direct destructuring breaks reactivity. Always use `storeToRefs` to preserve reactivity.
```javascript
// β INCORRECT: Breaks reactivity
const { tasks } = useTaskStore();
// CORRECT: Maintains reactivity
const taskStore = useTaskStore();
const { tasks } = storeToRefs(taskStore);
```
### 2. Vue Router & Navigation Guards
Secure routes and manage page transitions using dynamic routing and meta fields.
```javascript
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
component: () => import('@/views/Dashboard.vue'),
meta: { requiresAuth: true, title: 'Dashboard - Taskhub' }
},
{
path: '/login',
component: () => import('@/views/Login.vue'),
meta: { title: 'Login - Taskhub' }
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
// Navigation Guard (Auth Guard)
router.beforeEach((to, from, next) => {
const isAuthenticated = !!localStorage.getItem('user_token');
// Update document title dynamically
document.title = to.meta.title || 'Taskhub';
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login');
} else {
next();
}
});
export default router;
```
---
## Phase 5: Logic Reuse & Performance Optimization
### 1. Custom Composables
Extract reusable stateful logic into clean, testable functions. Below is a custom composable for managing local storage reactively:
```javascript
// src/composables/useLocalStorage.js
import { ref, watch } from 'vue';
export function useLocalStorage(key, defaultValue) {
const storedValue = localStorage.getItem(key);
const data = ref(storedValue ? JSON.parse(storedValue) : defaultValue);
watch(data, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue));
}, { deep: true });
return data;
}
```
### 2. Performance Tuning
* **`shallowRef` & `markRaw`**: Use these to prevent Vue from deeply tracking large, read-only datasets (e.g., complex third-party chart instances or large API responses), significantly reducing CPU overhead.
* **`v-once` & `v-memo`**: Use `v-once` for static content that never updates. Use `v-memo` to conditionally skip re-rendering in long lists unless specific dependencies change.
```vue
```
---
## Phase 6: Production Deployment & Engineering
### 1. Environment Variables
Configure environment variables for different stages of your pipeline:
* **`.env.development`**:
```env
VITE_API_BASE_URL=http://localhost:3000/api
```
* **`.env.production`**:
```env
VITE_API_BASE_URL=https://api.taskhub.com/v1
```
### 2. Build Optimization (Vite Manual Chunks)
To prevent generating a single massive JavaScript bundle, configure Vite to split vendor libraries into separate chunks for better browser caching:
```javascript
// vite.config.js (Partial)
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('element-plus')) return 'element-plus';
if (id.includes('vue') || id.includes('pinia')) return 'vue-core';
return 'vendor'; // Other third-party libraries
}
}
}
}
}
```
### 3. Automated Deployment (GitHub Actions)
Automate your build and deployment process using a CI/CD workflow:
```yaml
# .github/workflows/deploy.yml
name: Deploy Taskhub
on:
push:
branches:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Dependencies
run: npm ci
- name: Build Project
run: npm run build
- name: Deploy to Hosting (e.g., GitHub Pages, Vercel, or VPS)
run: |
# Add your deployment commands here
echo "Deploying build artifacts..."
```
YouTip