刚入行那会儿,我对WEB前端开发流程的理解特别朴素:拿到设计稿,写页面,调接口,发上线。直到完整跟过一个从零启动的项目,被需求变更、联调扯皮、上线前一夜的突发bug轮流折腾过以后,才发现这条链路上真正的“流程”二字,比想象中重得多。这篇文章想跟你聊聊我实际跑过无数遍的前端开发流程,从需求评审到上线的每一步,包括每个环节该干什么、容易在哪儿翻车、怎么提前避免。适合刚入行的前端同学、带新人的工程师,以及那些总觉得自己“干得很乱”的独立开发者。
1. 需求阶段:真正该在开会前确认的东西
1.1 需求评审不是在等原型,是在给开发排雷
很多同学一听到需求评审,第一反应是掏出电脑等原型图、等设计稿。我一开始也这样,后来发现这是最大的错觉。需求评审真正要做的事情,是把一个模糊的“我想要做个XX功能”变成一套能指导开发落地、能验证结果是否达标的清单。
你想想装修房子的时候,你不可能只跟工头说一句“装得好看一点”。你得告诉他:这个柜子要放什么、将来住几个人、电视墙留不留插座、厨房要不要洗碗机的位置。前端开发一模一样,需求方说“做一个用户登录注册功能”的时候,越是经验丰富的开发者,越要在一开始把细节问清楚。
我举一个实际遇到的例子。某电商活动项目,需求方最初的需求只有一句话:做一个用户登录/注册功能。如果直接开始做,大概率会在联调阶段陷入下面这些问题的泥潭:
- 登录方式到底用手机号还是邮箱,还是两种都要?第三方登录要不要?
- 验证码是图形验证码还是短信验证码?短信发送频率有没有限制?
- 用户点登录按钮之后,按钮是置灰防重复提交,还是允许连续点击然后由接口去重?
- 接口返回慢、返回超时、返回系统异常的时候,页面上分别展示什么?有没有统一的错误提示文案?
- 未登录用户访问需要登录才能看的页面,是直接跳转到登录页,还是先弹窗提示再跳转?
- 密码输入框默认是否明文展示,有没有“显示/隐藏”切换开关?
- 登录成功之后跳转到哪里?是从哪来回到哪去,还是固定跳首页?
- 每个入口的埋点参数怎么命名,数据由谁提供?
这些问题看起来零散,实际上每一条都对应着前端的代码分支、异常态、交互状态和数据上报。前端返工率高的项目,十有八九不是代码水平问题,而是开发前没把这些“边界情况”问清楚。需求评审不是等待一个设计稿,而是拿着这些问题去“排雷”,把后面会踩的坑提前挖出来。
1.2 把“做完”定义清楚,才谈得上验收
很多项目延期,不是开发偷懒,而是“做完”这个词的定义太模糊。产品经理觉得“做完”是页面能点、能跳转,后端觉得“做完”是接口能吐数据,前端觉得“做完”是视觉还原度达标,测试觉得“做完”是所有用例通过。所以我在需求阶段就强烈建议团队做一件事:字段级别的验收清单。
这个清单不需要多复杂,但一定要落到“字段”和“交互”这个颗粒度。比如登录页面,我会和产品经理一起把表格列出来:
| 页面区域 | 交互要求 | 接口依赖 | 异常处理 |
|---|---|---|---|
| 手机号输入框 | 格式校验、位数限制、禁止输入非法字符 | 无需接口 | 格式错误时给出提示并聚焦到输入框 |
| 验证码输入框 | 超过有效期后提示重新获取 | 获取验证码接口 | 获取失败时提示原因,60秒倒计时重置 |
| 登录按钮 | 点击后置灰并显示加载状态,防止重复提交 | 登录接口 | 失败时恢复按钮态并展示服务端返回的错误信息 |
| 登录成功 | 记录登录态、触发跳转 | 登录后获取用户信息接口 | 用户信息接口失败时,尝试用本地缓存兜底 |
这张表做完之后,“做完”就变成了一件可以逐项打勾的事。开发过程中卡在哪个字段,就去和产品、后端对哪个字段,不需要整个页面推翻重来。我见过太多项目死在“口头对齐”上——产品说改个按钮文案,前端顺手把按钮状态逻辑也改了,结果漏了异常分支,上线后用户连续点击导致重复下单。
需求阶段还有一个重要动作是评估工期。我在拆任务时有一个习惯:把每个功能拆成独立可验证的小块,每块控制在0.5到2天的工作量。小于0.5天的拆得太碎,管理成本高;大于2天的块风险太大,中途出问题很难定位。拆完之后集体过一遍,把“隐藏细节”补进评估里,比如导入导出功能的文件体积上限、大数据量列表的渲染性能、定时刷新页面的中断恢复。这些细节往往才是工期超标的元凶。
2. 技术选型与工程化:为什么我坚持先定“规矩”再写代码
2.1 技术栈选型的三个现实标尺
到了技术方案设计阶段,很多团队容易陷入“选最新框架”的执念。我个人认为,技术选型真正该看的不是热度和新鲜度,而是三个现实标尺:团队熟悉度、生态成熟度、维护周期。
团队熟悉度很好理解,选一个全组都没用过的框架,光是踩坑学习就要多花两三周。生态成熟度指的是框架周边配套是否齐全,组件库、状态管理、路由、权限方案、脚手架工具、招聘市场上能不能找到人接手,这些都算生态。维护周期是问自己:这个项目要活多久?如果是个活动页,上线一个月就下线,那用轻量方案快速搞定即可;如果是个要维护三到五年的后台管理系统,就必须选一个长期稳定、社区活跃、文档完善的技术栈。
我举个对比场景,某团队同时接到两个项目:一个是持续迭代的门户平台,一个是单次活动注册页。门户平台我会建议用完整技术栈加组件库加状态管理加权限方案,哪怕前期搭建成本高一点,后面一两年都是受益的;活动注册页则完全可以用轻量方案,甚至直接用原生加少量脚本,没必要为了“统一技术栈”把一个小页面也套进重型框架里。技术选型没有绝对的优劣,只有是否匹配项目生命周期和团队能力。
选型确定之后,有一件事必须立刻做:锁定版本。我见过大量项目因为某个依赖升级了小版本,构建报错、样式错乱、接口异常。现实的做法是在项目里固定主依赖版本号,并且把生成的依赖锁定文件提交到代码仓库。依赖升级要当作一个独立任务来评估,不能顺手升级。
2.2 规范先行的真实目的:让别人的代码像自己的代码
项目初期就把目录结构、命名方式、Git提交格式、分支管理、代码风格全部定下来,看起来像在“立规矩”,实际上是为了降低沟通成本。多人协作的时候,最耗时间的不是写代码,而是理解别人的代码。每个目录下是什么、组件文件叫什么、样式类名怎么起、提交信息怎么描述,如果每个人都有自己的习惯,团队就成了一锅粥。
我常用的目录结构是这样的:
src/ api/ # 接口请求统一封装 assets/ # 静态资源 components/ # 公共组件 pages/ # 页面级组件 router/ # 路由配置 store/ # 全局状态管理 utils/ # 工具函数 styles/ # 全局样式命名规范也提前约定好:组件文件名使用大驼峰命名,普通工具文件使用小驼峰,样式类名统一用短横线连接。Git提交信息我习惯采用类似feat: 增加结算页、fix: 修复列表滚动穿透的格式,这样后面看提交历史的时候,每条提交在干什么一目了然。分支管理上,主分支保持可发布状态,开发分支按功能或版本命名,个人开发分支随意一点问题不大,但合入主分支之前必须保证测试通过。
这一整套规范的核心目的,是让团队里任何一个人打开别人的代码,都能像看自己昨天写的代码一样顺畅。我经常打一个比方:厨房里每个调料瓶都贴上标签,不光是为了好看,是为了做饭的人不用花时间猜“这个瓶子里到底是酱油还是醋”。
3. 从空仓库到首个可运行页面:项目初始化的每一步
3.1 脚手架与依赖安装的几个隐藏坑
项目初始化看起来是最简单的环节:拉一个脚手架模板,装一下依赖,跑起来就算完。但这一步实际上藏着不少坑,我一个个说。
第一个坑是环境版本不一致。不同同事电脑上的Node版本、包管理器版本可能各不相同,同一个项目在A同学电脑上跑得好好的,到B同学电脑上就报错。解决的思路是统一版本。我一般会在项目文档里明确写清楚要求的运行时版本,同时建议团队使用版本管理工具来切换,避免“我本地是好的啊”这种经典甩锅台词。
第二个坑是版本依赖混乱。初始化项目的时候,直接执行安装最新依赖,往往会把一些间接依赖拉到很新的版本,而这些版本可能和项目的核心依赖不兼容。正确做法是初始化完成后,确认锁定文件生成正常,并且把这个锁定文件提交到仓库。后续谁安装了新依赖,代码评审的时候要能看到对应差异。
第三个坑是装完依赖不验证直接开写。我见过不少同事执行完安装命令,看到控制台没有报错就认为环境好了,结果一跑开发命令,缺某个插件、某个配置不对、端口被占用,各种问题接踵而来。我自己的习惯是初始化之后,先完整跑一遍dev命令看到页面可访问,再跑一遍build命令确认产物能正常生成,最后跑一遍lint确认代码风格检查通过,三步全绿才算是环境真正就绪。
3.2 目录、路由与接口层的初始约定
初始化阶段还要把基础设施打好。一个典型的包配置文件里,至少要把开发、构建、预览、代码检查这几组脚本定义清楚:
{ "name": "shop-mall-admin", "version": "1.0.0", "private": true, "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview", "lint": "eslint . --ext .js,.vue" } }接口层我习惯统一封装一个请求实例,把baseURL、超时时间、请求拦截器、响应拦截器都放在一个文件里管理。请求拦截器负责把登录凭证加到头部,响应拦截器负责统一处理业务错误码和网络异常。这样页面里永远不会散落一堆if (xxx) { ... }的业务码判断,维护起来舒服得多。
路由配置的初始约定也一样重要。页面级组件建议使用路由懒加载,也就是访问到对应路径时才加载该页面代码。这个优化一开始做起来很简单,后面等页面多了就是实打实的首屏性能收益。同时路由的路径命名要保持语义化,/user/login一看就知道是用户登录页,而不是/page1、/page2这种代码写起来省事、维护起来想哭的命名。
4. 组件拆分与状态管理:页面开发的搭积木方法论
4.1 粒度:组件大而全还是小而碎
页面开发阶段,前端的主要工作就是把视觉稿变成代码。这里最常见的问题不是写不出来,而是组件拆分的粒度拿不准。拆得太粗,组件变成一个大杂烩,改一处动全身;拆得太细,层层嵌套,状态传得晕头转向。
我理解组件拆分的核心是“边界”:这个组件是否独立承担一个完整功能?它是否只通过少量输入输出和外部交互?它内部的状态变更会不会影响外部?如果三个答案都是肯定的,它就是值得独立出来的组件。
实践中我习惯把组件粗略分成三层。页面级组件负责路由和整体布局,业务组件负责绑定某一块业务状态和交互,展示组件只接收数据渲染样式,不关心数据从哪来。这个分层不是说必须建三个目录,而是写代码时心里要有一杆秤:展示组件尽量保持“笨”,业务组件负责“想”,页面级组件负责“串”。
4.2 状态该放在哪层
状态管理的核心问题只有一句话:这份状态到底属于谁。很多刚入行的同学一见多页面要共享数据,就习惯性地把东西全部塞进全局状态里。全局状态确实方便,但滥用之后会带来新的痛苦:数据来源变多、改动影响面变大、调试变得很困难。全局状态像储物柜,把所有东西都塞进去,找起来的时候也很费劲。
我自己的习惯是分层处理。表单输入、弹窗开关、按钮加载状态这种局部状态,一定留在组件内部,绝不外溢;用户信息、权限、全局配置这种多页面都要用的数据,放全局状态;接口返回的数据,尽量按页面或模块管理,能用服务端状态管理处理的就用它,不要盲目复制成一份前端全局副本。
举一个购物车页面的例子。加入购物车按钮的 loading 状态属于按钮组件内部,商品列表数据属于购物车页面,购物车总数量、角标数字属于全局导航状态。如果你把 loading 也放到全局,就会出现在组件销毁后还残留全局状态的问题;如果你把商品列表数据也塞进全局,商品多了之后性能和内存都扛不住。
开发顺序上也有一点小经验。我一般先写静态结构和样式,把页面在视觉上做到位;然后接入 Mock 数据,让页面动起来;最后再处理边界状态,比如加载中、空数据、接口失败、网络超时。这个顺序的好处是每一步都有清晰的完成标准,不会做到一半突然发现基础结构都没搭对。
4.3 自测不是“看着没问题”
页面开发阶段的“自测”,如果只是自己在浏览器里点一遍、看到效果差不多就说完成了,那是在给后面的联调和测试埋雷。一个负责任的自测清单,至少要覆盖以下几种情况:
- 每个交互是否都有加载中、成功、失败、空数据四种反馈状态
- 快速连续点击按钮、刷新页面、切换路由时,状态是否稳定不报错
- 常用屏幕尺寸下布局是否正常,文字是否溢出遮挡
- 文案里的数字、金额、时间格式是否统一,是否有时区问题
- 页面恢复、路由回退、浏览器前进后退时,数据是否保持一致
我自己在提交代码之前,会额外做一次“逆向测试”:故意把接口返回的数据改成空数组、缺字段、超长字符串,看看页面会不会崩溃、会不会出现明显布局错乱。发现一次,就补一个容错分支,这样线上环境再遇到脏数据,页面也能兜住。
5. 联调那些事:接口沟通、字段变更与在线调试
5.1 拿到接口文档后的第一件事
联调阶段里,前端最容易犯的一个错误是:接口文档一拿到手,就开始写回调处理逻辑。我踩过这个坑之后才意识到,拿到接口文档后的第一件事,应该是把接口字段和页面字段做逐一映射,标出每个字段的用途、格式、可空性,然后对比页面需要的数据和接口提供的字段。
比如页面上要展示用户昵称、头像、注册时间,接口里字段名是userName、avatarUrl、createTime还是username、avatar、created_at?返回的注册时间是秒级时间戳还是毫秒级时间戳?头像地址是完整域名还是相对路径?这些细节不核对清楚,联调时就是反复改代码、反复重新打包,浪费大量时间。
为了让前后端并行开发,前端在页面开发阶段就会使用 Mock 数据。这里有一个关键约定:Mock 数据的格式必须和真实接口返回结构保持一致,否则等到接真实接口时才发现字段层次对不上,开发阶段的“顺利”就全变成返工成本。接口文档里如果没有明确统一返回结构,我建议向团队建议使用类似下面的格式,并写进接口规范文档:
{ "code": 0, "message": "ok", "data": {} }这是最简单的约定,但非常实用。不管业务多复杂,统一的外层结构都能让前端的响应拦截器一次性处理好错误码和异常分支。
5.2 联调中最常见的三种“伪Bug”
联调过程中,大量报出来的“bug”其实根本不是前端代码逻辑问题,而是前后端数据口径不一致。我把最常见的三种“伪Bug”列在这里,你在排查时可以少走很多弯路。
第一种是参数格式不对。前端要传一个整数类型参数,实际在拼接 URL 时变成了字符串;后端要求时间格式是2024-01-01 00:00:00,前端传出去的是2024/01/01。这类问题很好排查,打开网络面板看实际发出的请求体就能定位。
第二种是字段名不一致。前端的接口调用端用驼峰命名,后端返回的字段用下划线命名,或者某个字段首字母大写,都会导致页面上拿不到值。我习惯在拿到接口文档后列一个字段映射表,联调前先核对一遍,能省掉巨量的排查时间。
第三种是数据结构悄然变化。昨天data字段还是数组,今天就变成了对象,或者原来某个接口一定返回的字段,现在可能不返回了。前端如果直接用response.data[0].id这种访问方式,一定会炸。这也是我在开发阶段反复强调容错分支的原因——不是你太小心,而是真实环境里什么意外都可能发生。
5.3 在线调试的实用操作
联调阶段免不了在线调试。浏览器开发者工具的面板那么多,其实常用的就几个:Console 看日志和错误,Network 看请求耗时、状态码、响应体,Sources 打断点看代码执行过程,Performance 看性能耗时。
我自己的排查习惯是先看 Network 面板,确认请求到底是哪一步出了问题。请求没发出去,问题大概率在前端参数构造、拦截器或者路由拦截;请求发出去了但状态码异常,问题在服务端;状态码正常但页面不对,再看响应数据格式和前端渲染逻辑。这样一层层缩小范围,比在代码里瞎猜快得多。
移动端调试稍微麻烦一点,但有浏览器的远程调试能力配合开发者工具也能应付。关键是要在开发阶段就做好跨设备测试,不要等到上线前才用手机访问线上地址,那时候发现问题往往已经晚了。
6. 测试、性能优化与上线:前端交付前的最后三道关
6.1 功能测试之外,还有兼容性与回归
页面功能开发完,联调联通了,可距离真正的“可上线”还有一段路。这段路上最容易被忽视的是兼容性和回归测试。很多项目上线后出的问题,不是新功能开发的时候出的,而是改了一个公共组件,导致其他页面跟着挂了。
兼容性测试要根据项目用户的实际环境来定。面向内部办公人员的后台系统,浏览器环境相对统一;面向公众的 C 端页面,浏览器环境就千奇百怪了。我在项目交付前习惯拉一张兼容性矩阵,列清楚哪些浏览器和系统版本是必须支持的,哪些可以做降级处理。同时会用自动化测试工具跑一遍核心链路,再结合人工测试把视觉、交互、文案过一遍。
回归测试更是不能省。改了一个页面,要确认这个页面本身没问题,还要确认依赖这个页面的上下游页面也没问题。尤其是全局公共组件,比如导航栏、页脚、通用弹窗、登录态判断,改动影响面是全局性的。上线前走一遍核心业务链路的主流程,排名不分先后:注册登录、列表加载、详情查看、提交操作、结果反馈。这五个步骤都没问题,才有底气按下发布按钮。
6.2 性能指标:用数据说话
性能优化不是一个玄学动作,而是一个用数据说话的工程步骤。拿到一个页面之后,先测量,再优化,最后再测量对比收益。不测量就盲目优化,是最容易白费力气的事情。
我现在比较关注的核心指标包括首屏加载耗时、交互响应速度、视觉稳定性以及页面布局偏移。针对这些指标,常见的优化手段其实都是约定俗成的:
| 优化手段 | 解决的问题 | 实施要点 |
|---|---|---|
| 路由懒加载 | 首屏加载资源过大 | 按路由拆分代码块 |
| 图片懒加载 | 列表页图片过多导致卡顿 | 滚动到可视区域再加载 |
| 静态资源压缩 | 请求体积过大 | 构建时开启压缩,压缩率要平衡体积和CPU消耗 |
| 数据请求缓存 | 重复请求导致浪费 | 对只读接口做短时缓存 |
| 骨架屏 | 白屏时间过长体验差 | 加载时展示页面骨架结构 |
优化完成之后,最好把结果整理成前后对比数据,让团队和产品都能看到实际收益。优化如果让首屏从 3 秒变成 1 秒,这个结果是很有说服力的;但如果是“感觉快了”,那很容易被质疑。
还有一个细节值得提:性能优化要关注真实的移动端网络环境,而不是只在开发机的千兆宽带上测。我自己在优化完成后,会特意把网络模拟成慢速环境再看一遍首屏体验,这样得出来的结论才接近真实用户感受。
6.3 发布不是点一下按钮
发布环节看起来最简单,点一下构建、点一下部署,实际上是最不允许出错的环节。这里面的坑主要不是技术,而是流程。一个标准的发布清单,至少应该包含下面这些检查项:
| 检查项 | 说明 |
|---|---|
| 分支已合入主分支 | 确认所有代码都进入发布分支 |
| 版本号已更新 | 发布包和代码仓库版本一一对应 |
| 环境变量已确认 | 发布到生产环境的环境变量不能带测试环境的配置 |
| 构建产物已验证 | 本地完整构建过一次,确认无报错 |
| 回滚方案已准备 | 记录上一个可用版本,出问题能快速回退 |
发布方式上,大一点的项目建议走小范围验证再全量铺开。先让一部分用户使用新版本,观察错误率和核心指标有没有异常,再逐步放开。全量发布之后也不要马上就宣布“完成”,还要持续关注错误上报和运行日志,线上问题往往在发布后几分钟内暴露,越早发现越容易处理。
我见过不少团队发布前准备得很好,发布完就把监控这回事忘了。结果用户那边页面白屏、接口报错,开发这边完全不知情,等到用户来投诉才发现问题。所以发布不是流程终点,监控和响应机制才算是给这次发布画上句号。
我自己在经历了好几个项目从零到上线的完整流程之后,最大的感受是:所谓前端的开发流程,说到底不是一份挂在文档系统里没人看的制度,而是每个开发者脑子里的那根弦——需求阶段多问一句,联调阶段多核对一次,上线前多走一遍核心链路。流程感建立起来之后,项目推进反而会轻松很多,因为你已经知道每一步之后会发生什么、风险点在哪里、什么时候该停下来确认。希望这篇经验对你有用。