ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Vue 3项目创建与核心开发实战:Vite vs Vue CLI深度解析

Vue 3项目创建与核心开发实战:Vite vs Vue CLI深度解析 1. 从“Hello Vue”到项目骨架两种创建方式的深度抉择如果你正准备从Vue 2迁移或者想直接上手Vue 3第一个拦路虎往往不是新语法而是“项目该怎么创建”。官方文档会告诉你两种方式vue-cli和vite。但文档不会告诉你的是这个看似简单的选择背后是两套完全不同的开发理念和工具链选错了你可能会在后续的开发、调试、构建中踩一堆不必要的坑。今天我们就抛开官方那套温和的说辞从一线开发者的实战角度彻底拆解这两种方式并深入到它们生成的源码骨架里看看Vue 3的“五脏六腑”究竟是如何运作的。简单来说vue-cli像是为你准备好了一切的家装全包服务开箱即用但略显笨重而vite则像一套现代化的精装工具需要你更主动地配置但换来的是极致的速度和清爽。对于新手我通常的建议是如果你需要一个稳定、功能齐全、社区方案成熟的环境来快速启动一个企业级项目或者你的团队对Webpack生态有深厚积累选vue-cli。如果你追求极致的开发体验项目以现代浏览器为主且愿意拥抱更前沿的ES模块ESM生态那么vite是你的不二之选。这个选择会直接影响你后续引入组件库、配置代理、优化打包等一系列操作。别小看这个起点它决定了你项目底层是跑在“老式燃油车”还是“新能源电车”上。接下来我们就手把手走一遍这两种创建流程并重点剖析它们生成的核心源码文件让你不仅会创建更能理解每一个文件、每一行代码的用意。2. 方式一使用 Vue CLI —— 稳健派的“全家桶”Vue CLI 是Vue生态的“老牌管家”基于Webpack提供了从开发、测试到构建的一整套解决方案。它的核心优势在于其强大的插件系统和经过多年验证的稳定配置。2.1 环境准备与项目创建首先确保你的Node.js版本在12.0.0或以上。虽然Vue CLI 5理论上支持Node 12但我强烈建议使用Node.js 16 LTS或18 LTS版本以避免一些潜在的包兼容性问题。你可以通过终端运行node -v来检查。安装Vue CLI的命令依然是全局安装npm install -g vue/cli # 或者使用 yarn yarn global add vue/cli安装完成后通过vue --version验证是否安装成功。接下来是创建项目vue create my-vue3-app执行这个命令后你会进入一个交互式的命令行界面。这里有几个关键选择点直接影响项目结构Please pick a preset: 这里不要直接选默认的“Default ([Vue 2] babel, eslint)”。用键盘上下键选择“Manually select features”手动选择特性。这是关键一步因为默认预设是Vue 2。Check the features needed for your project: 用空格键选中你需要的特性。对于一个标准的Vue 3项目我建议至少选中Choose Vue version(必选用于选择Vue 3)Babel(用于JavaScript语法转换)TypeScript(强烈推荐Vue 3对TS的支持是顶级的)Router(如果项目需要路由)Vuex(如果项目需要状态管理不过Pinia现在是更推荐的选择)CSS Pre-processors(如Sass/Scss方便写样式)Linter / Formatter(代码规范如ESLint Prettier保证团队协作质量)后续的选项根据提示进行选择Choose a version of Vue.js that you want to start the project with: 选择3.x。关于TypeScript的配置如果不太熟悉可以暂时保持默认。对于路由模式新手可以选择history模式它URL更美观但需要后端配合hash模式更简单无需后端配置。对于CSS预处理器个人更推荐Sass/SCSS (with dart-sass)dart-sass是官方主推的实现兼容性更好。对于代码规范选择ESLint Prettier组合并选择Lint on save保存时检查。最后选择将配置放在In dedicated config files独立的配置文件中这样更清晰。等待依赖安装完成项目就创建好了。进入项目目录cd my-vue3-app运行npm run serve即可启动开发服务器。2.2 核心源码骨架解析Vue CLI版创建完成后我们重点看几个核心文件理解Vue CLI为我们搭建的骨架。src/main.ts- 应用入口这是整个Vue应用的起点。Vue CLI TypeScript 版本的这个文件非常典型import { createApp } from vue // 1. 导入Vue 3的工厂函数 import App from ./App.vue // 2. 导入根组件 import router from ./router // 3. 导入路由实例 import store from ./store // 4. 导入状态管理实例 // 5. 创建应用实例并挂载插件 const app createApp(App) app.use(router) app.use(store) // 6. 将应用挂载到DOM元素上 app.mount(#app)关键点解析createApp是Vue 3引入的新API替代了Vue 2的new Vue()。它返回一个应用实例具有更清晰的作用域。插件如router,store通过.use()方法注册到应用实例上这与Vue 2的Vue.use()全局注册有本质区别避免了全局污染也使得创建多个Vue应用实例微前端场景成为可能。.mount()方法替代了Vue 2的$mount作用相同。src/App.vue- 应用根组件这是整个应用的容器组件。template div idnav router-link to/Home/router-link | router-link to/aboutAbout/router-link /div router-view/ /template style langscss #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } /style关键点解析router-view/是Vue Router提供的组件它是一个“占位符”会根据当前URL路径渲染对应的路由组件如Home.vue,About.vue。style langscss标签使用了lang属性这得益于我们创建时选择了Sass预处理器可以直接编写SCSS语法。src/components/HelloWorld.vue- 示例组件这个文件展示了Vue 3的组合式API (Composition API)写法这是Vue 3的核心特性之一。script setup langts import { ref } from vue defineProps{ msg: string }() // 使用 defineProps 进行类型声明式的 props 定义 const count ref(0) // 使用 ref 创建响应式数据 /script template h1{{ msg }}/h1 button typebutton clickcountcount is: {{ count }}/button /template关键点解析script setup是Vue 3.2引入的语法糖是在单文件组件SFC中使用组合式API的编译时语法。在这个标签内的代码会被编译成组件的setup()函数。它的好处是代码更简洁无需显式返回模板需要使用的变量和方法。defineProps是一个编译器宏它只能在script setup中使用用于声明组件的props。这里使用了基于泛型的类型声明{ msg: string }是TypeScript的写法提供了完美的类型推断。ref是创建响应式数据的函数。它接收一个内部值返回一个响应式的、可更改的 ref 对象该对象只有一个.value属性指向内部值。在模板中Vue会自动“解包” ref所以我们可以直接使用count而不是count.value但在script setup内部修改值需要操作count.value。vue.config.js- Webpack配置入口这是Vue CLI项目的核心配置文件。虽然Vue CLI帮我们隐藏了大部分Webpack配置但我们可以在这里进行覆盖和自定义。const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, // 默认情况下 babel-loader 会忽略所有 node_modules 中的文件此选项可强制转译某些依赖 // 配置开发服务器代理解决跨域问题 devServer: { proxy: { /api: { target: http://localhost:3000, // 你的后端服务地址 changeOrigin: true, pathRewrite: { ^/api: // 重写路径去掉请求路径中的 /api 前缀 } } } } })实操心得很多新手在对接后端接口时会遇到跨域问题。在开发环境下最便捷的解决方案就是在vue.config.js中配置devServer.proxy。这样前端发往/api/xxx的请求会被开发服务器代理到目标后端地址完美绕过浏览器的同源策略。生产环境的跨域则需要后端配置CORS或使用Nginx反向代理。3. 方式二使用 Vite —— 极速派的“新锐利器”Vite 是一种新型的前端构建工具由Vue作者尤雨溪开发。它的核心理念是利用现代浏览器原生支持ES模块的特性在开发阶段提供极快的冷启动和热更新。对于Vue 3项目它现在是官方推荐的首选。3.1 项目创建与初体验使用Vite创建Vue 3项目更加轻快。你甚至不需要全局安装任何CLI工具。# 使用 npm 6.x npm create vitelatest my-vite-app --template vue-ts # 使用 npm 7, 需要额外的双横线 npm create vitelatest my-vite-app -- --template vue-ts # 使用 yarn yarn create vite my-vite-app --template vue-ts # 使用 pnpm pnpm create vite my-vite-app --template vue-ts这条命令做了几件事1. 从远程拉取vite模板。2. 创建一个名为my-vite-app的文件夹。3. 使用vue-ts模板初始化项目这个模板包含了Vue 3和TypeScript的基本配置。命令执行速度极快因为它只创建了项目结构和package.json并没有立即安装依赖。接下来进入项目并安装依赖cd my-vite-app npm install # 或 yarn 或 pnpm install安装完成后运行npm run dev。你会惊讶于服务器的启动速度几乎是秒开。这就是Vite的魅力所在。3.2 核心源码骨架解析Vite版Vite生成的项目结构比Vue CLI更简洁。我们来看几个关键文件的不同。index.html- 位于项目根目录的入口这是Vite与Vue CLI一个显著的不同。在Vite项目中index.html不再是打包后生成的而是开发入口和构建入口。!DOCTYPE html html langen head meta charsetUTF-8 / link relicon typeimage/svgxml href/vite.svg / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleVite Vue TS/title /head body div idapp/div script typemodule src/src/main.ts/script /body /html关键点解析script typemodule src/src/main.ts/script这行代码是灵魂。它告诉浏览器以ES模块的方式直接加载/src/main.ts。在开发模式下Vite服务器会拦截这些对原生ES模块的导入请求并进行即时编译和转换。这就是为什么Vite的启动速度如此之快——它不需要像Webpack那样先打包整个应用。#app依然是根容器的id。src/main.ts- 应用入口Vite版内容与Vue CLI版本大同小异但引入方式体现了ES模块的特点。import { createApp } from vue import ./style.css import App from ./App.vue createApp(App).mount(#app)vite.config.ts- Vite的核心配置文件这是Vite的配置文件使用TypeScript编写结构非常清晰。import { defineConfig } from vite import vue from vitejs/plugin-vue // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], // 使用Vue插件 // 配置解析别名方便导入模块 resolve: { alias: { : /src } }, // 开发服务器配置 server: { host: 0.0.0.0, // 监听所有地址方便局域网内手机调试 port: 5173, // 默认端口 open: true, // 启动后自动打开浏览器 proxy: { // 代理配置语法与Webpack略有不同但逻辑一致 /api: { target: http://localhost:3000, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } })关键点解析plugins: [vue()]Vite的核心通过插件体系扩展。vitejs/plugin-vue是官方插件用于解析.vue单文件组件。resolve.alias配置路径别名。将指向/src目录后在代码中就可以用import HelloWorld from /components/HelloWorld.vue的方式导入避免了冗长的相对路径。server.proxy开发服务器代理配置功能同Webpack的devServer.proxy用于解决跨域。src/components/HelloWorld.vue- 示例组件Vite模板默认生成的组件使用的是选项式API (Options API)但我们可以轻松改为组合式API。script setup langts import { ref } from vue defineProps{ msg: string }() const count ref(0) /script template h1{{ msg }}/h1 div classcard button typebutton clickcountcount is {{ count }}/button /div /template踩坑实录如果你在Vite项目中遇到类似error [err_module_not_found]: cannot find package vite imported from的错误这通常不是因为Vite没安装而是你的node_modules依赖安装可能不完整或存在缓存问题。最彻底的解决方法是1. 删除node_modules文件夹和package-lock.json或yarn.lock。2. 清除npm缓存npm cache clean --force。3. 重新运行npm install。这个问题在切换网络环境或使用某些包管理器时偶尔会出现。4. 核心源码深度讲解Vue 3 的响应式心脏ref与reactive理解了项目骨架我们深入到Vue 3最核心的响应式系统。Vue 2的响应式基于Object.defineProperty而Vue 3则使用了功能更强大的Proxy。这带来了质的飞跃也是组合式API的基石。我们主要通过ref和reactive这两个API来使用它。4.1reactive代理整个对象reactive()接收一个普通JavaScript对象返回该对象的响应式代理。import { reactive } from vue const user reactive({ name: 张三, age: 25, hobbies: [读书, 编程] }) // 修改属性视图会自动更新 user.name 李四 user.age // 年龄加1 user.hobbies.push(游泳) // 操作数组底层原理与注意事项reactive返回的是一个Proxy对象不等于原始对象。console.log(user)打印出来的是一个Proxy。它对深层次的对象属性也是响应式的。修改user.hobbies[0]同样能触发更新。它存在一个“局限”仅对对象类型有效Object, Array, Map, Set等对原始值string, number, boolean等无效。因为Proxy只能代理对象。解构或直接赋值给本地变量会丢失响应性。这是一个高频踩坑点。// 错误示例响应性丢失 const { name, age } user // 解构name和age不再是响应式 let localAge user.age // 赋值给普通变量localAge不是响应式 localAge 30 // 此修改不会更新视图也不会影响user.age // 正确做法如果需要解构响应式对象并保持响应性使用 toRefs import { reactive, toRefs } from vue const state reactive({ x: 1, y: 2 }) const { x, y } toRefs(state) // 现在 x 和 y 是响应式的 ref x.value // 有效4.2ref包装任何值为了解决reactive不能处理原始值的问题Vue提供了ref。ref()可以接受任何值返回一个响应式的、可变的ref 对象。import { ref } from vue const count ref(0) // 包装数字 const message ref(Hello) // 包装字符串 const isActive ref(false) // 包装布尔值 const obj ref({ a: 1 }) // 也可以包装对象但内部值会用 reactive 转换 console.log(count) // 输出: { value: 0 }关键行为解析ref对象只有一个.value属性指向内部值。在JavaScript中操作时必须通过.value来访问或修改。在模板中Vue会自动“解包” ref无需写.value。但在script setup中修改时必须写.value。script setup langts import { ref } from vue const count ref(0) const increment () { count.value // 正确在脚本中需要 .value } /script template button clickincrement{{ count }}/button !-- 正确在模板中自动解包无需 .value -- /template当ref的值是一个对象时.value会被reactive()自动转换使其深层响应。此时你可以像操作reactive对象一样操作.value上的属性。const objRef ref({ nested: { count: 0 } }) objRef.value.nested.count // 响应式更新4.3refvsreactive如何选择这是Vue 3新手最常问的问题之一。我的经验法则是使用ref当你定义的是原始值字符串、数字、布尔值。你定义的是一个可能在将来被整个替换的响应式对象。因为ref的.value赋值是响应式的。你需要将响应式数据在组合式函数之间传递。ref更容易被识别和保持响应性。使用reactive当你定义的是一个不需要整体替换的、结构固定的对象例如一个表单对象、一组相关的状态。你希望代码看起来更“自然”直接访问属性而不需要.value在模板中两者都可以但在脚本里reactive对象更简洁。一个常见的组合模式在组合式函数或组件setup中使用一个reactive对象来组织所有相关状态然后在返回时使用toRefs将其解构成多个ref以便在模板中直接使用。import { reactive, toRefs } from vue function useFeature() { const state reactive({ loading: false, data: null, error: null }) const fetchData async () { state.loading true try { // ... 获取数据 state.data await fetchSomeData() } catch (e) { state.error e } finally { state.loading false } } return { ...toRefs(state), // 解构成 ref保持响应性 fetchData } }5. 组合式API实战从“选项”到“组合”的思维转变Vue 3的组合式API不仅仅是语法上的变化更是一种逻辑组织方式的革新。它解决了选项式API在复杂组件中逻辑关注点分散在各处data,methods,computed,watch, 生命周期钩子导致的“碎片化”问题。5.1 生命周期钩子的变化在组合式API中生命周期钩子以函数的形式导入并使用它们的前缀是on。Vue 2 选项式 APIVue 3 组合式 API (script setup内部)beforeCreate不再需要直接用setup()或script setup中的代码替代created不再需要直接用setup()或script setup中的代码替代beforeMountonBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeUnmountonBeforeUnmount(Vue 2 是beforeDestroy)unmountedonUnmounted(Vue 2 是destroyed)activatedonActivated(用于KeepAlive)deactivatedonDeactivated(用于KeepAlive)errorCapturedonErrorCaptured使用示例script setup langts import { onMounted, onUnmounted, ref } from vue const timer refNodeJS.Timeout | null(null) const count ref(0) onMounted(() { console.log(组件挂载了) timer.value setInterval(() { count.value }, 1000) }) onUnmounted(() { console.log(组件卸载了) if (timer.value) { clearInterval(timer.value) } }) /script关键点组合式API的生命周期钩子可以多次调用并且会按照注册顺序执行。这允许你将与同一功能相关的代码如初始化数据和清理定时器组织在一起。5.2computed与watch的新写法计算属性和侦听器也变成了函数式。computed接受一个 getter 函数返回一个只读的响应式 ref 对象。也可以使用带有get和set函数的对象来创建可写的 ref。script setup langts import { ref, computed } from vue const firstName ref(张) const lastName ref(三) // 只读的计算属性 const fullName computed(() { return firstName.value lastName.value }) // 可写的计算属性 const writableFullName computed({ get() { return firstName.value lastName.value }, set(newValue: string) { [firstName.value, lastName.value] newValue.split( ) } }) /scriptwatch用于侦听一个或多个响应式数据源并在其变化时执行副作用函数。script setup langts import { ref, watch } from vue const count ref(0) const user ref({ name: Alice, age: 20 }) // 1. 侦听单个 ref watch(count, (newVal, oldVal) { console.log(count 从 ${oldVal} 变成了 ${newVal}) }) // 2. 侦听一个 getter 函数 watch( () user.value.age, (newAge, oldAge) { console.log(年龄从 ${oldAge} 变成了 ${newAge}) } ) // 3. 侦听多个源 watch([count, () user.value.name], ([newCount, newName], [oldCount, oldName]) { console.log(count或name变了) }) // 4. 深度侦听 reactive 对象 const state reactive({ deep: { nested: { value: 1 } } }) watch( () state.deep, (newVal, oldVal) { // 注意对于对象newVal 和 oldVal 是同一个引用除非进行深拷贝 }, { deep: true } // 深度侦听 ) // 5. 立即执行一次 watch(count, (newVal) { console.log(初始值: ${newVal}) }, { immediate: true }) /scriptwatchEffect立即运行一个函数同时响应式地追踪其依赖并在依赖变更时重新执行。它更适用于“副作用”场景你不需要明确指定侦听源。script setup langts import { ref, watchEffect } from vue const count ref(0) const double ref(0) watchEffect(() { // 这个函数会自动追踪 count.value double.value count.value * 2 console.log(double更新为: ${double.value}) }) // 立即打印: double更新为: 0 count.value // 触发函数重新执行打印: double更新为: 2 /script经验技巧watch和watchEffect的主要区别在于追踪依赖的方式。watch是惰性的需要明确指定侦听源并且只在源改变时触发。watchEffect是立即执行的会自动收集函数体内用到的所有响应式依赖。根据场景选择当你需要基于旧值和新值执行逻辑时用watch当你只需要在依赖变化时执行一个副作用如发送请求、操作DOM时用watchEffect更简洁。6. 工程化进阶TypeScript集成与Vite配置调优对于现代前端项目TypeScript和构建工具的深度配置是提升开发效率和项目质量的关键。6.1 Vue 3 TypeScript 的最佳实践Vue 3 本身是用 TypeScript 编写的提供了完美的类型支持。在script setup langts中你可以获得开箱即用的类型推断。1. 为组件Props提供类型script setup langts // 方式1使用泛型参数推荐最简洁 defineProps{ title: string likes?: number // 可选属性 isPublished: boolean }() // 方式2使用运行时声明当需要更复杂的选项如默认值时 const props withDefaults( defineProps{ title: string likes?: number }(), { likes: 0 // 默认值 } ) /script2. 为组件Emits提供类型script setup langts // 方式1使用类型字面量 const emit defineEmits{ (e: update:title, value: string): void (e: submit, payload: { email: string; password: string }): void }() // 方式2使用运行时声明 const emit defineEmits([update:title, submit]) /script3. 为模板Ref提供类型script setup langts import { ref, onMounted } from vue import type { MyCustomComponent } from ./MyCustomComponent.vue // 为组件实例Ref提供类型 const customComponentRef refInstanceTypetypeof MyCustomComponent | null(null) // 为DOM元素Ref提供类型 const inputRef refHTMLInputElement | null(null) onMounted(() { if (inputRef.value) { inputRef.value.focus() // 类型安全有代码提示 } }) /script template MyCustomComponent refcustomComponentRef / input refinputRef typetext / /template4. 解决“选项‘baseUrl’已弃用”警告如果你在tsconfig.json中看到关于baseUrl的弃用警告这是因为TypeScript新版本推荐使用paths和rootDirs等更灵活的配置。在Vite项目中路径别名通常在vite.config.ts的resolve.alias中配置TypeScript需要通过tsconfig.json的compilerOptions.paths来识别这些别名以提供类型支持。// tsconfig.json { compilerOptions: { target: ES2020, useDefineForClassFields: true, module: ESNext, lib: [ES2020, DOM, DOM.Iterable], skipLibCheck: true, moduleResolution: bundler, allowImportingTsExtensions: true, resolveJsonModule: true, isolatedModules: true, noEmit: true, jsx: preserve, strict: true, noUnusedLocals: true, noUnusedParameters: true, noFallthroughCasesInSwitch: true, // 配置路径映射与 vite.config.ts 中的 alias 对应 baseUrl: ., // 注意此选项在未来版本可能被移除但目前仍需 paths: { /*: [src/*] } }, include: [src/**/*.ts, src/**/*.d.ts, src/**/*.tsx, src/**/*.vue], references: [{ path: ./tsconfig.node.json }] }6.2 Vite 生产构建优化Vite 使用 Rollup 进行生产构建。默认配置已经做了很多优化但我们还可以根据项目需求进行调优。1. 代码分割与异步加载Vite/Rollup 会自动进行动态导入的代码分割。你可以利用import()语法手动分割代码。// 懒加载组件提高首屏速度 const HeavyComponent defineAsyncComponent(() import(./components/HeavyComponent.vue) ) // 路由懒加载 (Vue Router 4) const routes [ { path: /dashboard, component: () import(/views/Dashboard.vue) // 该组件会被单独打包 } ]2. 配置构建选项在vite.config.ts中可以配置build选项import { defineConfig } from vite import vue from vitejs/plugin-vue import { visualizer } from rollup-plugin-visualizer // 可视化分析包大小 export default defineConfig({ plugins: [vue(), visualizer({ open: true })], // 打包后自动打开分析报告 build: { target: es2015, // 构建目标浏览器环境 outDir: dist, // 输出目录 assetsDir: assets, // 静态资源目录 sourcemap: false, // 生产环境关闭 sourcemap减小体积 minify: terser, // 使用 terser 进行压缩 terserOptions: { compress: { drop_console: true, // 移除 console.log drop_debugger: true // 移除 debugger } }, rollupOptions: { output: { // 对 chunk 文件进行命名便于缓存 chunkFileNames: js/[name]-[hash].js, entryFileNames: js/[name]-[hash].js, assetFileNames: [ext]/[name]-[hash].[ext], // 手动拆包将大的依赖单独打包 manualChunks(id) { if (id.includes(node_modules)) { if (id.includes(vue)) { return vue-vendor } if (id.includes(lodash) || id.includes(axios)) { return common-vendor } // 其他 node_modules 依赖打包到一起 return vendor } } } } } })3. 处理环境变量Vite 使用.env文件来管理环境变量。以VITE_开头的变量会被暴露给客户端代码。// .env.development VITE_API_BASE_URLhttp://localhost:3000/api // .env.production VITE_API_BASE_URLhttps://api.yourdomain.com/api在代码中通过import.meta.env.VITE_API_BASE_URL访问。const apiClient axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL })避坑指南关于vite_cjs_tracetrue vite dev这个网络热词它通常出现在一些特定的调试场景或问题排查中。VITE_CJS_TRACE是一个环境变量当设置为true时Vite 会在开发服务器启动时追踪 CommonJS 模块的导入路径这有助于诊断某些与模块解析相关的问题比如循环依赖或路径错误。但在绝大多数正常开发中你不需要关心它。如果你在命令行中看到这个可能是某个脚本或工具链设置了这个变量。如果它导致了问题可以尝试在启动命令前取消它在Unix-like系统用unset VITE_CJS_TRACE在Windows命令提示符用set VITE_CJS_TRACE。从两种创建方式的抉择到核心响应式API的深度剖析再到组合式API的思维转变和工程化配置的调优我们完成了一次从零到一的Vue 3深度上手之旅。选择vue-cli还是vite本质上是在选择项目的技术基调和开发体验。理解ref和reactive是掌握Vue 3响应式系统的钥匙。而拥抱组合式API和TypeScript则是构建可维护、可扩展的现代Vue应用的最佳实践。剩下的就是在具体的项目中不断实践和深化这些概念了。记住工具和语法是死的解决问题的思路和代码组织的清晰度才是核心。
返回列表