CodeBuddy Code CLI 实战:打造符合 Vue 3 规范的现代化待办应用
CodeBuddy Code CLI 实战:打造符合 Vue 3 规范的现代化待办应用
在 Vue 3 生态成熟的当下,“符合规范” 已不再是可选要求 —— 它直接影响项目的可维护性、性能和团队协作效率。但对多数开发者而言,手动配置 Vue 3 规范(如 Composition API 最佳实践、Pinia 状态管理、ESLint 规则)既耗时又容易遗漏。而 CodeBuddy Code CLI(以下简称 Code CLI)能一键生成符合 Vue 3 规范的项目骨架,再配合实战开发,能让我们快速掌握 “规范落地” 的核心逻辑。本文就以现代化待办应用为例,带你从项目初始化到功能上线,全程贴合 Vue 3 官方推荐规范。
第一步:用 Code CLI 初始化符合 Vue 3 规范的项目
Code CLI 的核心优势之一是 “内置规范配置”,初始化时只需选择正确选项,就能规避 “手动配置 ESLint、TypeScript 兼容” 等麻烦。这一步是后续规范开发的基础,务必仔细选择配置项。
1. 环境检查(确保兼容 Vue 3)
首先确认本地环境满足 Vue 3 要求,打开终端执行以下命令:
bash
# 检查 Node.js 版本(Vue 3 要求 ≥14.18.0)
node -v
# 检查 Code CLI 版本(确保是最新版,支持 Vue 3 规范)
codebuddy -v
若 Node.js 版本过低,需前往 Node.js 官网 升级;若 Code CLI 不是最新版,执行 npm update -g @codebuddy/code-cli 更新。
2. 执行初始化命令,锁定 Vue 3 规范
在目标文件夹下打开终端,执行初始化命令:
bash
codebuddy init vue
此时终端会弹出配置选项,严格按以下规范选择(每一步都对应 Vue 3 官方推荐):
- 项目名称:自定义(如
vue3-todo-standard,建议用小写 + 横杠命名,符合前端项目命名规范) - Vue 版本:选择
Vue 3(必须,避免使用 Vue 2 兼容模式) - 是否使用 TypeScript:选择
Yes(Vue 3 对 TS 支持更完善,强类型能减少运行时错误,符合现代化规范) - 状态管理工具:选择
Pinia(Vue 3 官方推荐替代 Vuex,API 更简洁,支持 Composition API) - 包管理器:选择
pnpm(比 npm 更快,且能避免依赖冲突,Vue 生态推荐) - 代码规范工具:勾选
ESLint + Prettier(ESLint 检查语法错误,Prettier 统一代码格式,双工具配合符合 Vue 3 代码规范) - 是否添加路由:选择
Yes(后续扩展 “任务分类页面” 需用到 Vue Router,提前集成符合项目扩展规范)
3. 验证规范配置是否生效
初始化完成后,进入项目目录并启动开发服务:
bash
cd vue3-todo-standard
pnpm dev
启动成功后,做两个关键验证:
- 查看项目目录:是否自动生成
store(Pinia 状态管理目录)、router(路由目录),且组件内默认使用<script setup lang="ts">(符合 Vue 3 Script Setup 规范)。 - 故意写一段不规范代码(如在组件内用
var声明变量),观察终端是否报错(ESLint 应自动检测并提示错误,说明规范配置生效)。
第二步:梳理 Vue 3 规范下的项目结构
符合 Vue 3 规范的项目结构,核心是 “职责单一、目录可扩展”。相比 Vue 2,Vue 3 项目更强调 “状态管理(Pinia)、路由(Vue Router)、组件” 的分离,同时 Script Setup 简化了组件内代码组织。以下是本次实战的关键目录说明(重点关注规范要求):
| 目录 / 文件 | 作用 | 规范要点 |
|---|---|---|
| src/store | Pinia 状态管理目录 | 每个模块单独一个文件(如 todoStore.ts),避免单文件冗余,符合模块化规范 |
| src/router/index.ts | Vue Router 配置文件 | 路由定义需用 createRouter 函数,路径命名用 kebab-case(如 /todo-list) |
| src/components | 自定义组件目录 | 组件名用 PascalCase(如 TodoInput.vue),且单文件组件仅包含单一功能 |
| src/views | 页面级组件目录 | 与路由一一对应(如 TodoHome.vue 对应 / 路由),区别于通用组件 |
| src/components/Base | 基础 UI 组件目录(如按钮、输入框) | 前缀统一用 Base(如 BaseButton.vue),符合组件命名规范 |
| src/types | TypeScript 类型定义目录 | 公共类型(如 Todo.ts)集中管理,避免组件内重复定义,符合 TS 规范 |
本次实战先聚焦核心功能,暂不拆分过多组件,重点先把 “状态管理、路由、组件语法” 的规范落地。
第三步:按 Vue 3 规范开发核心功能(附代码与规范解读)
待办应用的核心功能仍为 “增删改查 + 状态持久化”,但本次开发全程贴合 Vue 3 规范:用 Pinia 管理全局状态(替代组件间传值)、用 Script Setup + TypeScript 写组件、用 Vue Router 实现页面跳转、用 ESLint 保障代码格式。每一步代码都会标注 “规范要点”,帮你理解 “为什么这么写符合 Vue 3 规范”。
1. 第一步:定义 TypeScript 类型(符合强类型规范)
Vue 3 推荐用 TypeScript 定义所有数据类型,避免 “any 类型滥用”。先在 src/types/Todo.ts 中定义待办任务的类型:
typescript
// src/types/Todo.ts
export interface Todo {
id: string; // 用 string 类型(UUID),避免数字 ID 溢出,符合数据安全规范
text: string; // 任务内容
done: boolean; // 完成状态
createTime: number; // 创建时间(时间戳),便于排序
}
规范要点:公共类型必须集中管理,且用 interface 而非 type(interface 支持扩展,更适合定义数据结构,符合 Vue 3 + TS 规范)。
2. 第二步:用 Pinia 管理全局状态(符合状态管理规范)
Vue 3 官方推荐用 Pinia 替代 Vuex,核心原因是 Pinia 支持 Composition API、语法更简洁,且无需嵌套模块。本次待办任务的状态(任务列表、增删方法)全部放在 Pinia 中管理。
(1)创建 Pinia Store
在 src/store/todoStore.ts 中创建状态管理模块:
typescript
// src/store/todoStore.ts
import { defineStore } from 'pinia';
import { Todo } from '@/types/Todo';
import { v4 as uuidv4 } from 'uuid'; // 生成唯一 ID,需先安装:pnpm add uuid @types/uuid
// 用 defineStore 定义 Store,第一个参数为唯一 ID(必须与文件名对应,符合命名规范)
export const useTodoStore = defineStore('todo', {
// 状态:类似 Vue 2 的 data
state: (): { todoList: Todo[] } => ({
todoList: [],
}),
// 计算属性:类似 Vue 2 的 computed,缓存结果
getters: {
// 未完成任务数量(符合“计算属性只做数据转换,不修改状态”规范)
undoneCount: (state) => state.todoList.filter(todo => !todo.done).length,
// 按创建时间排序的任务列表(新任务在前)
sortedTodoList: (state) =>
[...state.todoList].sort((a, b) => b.createTime - a.createTime),
},
// 方法:类似 Vue 2 的 methods,用于修改状态(同步/异步均可)
actions: {
// 初始化任务:从本地存储读取(符合“状态初始化统一管理”规范)
initTodo() {
const savedTodos = localStorage.getItem('vue3-todo-list');
if (savedTodos) {
this.todoList = JSON.parse(savedTodos);
}
},
// 添加任务:接收任务文本,生成完整 Todo 对象(符合“单一职责”规范)
addTodo(text: string) {
if (!text.trim()) return; // 空文本不添加,避免无效数据
const newTodo: Todo = {
id: uuidv4(), // 唯一 ID
text: text.trim(),
done: false,
createTime: Date.now(),
};
this.todoList.push(newTodo);
this.saveTodo(); // 保存到本地存储
},
// 切换任务完成状态:接收 ID,修改对应任务(符合“修改状态通过 actions,不直接操作 state”规范)
toggleTodoDone(id: string) {
const todo = this.todoList.find(todo => todo.id === id);
if (todo) todo.done = !todo.done;
this.saveTodo();
},
// 删除任务:接收 ID,过滤数组(符合“不可变数据”思想,避免直接 splice 修改原数组)
deleteTodo(id: string) {
this.todoList = this.todoList.filter(todo => todo.id !== id);
this.saveTodo();
},
// 保存任务到本地存储:单独抽离,避免重复代码(符合“复用性”规范)
saveTodo() {
localStorage.setItem('vue3-todo-list', JSON.stringify(this.todoList));
},
},
});
规范要点:
- Store 唯一 ID 必须与文件名一致(如
todo对应todoStore.ts),便于定位模块。 - 所有状态修改必须通过
actions实现,禁止在组件内直接修改state(符合 “单向数据流” 规范)。 - 计算属性用
getters,避免在组件内重复写过滤 / 排序逻辑(符合 “逻辑复用” 规范)。
(2)在入口文件挂载 Pinia
打开 src/main.ts,添加 Pinia 挂载代码(确保全局可访问):
typescript
// src/main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia'; // 引入 Pinia
import router from './router'; // 引入路由
import App from './App.vue';
import './style.css';
const app = createApp(App);
app.use(createPinia()); // 挂载 Pinia
app.use(router); // 挂载路由
app.mount('#app');
3. 第三步:配置 Vue Router(符合路由规范)
本次实战需要两个页面:“待办首页”(展示所有任务)、“已完成任务页”(展示已完成任务)。路由配置需符合 Vue Router 4(Vue 3 配套版本)的规范。
(1)创建页面组件
先在 src/views 目录下创建两个页面组件:
TodoHome.vue(待办首页):展示所有任务,包含添加 / 删除功能。TodoDone.vue(已完成任务页):仅展示已完成任务,支持删除。
以 TodoHome.vue 为例(核心代码,重点看 Script Setup 规范):
vue
<!-- src/views/TodoHome.vue -->
<template>
<div class="todo-home">
<h2>我的待办任务</h2>
<!-- 引入基础输入组件 -->
<BaseTodoInput @add-todo="handleAddTodo" />
<!-- 任务列表 -->
<div class="todo-list">
<TodoItem
v-for="todo in sortedTodoList"
:key="todo.id"
:todo="todo"
@toggle-done="handleToggleDone"
@delete-todo="handleDeleteTodo"
/>
</div>
<!-- 未完成任务统计 -->
<div class="todo-count">未完成任务:{{ undoneCount }}</div>
</div>
</template>
<script setup lang="ts">
// 1. 引入依赖(符合“按需引入”规范,避免全局引入冗余)
import { useTodoStore } from '@/store/todoStore';
import BaseTodoInput from '@/components/Base/BaseTodoInput.vue';
import TodoItem from '@/components/TodoItem.vue';
import { onMounted } from 'vue';
// 2. 初始化 Pinia Store(符合“Store 按需使用”规范,不全局注入)
const todoStore = useTodoStore();
// 解构 Store 中的 getters 和 actions(简化代码,符合“便捷性”规范)
const { initTodo, addTodo, toggleTodoDone, deleteTodo, undoneCount, sortedTodoList } = todoStore;
// 3. 生命周期钩子:页面挂载时初始化任务(符合“生命周期统一管理”规范)
onMounted(() => {
initTodo();
});
// 4. 事件处理:接收子组件事件,调用 Store 方法(符合“组件不直接修改状态,仅触发 actions”规范)
const handleAddTodo = (text: string) => {
addTodo(text);
};
const handleToggleDone = (id: string) => {
toggleTodoDone(id);
};
const handleDeleteTodo = (id: string) => {
deleteTodo(id);
};
</script>
<style scoped>
/* 样式用 scoped,避免污染全局(符合“组件样式隔离”规范) */
.todo-home {
max-width: 800px;
margin: 2rem auto;
padding: 0 1rem;
}
.todo-list {
margin: 1.5rem 0;
gap: 0.8rem;
display: flex;
flex-direction: column;
}
.todo-count {
color: #666;
font-size: 0.9rem;
}
</style>
规范要点:
- 组件内用
<script setup lang="ts">(Vue 3 推荐的组件语法,简化代码,支持 TS)。 - Store 按需引入,不全局注入(避免不必要的性能开销,符合 “轻量化” 规范)。
- 组件样式用
scoped(避免样式污染,符合 “组件隔离” 规范)。 - 子组件事件通过
@事件名接收,不直接在子组件修改状态(符合 “单向数据流” 规范)。
(2)配置路由规则
打开 src/router/index.ts,添加路由配置(符合 Vue Router 4 规范):
typescript
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import TodoHome from '@/views/TodoHome.vue';
import TodoDone from '@/views/TodoDone.vue';
// 路由规则:路径用 kebab-case,组件用 PascalCase(符合命名规范)
const routes = [
{
path: '/',
name: 'TodoHome',
component: TodoHome,
meta: { title: '待办首页' } // 页面标题,便于后续统一设置
},
{
path: '/done',
name: 'TodoDone',
component: TodoDone,
meta: { title: '已完成任务' }
}
];
// 创建路由实例:用 createWebHistory(HTML5 历史模式,无 # 号,符合现代化 URL 规范)
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
});
// 全局导航守卫:设置页面标题(符合“路由守卫统一处理公共逻辑”规范)
router.beforeEach((to) => {
if (to.meta.title) {
document.title = to.meta.title as string;
}
});
export default router;
规范要点:
- 路由路径用 kebab-case(如
/done,而非/todoDone),符合 URL 命名规范。 - 使用
createWebHistory(历史模式),避免 hash 模式的#号,符合现代化应用 URL 规范。 - 用全局导航守卫统一设置页面标题,避免在每个组件内重复写
document.title(符合 “公共逻辑集中管理” 规范)。
4. 第四步:开发通用组件(符合组件化规范)
Vue 3 强调 “组件拆分粒度适中”,通用组件(如输入框、任务项)需单独抽离,便于复用和维护。以下是核心通用组件的实现(以 BaseTodoInput.vue 为例):
vue
<!-- src/components/Base/BaseTodoInput.vue -->
<template>
<div class="base-todo-input">
<input
type="text"
v-model.trim="inputValue"
placeholder="请输入任务内容..."
@keyup.enter="handleSubmit"
:placeholder="placeholder"
class="input"
/>
<button @click="handleSubmit" class="btn">添加</button>
</div>
</template>
<script setup lang="ts">
// 1. 定义 props(用 defineProps,符合 Vue 3 组件通信规范)
const props = defineProps<{
placeholder?: string; // 可选 props,有默认值
}>();
// 2. 定义 emits(用 defineEmits,明确事件类型,符合 TS 规范)
const emit = defineEmits<{
(e: 'add-todo', text: string): void; // 事件名 + 参数类型
}>();
// 3. 响应式变量(用 ref,符合 Vue 3 响应式 API 规范)
const inputValue = ref('');
// 4. 事件处理:验证通过后触发事件(符合“子组件不处理业务逻辑,仅传递数据”规范)
const handleSubmit = () => {
if (!inputValue.value) return; // 空值不提交
emit('add-todo', inputValue.value); // 触发事件,传递数据
inputValue.value = ''; // 清空输入框
};
// 5. 设置 props 默认值(符合“props 默认值统一管理”规范)
props.placeholder ??= '请输入任务内容...';
</script>
<style scoped>
.base-todo-input {
display: flex;
gap: 0.5rem;
}
.input {
flex: 1;
padding: 0.8rem;
border: 1px solid #e5e7eb;
border-radius: 0.4rem;
font-size: 1rem;
}
.btn {
padding: 0 1.2rem;
background-color: #2563eb;
color: white;
border: none;
border-radius: 0.4rem;
cursor: pointer;
}
.btn:hover {
background-color: #1d4ed8;
}
</style>
规范要点:
- 用
defineProps和defineEmits替代 Vue 2 的props和$emit(Vue 3 推荐语法,支持 TS 类型检查)。 - 通用组件(Base 前缀)仅负责 UI 和数据传递,不处理业务逻辑(符合 “单一职责” 规范)。
- Props 默认值用
??=设置,避免在defineProps内写默认值(更灵活,符合 TS 规范)。
第四步:Vue 3 规范落地的关键检查(避坑指南)
开发完成后,需对照 Vue 3 规范做一次 “全面检查”,避免遗漏关键细节。以下是本次实战的核心检查项,可直接复用:
| 规范类别 | 检查项 | 是否符合规范 |
|---|---|---|
| 组件语法 | 所有组件是否使用 <script setup lang="ts">? |
□ 是 □ 否 |
| 状态管理 | 是否通过 Pinia actions 修改状态,无组件内直接修改 state? | □ 是 □ 否 |
| 路由规范 | 路径是否用 kebab-case,是否使用 createWebHistory 模式? | □ 是 □ 否 |
| 组件通信 | 是否用 defineProps/defineEmits,无 \(parent/\)children 通信? | □ 是 □ 否 |
| 代码格式 | ESLint + Prettier 是否无报错,代码缩进 / 命名统一? | □ 是 □ 否 |
| 类型安全 | 是否无 any 类型,所有数据都有明确 TS 类型定义? | □ 是 □ 否 |
| 样式隔离 | 组件样式是否用 scoped,无全局样式污染? | □ 是 □ 否 |
若存在 “不符合” 项,需针对性修改:
- 若组件用 Options API:重构为 Script Setup(参考
TodoHome.vue语法)。 - 若有 any 类型:补充 TS 类型定义(如
Todo接口)。 - 若路由用 hash 模式:修改为
createWebHistory(参考router/index.ts)。
第五步:打包优化与部署(符合现代化应用规范)
Vue 3 项目的打包优化有明确规范,核心是 “减小包体积、提升加载速度”。Code CLI 生成的项目已内置基础优化,但仍需补充关键配置。
1. 打包优化配置
打开 vite.config.ts(Code CLI 生成的 Vite 配置文件),添加以下优化项(符合 Vite + Vue 3 打包规范):
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
export default defineConfig({
plugins: [vue()],
// 路径别名:简化 @ 开头的路径引用(符合“路径统一”规范)
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
// 打包优化:减小包体积(符合“性能优化”规范)
build: {
sourcemap: false, // 关闭 sourcemap(生产环境无需调试,减小包体积)
rollupOptions: {
output: {
// 拆分公共依赖(如 Pinia、Vue Router),避免重复打包(符合“代码分割”规范)
manualChunks: {
pinia: ['pinia'],
router: ['vue-router'],
},
},
},
},
// 开发环境优化:提升热更新速度(符合“开发效率”规范)
server: {
hmr: true, // 开启热模块替换
open: true, // 启动后自动打开浏览器
},
});
2. 执行打包命令
在终端执行打包命令,生成优化后的静态文件:
bash
pnpm run build
打包完成后,dist 文件夹体积会比未优化前减小 30% 左右(视依赖情况而定)。
3. 部署到 Vercel(符合现代化部署规范)
Vercel 对 Vue 3 项目支持友好,且能自动识别 Vite 配置,步骤如下:
- 把项目推送到 GitHub 仓库(确保包含
package.json和vite.config.ts)。 - 打开 Vercel 官网,用 GitHub 账号登录。
- 点击 “New Project”,选择刚推送的仓库,点击 “Deploy”。
- 等待部署完成,Vercel 会生成一个在线链接(如
https://vue3-todo-standard.vercel.app/),可直接访问。
规范要点:部署时无需手动修改配置,Vercel 会自动读取 package.json 中的 build 命令(符合 “自动化部署” 规范)。
总结:Vue 3 规范的核心价值与扩展方向
通过本次实战,你会发现:Vue 3 规范并非 “束缚”,而是 “提升效率的工具”——Pinia 简化了状态管理,Script Setup 减少了冗余代码,TypeScript 提前规避了错误,Code CLI 则让规范落地更轻松。
更多推荐


所有评论(0)