ARTICLE DETAIL

资讯详情

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

Vue3实战:从环境搭建到部署避坑全记录

Vue3实战:从环境搭建到部署避坑全记录 1. 项目背景与整体定位1.1 这个“02”项目到底是什么先说结论这不是什么高深课题而是一次把 Vue 从“看过文档”变成“跑起来、用起来、出问题能修”的完整体验。为什么标题叫“02”因为这是同一系列的第二次上手前一次可能还在折腾脚手架、目录结构这一次的目标很明确——把 Vue 项目从零搭起来完成几个真实功能然后把过程中踩的坑、绕的路、想明白的原理全部记录下来。在做这个项目之前我对 Vue 的状态停留在“知道有响应式、有组件化、有虚拟 DOM 这些概念”的阶段网上的教程也刷了不少但真正打开编辑器动手写项目时发现完全不是一回事。装环境、拉依赖、选路由模式、配跨域、处理视频流、调样式、打包部署每一步都有细节等着。这篇博文就是把这一整套体验记录下来适合两类人看一类是刚学完 Vue 基础、准备动手做点东西的新手另一类是工作中被 Vue 项目折磨过、想看看别人怎么处理公共问题的前端开发。我的建议是不要把它当成教程来背当成“排查手册 避坑清单”来用更合适。核心解决的问题有四个环境怎么一次性配好而不是反复折腾路由、生命周期、v-model 这些机制在真实项目里到底是什么表现遇到 m3u8 视频流、跨域、线上样式失效这类硬骨头怎么啃以及面试官问到的那些 Vue 考点是不是真的在项目里理解过。1.2 技术选型先想清楚别急着敲命令这个项目我选择的是 Vue 3 Vite Vue Router 4 Pinia状态管理看需求决定是否引入的组合。为什么不用 Vue 2 或者 Vue CLI并不是旧技术不能用而是既然做“体验”和“验证”就应该面向当前主流生态。Vue 3 组合式 API 在组织业务代码时优势明显社区组件库也已经全面兼容Vite 的开发服务器冷启动快热更新顺滑配置比 Webpack 时代轻量太多。不过这里要提醒一句如果你所在团队的项目还在用 Vue 2 和 Webpack那这个项目体验只能作为个人练习不能直接套用于生产环境。技术选型永远要服从团队现状和业务约束而不是追求“最新最好”。我这个项目本来就是个人体验性质所以选了更符合未来方向的一套组合。2. 环境配置与依赖管理的完整复现2.1 Node 和包管理器第一个容易翻车的地方很多人以为“安装依赖”就是敲一句npm install那么简单其实第一步就容易被坑Node 版本。Vue 3 Vite 需要 Node.js 16.18 或更新版本新版本 Vite 对 Node 18/20 支持更友好。如果你的机器上装的是 14 或更早版本npm create vite时会直接报错或者报环境不支持。建议先执行node -v检查版本不满足就通过 nvmNode 版本管理器切换到合适版本。Windows 上推荐用 nvm-windowsmacOS 直接用 nvm 脚本即可。包管理器的选择也很关键。npm 是默认选项但安装速度慢、磁盘占用大同一个项目反复 clone 下来重装依赖时体验很明显。我个人在实际体验中更推荐 pnpm它的硬链接机制让多个项目共享依赖装包速度快很多占空间也小。如果你在团队协作中还需要统一包管理器版本避免package-lock.json和pnpm-lock.yaml混用导致的依赖树差异。这也是我在这个项目里学到的第一课环境一致性是“项目能跑”的最基本前提。2.2 Vite 创建项目文件结构、选项含义要弄清环境搞定后用npm create vitelatest创建项目时Vite 会问两个问题框架选什么、是否使用 TypeScript。这里我建议初学者直接选 JavaScript 而不是 TypeScript原因不是 TS 不好而是先把 Vue 本身的机制打通再叠加类型系统避免一次引入太多变量导致排查困难。项目结构生成后你会看到根目录下有index.html、package.json、vite.config.js、src目录等文件。很多初学者拿到手就开始写业务代码其实应该先理解三个配置相关的核心入口。一是index.htmlVite 项目不像传统 Webpack 项目有public/index.html作为模板而是直接把根目录的index.html作为入口页面并且通过script typemodule src/src/main.js加载入口 JS。二是vite.config.js配置代理、别名、构建输出都在这里后面会将详细配置方法。三是src/main.js这是 Vue 应用的引导文件负责创建实例、挂载路由和 Pinia。把这三个文件的职责分清楚后面遇到问题不会一头雾水。2.3 安装依赖的真实过程与常见报错在项目根目录执行pnpm install或npm install正常情况下会看到依赖树解析、下载、链接的日志。但我必须坦白说“正常情况下”这四个字往往是一种奢望实际体验中我至少遇到三种典型报错。第一种是ERESOLVE unable to resolve dependency tree这通常是因为依赖版本冲突比如本地 Node 版本过低、某些包要求 Node 版本范围不匹配项目配置等。一般清理缓存、删除node_modules和锁文件后重新安装可以解决。第二种是网络问题导致的下载失败比如某些大包如esbuild下载超时可以通过配置镜像源解决。第三种是运行npm run dev时报Error: Cannot find module vite说明依赖没有完整安装或安装中断重装依赖基本能修复。关于镜像源我不建议大家在个人博客里写得过于绕直接说结论如果公司内网有私有 npm 源优先用公司源并配置.npmrc个人学习项目用默认源就行。镜像源只是一种加速手段不是代码质量的核心别把时间浪费在这上面。2.4 项目跑起来之后的第一个观察点执行pnpm run dev成功后控制台会输出本地访问地址http://localhost:5173。第一次打开页面时Vite 的默认页面会展示 Vue 标志和示例组件。很多人就停在这一步但我建议做两件事一是打开浏览器开发者工具看 Network 面板里请求了哪些模块体会一下 Vite 开发模式下的module加载方式与传统打包后加载的不同二是去src/components里改一下标题文字感受一下热更新HMR到底有多快。关于热更新有几个细节值得注意Vite 的 HMR 是通过 ES Module 的模块边界实现的修改组件局部样式时页面不会整体刷新而是只替换受影响的模块这个体验比刷新整个页面要好很多。如果你修改的是main.js引用的入口文件那才会触发页面级刷新。这也是为什么我建议把这个项目当成“体验”项目来做很多开发体验细节只有真正手摸到才能记住。3. 核心机制拆解路由、生命周期、响应式3.1 路由到底选 history 还是 hashVue Router 4 创建路由实例时核心选择是createWebHistory()还是createWebHashHistory()。这个选择直接影响 URL 形态和部署方式。createWebHistory使用 HTML5 History APIURL 干净/user/123但有个致命前提服务器需要配置将前端路由回退到index.html否则生产环境部署后刷新页面就会 404。createWebHashHistory则是通过 URL 中的#来实现路由跳转/#/user/123对服务器要求低但 URL 不美观。在这个个人体验项目中开发环境用 history 模式没有任何问题因为 Vite 自带的开发服务已经配置了对 History API 的 fallback。但如果要发布到线上就一定要确认 Nginx 或容器服务是否做了 try_files 配置。我自己在这个项目上线部署时就踩了刷新 404 的坑后面第 5 章会专门讲这个问题的排查和处理过程。3.2 动态路由与路由守卫的落地场景动态路由是这个项目里我体会最深的一个点。很多人的需求是“根据登录用户的权限动态生成菜单和路由”这话说起来轻松实现起来却有讲究。Vue Router 4 里addRoute()可以在运行时动态添加路由但是要注意动态添加的路由不会自动反映到现有的导航守卫逻辑里你需要自己维护一个“已添加路由”的标志避免每次路由跳转时重复添加导致警告。路由守卫则是控制访问权限的关键。这个项目里我做了一个简单的登录拦截全局前置守卫router.beforeEach里判断本地存储是否有 token没有就去 /login有的情况下如果已经动态添加过路由就直接放行否则先await store.dispatch(generateRoutes)动态生成路由再用next({ ...to, replace: true })重进一次目标路由。很多人会在这里被绕晕核心就是next()时机问题动态路由必须在前置守卫里完成注册然后在 next 时重定向到当前路由确保目标路由已经存在。3.3 生命周期函数从 created 到 unmounted 的真实触发顺序Vue 3 组合式 API 中onMounted、onUpdated、onUnmounted这几个生命周期钩子被推到了前端开发者面前但很多人问我created去哪了其实是合进了setup()本身。实操中setup()是在组件实例创建之前触发的此时你拿不到this但可以通过参数props和ctx获取数据和上下文。onMounted是在组件挂载到 DOM 后执行此时可以调用document、访问 DOM 元素、发起异步请求等。更重要的一个坑是onUnmounted它对应 Vue 2 的beforeDestroy在组件销毁前做一些清理清除定时器、取消事件监听、释放视频流资源等。如果你写的是一个使用 WebRTC 或播放器的组件不在onUnmounted里做释放很容易出现切走页面后摄像头灯还亮着或者视频播放声音还在的情况。我在这个项目里特意写了一个带有onMounted和onUnmounted的播放组件验证的就是这个释放过程的必要性。顺带一提Vue 3 里onUpdated不常用但如果你在ref更新后需要操作更新后的 DOMwatch或nextTick往往比onUpdated更好用。3.4 v-model 的自定义实现和双向绑定本质v-model 是 Vue 里“被魔法化”最严重的一个特性。很多人只知道它能用在表单元素上却不知道它本质上是:modelValue和update:modelValue事件的语法糖。在 Vue 3 里自定义组件中使用 v-model 需要显式声明modelValueprop并在需要更新值的时候emit(update:modelValue, newValue)。这个项目里我实现了一个自定义搜索框组件功能是搜索关键字输入、防抖处理、父组件拿到值后请求接口。通过这个组件把 v-model 的自定义协议落地了一遍。具体做法是组件内部维护一个 ref监听输入事件在 watch 中发出update:modelValue同时接收外部传入的modelValue并在外部值变化时同步到内部状态。这里最容易出现死循环或值不同步的问题解决方法是区分“用户输入引起的更新”和“外部 prop 变化引起的更新”不要用同一个逻辑去处理两种来源。面试时如果有人问 v-model 的原理你可以答出“语法糖、modelValue、update:modelValue”这十四字口诀但只有亲手写过才会真正理解“为什么需要区分数据源”这种深层问题。3.5 自定义指令与 $attrs机制很立体Vue 中的自定义指令是容易被忽略但很好用的特性。这个项目里我做了一个“按钮权限”指令v-permissionuser:add指令的mounted钩子会读取当前用户的权限码数组如果匹配不到直接移除 DOM 节点。这比在模板里写一堆v-if判断权限要优雅得多。同时这也解释了 Vue 的指令本质它只是钩子函数与 DOM 的绑定协议而不是模板逻辑的主角。$attrs则是解决组件属性透传的关键。没有inheritAttrs: false约束时组件根元素会自动继承没有被 props 消费的属性比如class、style、>
返回列表