作为资深前端架构师,基于 Vue 技术栈(Vue 2/Vue 3 + Vuex/Pinia + Vue Router)的大规模项目经验,核心挑战依然是 “可扩展性”“可维护性” 和 “团队协作效率”。
一、架构设计:从 “能用” 到 “可持续”
1. 模块化与分层设计(避免 “意大利面代码”)
-
核心原则:按 “职责分层” 而非 “技术栈分层”。例:
传统分层(UI 层、业务层、API 层)在复杂业务中易导致耦合,建议按 “领域驱动设计(DDD)” 拆分:-
「基础层」:工具函数、常量、API 请求封装(Axios 统一拦截、错误处理)。
-
「领域层」:按业务域拆分模块(如电商的 “商品域”“订单域”“用户域”),每个域包含独立的状态(Pinia 模块)、模型(Class/Interface)、业务逻辑(避免跨域直接调用,通过 “领域服务” 通信)。
-
「应用层」:页面 / 组件,负责组装领域层能力,不包含复杂业务逻辑(Vue 组件的 script 部分只做数据绑定和事件转发)。
-
「基础设施层」:路由(Vue Router)、状态管理(Pinia)、权限、监控等横切关注点。
-
2. 组件化设计:从 “复用” 到 “标准化”
-
组件分级体系:
-
「通用组件」:上传、过滤、分页等基础 UI(如基于 Element Plus UI 二次封装)BaseButton、BaseInput、BaseSelect。
-
「业务组件」:带领域逻辑的组合组件(如 “商品卡片”“订单状态组件”,通过 Props 接收数据,
emits传递事件)。ProductCard -
「布局组件」:TheHeader、TheMain、TheFooter。
-
-
组件设计原则:
-
单一职责:一个组件只做一件事(例:“搜索框” 不应包含 “搜索结果列表” 的渲染逻辑,可拆分为
<SearchInput>和<SearchResult>,通过父组件协调)。 -
Props 设计:明确必填 / 可选,复杂配置用 “配置对象” 而非零散 props(例:
{ formConfig: { labelWidth: 120, items: [] } })。
-
3. 状态管理:从 “全量共享” 到 “精准控制”
-
状态分层策略(以 Pinia 为例,替代 Vuex):
-
「全局状态」:用户信息、权限、全局配置(用 Pinia 的
defineStore定义全局 store,通过useStore()在组件中访问,严格控制字段,避免冗余)。 -
「模块状态」:某业务域的共享状态(如 “购物车” 在商品页和结算页共享,用 Pinia 的
modules拆分,每个模块独立维护 state/actions/getters)。 -
「页面状态」:仅当前页面使用(用 Vue 组件的
ref/reactive,配合setup语法糖,避免无脑丢全局)。
-
-
踩坑教训:早期项目用单一 Vuex store 存储所有状态,导致一个商品详情页的修改,触发首页、分类页等无关组件重渲染,页面卡顿率提升 30%,拆分后性能恢复正常。
4. 路由设计:从 “静态配置” 到 “动态权限路由” 实操
-
核心需求:支持权限控制、动态加载、路由缓存(基于 Vue Router 4)。
-
实现方案:
-
路由配置中心化:用数组定义路由元信息(
path、component、meta: { title, auth, keepAlive })。 -
权限过滤:登录后根据用户角色,通过
router.addRoute动态生成可访问路由表(避免在组件内写大量v-if="hasPermission")。 -
路由懒加载:结合 Vue 的异步组件
defineAsyncComponent,按模块拆分 chunk(例:component: () => import('@/pages/order'))。实操 -
路由缓存:通过
<keep-alive>组件缓存页面(配合meta.keepAlive控制),结合activated钩子处理缓存刷新逻辑(需注意缓存失效策略)。
-
5. 跨端架构:从 “多端独立开发” 到 “一套代码多端运行” 简历
-
方案选择:
-
轻量级跨端:用 CSS Media Query + 动态导入(针对 H5 移动端 / PC 端差异,通过 Vue 的
v-if="$isMobile"区分)。 -
中重度跨端:UniApp(小程序 + H5+App)或 Vue Native(原生 App),需注意:
- 封装 “平台适配层”:将平台特有 API(如微信小程序的
wx.xxx和 H5 的window.xxx)统一封装(例:import { request } from '@/utils/adapter',内部通过process.env.VUE_APP_PLATFORM切换实现)。 - 避免 “大而全”:核心业务用跨端代码,平台特有功能(如微信支付、原生推送)用条件编译(
#ifdef MP-WEIXIN)单独实现。
- 封装 “平台适配层”:将平台特有 API(如微信小程序的
-
-
实战案例:某跨境电商项目,通过 UniApp 实现微信小程序、支付宝小程序、H5 三端统一,开发人力减少 60%,但需定期同步各平台 API 更新,避免适配失效。
二、工程化:从 “手动操作” 到 “自动化流水线”
1. 脚手架与项目初始化
-
核心目标:统一技术栈、规范目录结构、集成基础能力(路由、状态管理、API 封装等)。
-
实现方式:
- 基于 Vue CLI 或 Vite 创建自定义模板,通过
vue create或vite create选择 “业务模板”(如 “PC 管理系统”“H5 活动页”“小程序组件库”)。 - 初始化项目自动集成:ESLint/Prettier(代码规范,配合
eslint-plugin-vue)、husky(Git Hooks)、commitlint(提交规范)、README 模板(包含启动、部署、开发规范)。
- 基于 Vue CLI 或 Vite 创建自定义模板,通过
-
效果:新成员入职后,1 小时内可基于脚手架启动开发,避免 “每个项目一套规范” 的混乱。
2. 构建与性能优化
-
构建工具选择:
-
中大型项目:Vue CLI(基于 Webpack,生态完善,适合复杂配置),需优化:
- 多进程构建:
thread-loader提升编译速度。 - 代码分割:
splitChunks提取公共库(vue、element-plus)和业务公共模块。 - 树摇(Tree Shaking):开启
production模式 + ES Module,删除未引用代码。
- 多进程构建:
-
超大型项目:Vite(开发时快于 Webpack 10 倍 +),利用其原生 ESM 和按需编译特性,注意兼容第三方 CommonJS 模块(通过
@vitejs/plugin-commonjs处理)。
-
-
资源优化:
- 图片:使用
vite-plugin-image-optimizer压缩,大图片用 WebP 格式(通过<picture>标签降级兼容),列表图片懒加载(结合 Vue 指令v-lazy)。 - CSS:通过
vue-style-loader提取 CSS 为单独文件,使用purgecss删除未使用样式,关键 CSS 内联到 HTML。 - JS:
terser压缩,开启 gzip/brotli(nginx 配置或 Vite 的compression插件),非首屏 JS 延迟加载(import().then()动态导入)。
- 图片:使用
3. 代码质量与测试体系
-
质量门禁:
- 提交阶段:husky + lint-staged 实现 “仅校验修改的文件”(如
*.vue文件通过eslint --fix自动修复),commitlint 强制规范提交信息(如feat(订单): 新增优惠券功能)。 - 构建阶段:CI 流水线执行 ESLint、TypeScript 类型检查、单元测试(覆盖率≥70%),失败则阻断构建。
- 提交阶段:husky + lint-staged 实现 “仅校验修改的文件”(如
-
测试策略:
实操- 单元测试:用 Jest + Vue Test Utils 测试工具函数、Composition API、纯业务逻辑(例:价格计算、权限判断)。
- 组件测试:用 Vue Test Utils 测试组件渲染和交互(如点击按钮是否触发
emit,输入框是否双向绑定),避免测试实现细节。 - E2E 测试:用 Cypress 测试核心流程(如 “登录 - 加购 - 下单”),定期回归(每日凌晨自动执行)。
-
经验:某支付系统通过测试体系,线上 bug 率从千分之 5 降至千分之 1.2,回归测试时间从 3 天缩短至 2 小时。
4. CI/CD 流水线
-
核心流程:
- 开发者提交代码到 Git 仓库(触发 pre-commit 钩子校验)。
- 合并到 dev 分支:自动执行构建、测试,部署到测试环境。
- 合并到 release 分支:生成版本号(基于 semver),部署到预发环境,触发自动化验收测试。
- 合并到 master 分支:部署到生产环境(支持灰度发布:先部署 10% 机器,监控无异常后全量)。
-
工具链:GitLab CI/Jenkins(流水线) + Docker(容器化部署) + Nginx(静态资源服务 + 灰度配置)。
三、性能优化:从 “能用” 到 “流畅”
1. 首屏加载优化(核心指标:FCP、LCP)
-
关键手段:
-
减少请求数:合并 HTTP 请求(雪碧图、JS/CSS 合并),使用 HTTP/2 多路复用。
-
减小资源体积:代码分割(首屏只加载核心 JS)、路由懒加载(Vue Router 的异步组件)、资源压缩(gzip/brotli)。
-
预加载策略:
- 关键资源:
<link rel="preload" href="app.js" as="script"> - 预连接:
<link rel="preconnect" href="https://api.example.com">
- 关键资源:
-
服务端渲染(SSR)/ 静态生成(SSG):对 SEO 要求高或首屏内容固定的页面(如首页、商品详情页),用 Nuxt.js 实现,FCP 可提升 50%+。
-
-
案例:某电商首页通过 Nuxt.js SSR + 图片懒加载,LCP 从 3.2s 优化至 1.8s,用户停留时长提升 20%。
2. 运行时性能优化(核心指标:FID、CLS)
-
渲染优化:
- 避免频繁 DOM 操作:通过 Vue 的响应式系统批量更新(Vue 会自动合并
nextTick内的 DOM 操作),长列表用虚拟列表(vue-virtual-scroller)渲染万级数据。 - 减少重绘重排:样式集中修改(通过
class切换而非v-bind:style),使用will-change: transform(将元素提升为单独图层)。
- 避免频繁 DOM 操作:通过 Vue 的响应式系统批量更新(Vue 会自动合并
-
事件优化:
- 防抖节流:搜索输入、窗口 resize 等高频事件(用
lodash的debounce/throttle,或自定义 Composition API 封装)。 - 事件委托:列表项点击事件绑定到父元素(通过
@click="handleItemClick($event)",在回调中判断目标元素)。
- 防抖节流:搜索输入、窗口 resize 等高频事件(用
-
内存管理:
- 及时销毁定时器、事件监听(在 Vue 组件的
beforeUnmount钩子中清理)。 - 避免闭包内存泄漏(例:组件内定义的函数引用外部大对象,需在卸载时手动置空)。
- 及时销毁定时器、事件监听(在 Vue 组件的
3. 监控与性能埋点
-
实现方案:
- 前端监控 SDK:采集性能指标(通过
PerformanceAPI)、错误信息(window.onerror、Vue 的errorHandler)、用户行为(点击、页面停留)。 - 日志上报:采用 “批量上报 + 离线存储”(
localStorage暂存,网络恢复后发送),避免频繁请求影响性能。 - 告警机制:设置阈值(如 LCP>3s、错误率 > 1%),通过钉钉 / 邮件实时告警,定位问题链路(结合用户 ID、设备信息、接口日志)。
- 前端监控 SDK:采集性能指标(通过
-
经验:某金融平台通过监控发现,某安卓机型在输入验证码时频繁崩溃,最终定位为第三方输入法与 Vue 双向绑定(
v-model)的兼容性问题,针对性修复后崩溃率降为 0。
四、团队协作:从 “各自为战” 到 “高效协同”
1. 规范先行:代码、文档、流程
-
代码规范:
- 基于
eslint-plugin-vue扩展,明确:命名规则(组件 PascalCase,函数 camelCase)、注释要求(复杂逻辑必须写注释,组件需说明 props 和用法)、目录结构(按领域 / 页面划分)。 - 用 TypeScript 强制类型约束(Vue 3 +
<script setup lang="ts">),减少 “传参类型错误”(大型项目必选,初期成本高,长期收益显著)。
- 基于
-
文档体系:
- 架构文档:核心模块设计、数据流图、技术选型理由(避免新人 “重构” 合理设计)。
- 接口文档:用 Swagger/APIFox 管理,前后端同步更新(可通过 OpenAPI 生成 TS 接口类型,避免手动维护)。
- 组件文档:用 Storybook 展示 Vue 组件用法、参数、交互效果(开发时可直接在 Storybook 调试,无需启动整个项目)。
-
协作流程:
- 分支管理:采用 Git Flow(master/release/develop/feature/hotfix),feature 分支从 develop 创建,通过 MR 合并(至少 1 人 Code Review 通过)。
- 迭代管理:2 周一个迭代,每日站会同步 blockers,迭代末进行复盘(技术债、流程问题)。
2. 技术沉淀与复用
- 内部组件库:基于业务场景沉淀组件(如 “表单设计器”“报表组件”),避免重复开发(某企业级 SaaS 通过组件库沉淀,新模块开发效率提升 50%)。
- 工具函数库:封装通用逻辑(如日期处理、权限判断、数据转换),通过 Vue 的
plugins全局注册,避免 “复制粘贴” 导致的不一致。 - 最佳实践库:记录常见问题解决方案(如 “跨域处理”“大屏适配”“打印功能”),新成员可快速查阅。
五、踩坑总结与核心原则
- 不要过度设计:架构是 “演进” 出来的,初期用简单方案解决问题(如小项目用 Vuex 的
modules即可,不必上来就上 Pinia 的细粒度拆分),随着业务增长逐步优化。 - 重视技术债:
每个迭代预留 20% 时间重构,避免 “紧急需求堆砌”导致后期无法维护(曾因连续 6 个月只做新功能,重构时花了 3 个月才理清逻辑)。 - 以业务为中心:技术是服务于业务的,选择 “合适的技术” 而非 “最新的技术”(例:中小型项目用 Vue CLI 足够,不必强行上微前端)。
- 关注用户体验:性能、兼容性、交互流畅度直接影响业务指标,每个需求评审都需纳入考量。
大规模 Vue 项目的本质是 “系统工程”,需要架构设计、工程化、性能优化、团队协作多维度协同。核心目标不是追求 “完美架构”,而是在 “业务快速迭代” 与 “系统稳定性” 之间找到平衡,让项目在持续增长中依然保持可控。
大规模前端项目结构
以下是基于 Vue 3 + JavaScript + Pinia + Vue Router 的大规模前端项目精简结构,保留核心分层逻辑,合并冗余目录,更侧重 “实用主义” 和 “快速上手”,适合需要兼顾规模与开发效率的团队:
项目根目录结构
project-name/
├── .github/ # GitHub配置(Issue模板、PR workflows)
├── .husky/ # Git Hooks(pre-commit、commit-msg校验)
├── docs/ # 项目文档(架构说明、接口文档、开发规范)
├── public/ # 静态资源(无需构建,直接复制到dist)
│ ├── favicon.ico
│ └── robots.txt
├── scripts/ # 工具脚本(部署、构建优化、数据模拟)
├── src/ # 源代码核心目录(精简分层)
├── tests/ # 测试目录
│ ├── unit/ # 单元测试(Jest + Vue Test Utils)
│ └── e2e/ # E2E测试(Cypress)
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── .eslintrc.js # ESLint配置(vue规则)
├── .prettierrc # 代码格式化配置
├── index.html # 入口HTML
├── package.json # 依赖管理
├── README.md # 项目说明(启动、部署、目录说明)
└── vite.config.js # Vite构建配置
核心源代码目录(src/)
精简分层逻辑:基础层(base)、业务域(domains)、应用层(application)、基础设施(infrastructure) ,合并细分子目录,减少层级嵌套。
src/
├── app/ # 应用入口
│ ├── app.vue # 根组件
│ ├── main.js # 入口文件(初始化Vue、注册插件)
│ └── config.js # 全局配置(标题、主题等)
├── assets/ # 静态资源(需构建处理)
│ ├── css/ # 全局样式
│ │ ├── variables.scss # 样式变量(主题色、尺寸)
│ │ └── common.scss # 公共样式(重置、基础类)
│ ├── img/ # 图片(按业务域分类)
│ └── fonts/ # 字体文件
├── base/ # 基础层(通用能力,无业务逻辑)
│ ├── constants/ # 全局常量(枚举、固定配置)
│ └── utils/ # 工具函数(格式化、校验、存储等)
├── api/ # API层(按业务域封装接口)
│ ├── client.js # Axios实例(拦截器、基础配置)
│ ├── user.js # 用户域接口
│ ├── order.js # 订单域接口
│ └── product.js # 商品域接口
├── domains/ # 业务域(核心逻辑,按业务拆分)
│ ├── user/ # 用户域
│ │ ├── store.js # Pinia状态(用户相关状态)
│ │ └── service.js # 业务服务(用户逻辑处理)
│ ├── order/ # 订单域(同上)
│ └── product/ # 商品域(同上)
├── application/ # 应用层(组件与页面,组装业务能力)
│ ├── components/ # 组件(按级别拆分)
│ │ ├── base/ # 原子组件(按钮、输入框等基础UI)
│ │ ├── business/ # 业务组件(商品卡片、订单状态等)
│ │ └── layouts/ # 布局组件(主布局、弹窗布局)
│ └── pages/ # 页面(按路由拆分)
│ ├── user/ # 用户相关页面(登录、个人中心)
│ ├── order/ # 订单相关页面(列表、详情)
│ └── product/ # 商品相关页面(列表、详情)
├── infrastructure/ # 基础设施(横切能力)
│ ├── router/ # 路由
│ │ ├── index.js # 路由实例与配置
│ │ └── guards.js # 路由守卫(权限、登录拦截)
│ ├── store/ # Pinia入口(聚合所有域状态)
│ │ └── index.js # 导出createPinia及所有store
│ ├── permission.js # 权限管理(角色、按钮权限)
│ ├── plugins/ # 插件注册(UI库、第三方工具)
│ └── monitor.js # 监控埋点(性能、错误、行为)
└── mock/ # 本地模拟数据(开发环境用)
├── user.js
└── order.js
核心目录职责说明(精简逻辑)
-
base/ 基础层存放完全通用的能力:常量(如正则、状态码)、工具函数(如日期格式化、本地存储封装),可直接复用到其他项目,不依赖任何业务代码。
-
api/ API 层按业务域(用户、订单、商品)封装接口请求,每个文件对应一个业务域的所有接口(如
user.js包含登录、获取用户信息等),内部调用client.js(Axios 实例),只处理接口请求 / 响应,不包含业务逻辑。 -
domains/ 业务域(核心)每个业务域(如
user/)包含:store.js:Pinia 状态(仅存储当前域的共享数据,如用户信息、订单列表);service.js:业务逻辑处理(调用api/接口,处理数据转换、状态更新,如 “登录后保存用户信息到 store”)。原则:域内高内聚,域间低耦合(跨域调用通过service,不直接操作其他域的store)。
-
application/ 应用层
-
components/:按 “原子 - 业务 - 布局” 分级,组件只做两件事:- 接收
props展示数据,通过emit传递用户操作; - 调用
domains/的service或store获取 / 修改数据(不写复杂业务逻辑)。
- 接收
-
pages/:页面是组件的组合,处理路由参数、页面级私有状态(用ref/reactive),调用业务域的service完成流程(如 “提交订单”= 收集表单 + 调用order.service.create())。
-
-
infrastructure/ 基础设施处理跨业务的通用技术能力:路由配置与守卫、Pinia 聚合、权限控制、插件注册(如 Element Plus)、监控埋点,不包含业务逻辑。
精简优势
- 减少认知负担:合并细分子目录(如去掉
models/,业务数据结构通过注释和示例说明),适合 JavaScript 灵活开发的特点。 - 降低层级嵌套:核心目录最多 3 层(如
src/domains/user/store.js),避免 “找文件像走迷宫”。 - 保留扩展性:业务域拆分清晰,新增业务只需在
domains/、api/、pages/新增对应文件,不影响其他模块。
此结构在保持大规模项目所需的 “模块化”“低耦合” 特性的同时,通过精简目录和合并冗余层级,让团队更专注于业务开发,适合 Vue 3 + JavaScript 技术栈的中大型项目(如企业 SaaS、电商平台)。
0 到 1 搭建一个前端项目主要流程
十、核心功能模块
1. 用户权限系统
- 多角色管理(卖家 / 买家 / 运营商 /销售)
- 动态菜单生成(基于用户权限)
- 细粒度权限控制(按钮级、页面级)
- 单点登录(SSO)集成
- 登录状态保持与自动续签
2. 文件上传
- 大文件分片上传 / 断点续传
- 文件预览(支持多种格式)
- 文件权限与共享
- 文件版本控制
3. 消息中心
- 消息通知中心(WebSocket)
- 消息推送与订阅
4. 国际化支持
- 多语言切换(i18n)
- 时间 / 货币格式本地化
- 语言包动态加载
4. 主题色
- 2、基础层设计
- 2.1、自建Gitlab
- 2.2、版本管理
- 2.3、自动编译发布Jenkins
- 2.4、纯前端版本发布
- 2.5、统一脚手架
- 2.6、Node中间层
- 2.7、埋点系统
- 2.8、监控和报警系统
- 2.9、安全管理
- 2.10、Eslint
- 2.11、灰度发布
- 2.12、前后端分离
- 2.13、Mock
- 2.14、定期备份
- 3、应用层设计
- 3.1、多页和单页
- 3.2、以应用为单位划分前端项目
- 3.3、基础组件库的建设
- 3.4、技术栈统一
- 3.5、浏览器兼容
- 3.6、内容平_台建设
- 3.7、权限管理平_台
- 3.8、登录系统设计(单点登录)
- 3.9、CDN
- 3.10、负载均衡
- 3.11、多端共用一套接口
- 4、总结
1、综合
分为基础层和应用层。
基础层偏基础设施建设,与业务相关性较低。
应用层更贴近用户,用于解决某一个问题。
部分两个都沾边的,根据经验划分到其中一个。
1.4、其他
由于已经谈到架构层级,因此很多内容,并不仅仅只属于前端领域,有很多内容是复合领域(前端、后端、运维、测试),因此需要负责架构的人,技术栈足够全面,对未来发展有足够的前瞻性。
文章的内容结构为:【项目】—>【解决的问题和带来的好处】—>【项目的实际意义】
2、基础层设计
2.1、自建Gitlab
强烈建议使用Gitlab进行版本管理,自建Gitlab难度并不大,方便管理,包括代码管理、权限管理、提交日志查询,以及联动一些第三方插件。
意义:公司代码是公司的重要资产,使用自建Gitlab可以有效保护公司资产。
2.2、版本管理
版本管理的几个关键点:
- 发布后分支锁死,不可再更改:指当例如0.0.1版本成功发布后,不可再更改0.0.1分支上的代码,否则可能会导致版本管理混乱。
- 全自动流程发布;指应避免开发者提交后,手动编译打包等操作,换句话说,开发人员发布后,将自动发布到预发布/生产环境。开发人员不和相关环境直接接触。实现这个需要参考下面的2.3。
- 多版本并存;指当例如发布0.0.2版本后,0.0.1版本的代码应仍保存在线上(例如CDN),这样当出现线上bug时,方便快速回滚到上一个版本。
意义:提高项目的可控性。
2.3、自动编译发布Jenkins
这个工具用于在代码发布后,执行一系列流程,例如自动编译打包合并,然后再从Gitlab发布到CDN或者静态资源服务器。 使用这个工具,可以让一般研发人员不关心代码传到Gitlab后会发生什么事情,只需要专心于开发就可以了。
意义:让研发人员专心于研发,和环境、运维等事情脱钩。
2.7、埋点系统
强烈推荐前端做自己的埋点系统。这个不同于后端的日志系统。
前端埋点系统的好处:
- 记录每个页面的访问量(日周月年的UV、PV);
- 记录每个功能的使用量;
- 捕捉报错情况;
- 图表化显示,方便给其他部门展示;
埋点系统是前端高度介入业务,把握业务发展情况的一把利剑,通过这个系统,我们可以比后端更深刻的把握用户的习惯,以及给产品经理、运营等人员提供准确的数据依据。当有了数据后,前端人员就可以针对性的优化功能、布局、页面交互逻辑、用户使用流程。
2.8、监控和报警系统
监控和报警系统应基于埋点系统而建立
- 当访问量有比较大的变化(比如日PV/UV只有之前20%以下)时,自动触发报警,发送邮件到相关人员邮箱;
- 比如报错量大幅度上升(比如200%或更高),则触发报警;
- 当一段时间内没有任何访问量(不符合之前的情况),则触发报警;
- 每过一段时间,自动汇总访问者/报错触发者的相关信息(例如系统、浏览器版本等);
建设这个系统的好处在于,提前发现一些不容易发现的bug(需要埋点做的比较扎实)。有一些线上bug,因为用户环境特殊,导致无法被开发人员和测试人员发现。但其中一部分bug又因为不涉及资金,并不会导致资损(因此也不会被后端的监控系统所发现),这样的bug非常容易影响项目里某个链路的正常使用。
意义:
提高项目的稳定性,提高对业务的把控能力。降低bug数,降低资损的可能性,提前发现某些功能的bug(在工单到来之前)。
2.9、安全管理
前端的安全管理,通常要依赖于后端,至于只跟单纯有关系的例如dom.innerHTML= 'xxx '这种太基础,就不提了。
安全管理的很难从架构设计上完全避免,但还是有一定解决方案的,常见安全问题如下:
- XSS注入:对用户输入的内容,需要转码(大部分时候要server端来处理,偶尔也需要前端处理),禁止使用eval函数;
- https:这个显然是必须的,好处非常多;
- CSRF:要求server端加入CSRF的处理方法(至少在关键页面加入);
意义:减少安全漏洞,避免用户受到损失,避免遭遇恶意攻击,增加系统的稳定性和安全性。
2.10、Eslint
Eslint的好处很多,强烈推荐使用:
- 降低低级bug(例如拼写问题)出现的概率;
- 增加代码的可维护性,可阅读性;
- 硬性统一代码风格,团队协作起来时更轻松;
总的来说,eslint推荐直接配置到脚手架之中,对我们提高代码的可维护性的帮助会很大。可以考虑在上传到gitlab时,硬性要求eslint校验,通过的才允许上传。
意义:提高代码的可维护性,降低团队协作的成本。
2.11、灰度发布
灰度发布是大型项目在发布时的常见方法,指在发布版本时,初始情况下,只允许小比例(比如1~5%比例的用户使用),若出现问题时,可以快速回滚使用老版本,适用于主链路和访问量极大的页面。
好处有以下几点:
- 生产环境比开发环境复杂,灰度发布时可以在生产环境小范围尝试观察新版本是否可以正常运行,即使出问题,也可以控制损失。
- 对于大版本更新,可以先灰度一部分,观察埋点效果和用户反馈(即所谓的抢先试用版)。假如效果并不好,那么回滚到老版本也可以及时止损;
- 当我们需要验证某些想法或问题的时候,可以先灰度一部分,快速验证效果如何,然后查漏补缺或者针对性优化;
灰度发布通常分为多个阶段:【1】1%;【2】510%;【3】3050%;【4】全量推送(100%)。灰度发布一定要允许配置某些IP/账号访问时,可以直接访问到灰度版本。
意义:降低风险,提高发布灵活度。
。
3、应用层设计
3.2、以应用为单位划分前端项目
在项目比较大的时候,将所有页面的前端文件放入到同一个代码仓库里,我之前参与过一家企业的前端项目开发,发现其就是这么做的。
- 会极大的增加代码的维护难度;
- 项目会变得很丑陋;
- 不方便权限管理,容易造成页面误更改或代码泄密;
- 任何人都有权利改任何他能看到的页面(在合并代码的时候,管理人员并不能确定他本次修改的页面是否是需求里他应该改的页面);
- 发布成本高,即使改一个页面,也需要发布所有资源;
因此,我们应该避免这种现象的发生,个人推荐以应用为单位进行开发、发布。所谓应用即指一个业务涉及到的前后端代码,好处很多:
- 方便进行管理,当某个业务有需求变更时,可以只给研发人员该业务前端应用的developer权限;
- 在需要发布某业务时,只需要发布该业务的所属应用即可;
意义:规范项目,增加代码的安全性,降低项目维护成本。
3.3、基础组件库的建设
这个蛮基础的,对于组件库的建设,不建议研发人员较少时去做这件事情,专职前端开发人数少于10人时,建议使用比较靠谱的第三方UI库,例如Antd,这样性价比更高。
意义:统一不同/相同产品线之间的风格,给用户更好的体验,减少单次开发中写UI组件时浪费的时间和人力,提高开发效率。
3.4、技术栈统一
前端有三大主流框架,还有兼容性最强jQuery,以及各种第三方库,UI框架。因此项目需求如果复杂一些,很容易形成一个大杂烩。因此前端的技术栈必须统一,具体来说,建议实现以下举措:
- 三大框架选型其一,团队水平一般推荐Vue、水平较好推荐React,对外项目选React或者ng;
- 需要兼容IE8或更老版本时,建议使用jQuery;
- 组件库自建或者统一选择一个固定的第三方;
- 一些特殊第三方库统一使用一个版本,例如需要使用地图时,固定使用高德或百度或腾讯地图;
- 基础设施建设应避免重复造轮子,所有团队尽量共用,并有专门的前端平_台负责统一这些东西,对于特殊需求,可以新建,但应当有说服力;
总的来说,技术栈统一的好处很多,可以有效提高开发效率,降低重复造轮子产生的成本。
意义:
方便招人,简化团队成员培养成本,以及提高项目的可持续性。
3.5、浏览器兼容
常见的问题是IE6、7、8,以及部分小众浏览器(PC和手机)产生的奇怪问题。因此应该考虑统一解决方案,避免bug的重复产生。常见解决方案有:
- 配置postcss,让某些css增加兼容性前缀;
- 写一个wepback的loader,处理某些特殊场景;
- 规范团队代码,使用更稳定的写法(例如移动端避免使用fixed进行布局);
- 对常见问题、疑难问题,总结解决方案并团队共享;
- 建议或引导用户使用高版本浏览器(比如chrome);
意义:避免浏览器环境产生的bug,以及排查此类bug所浪费的大量时间。
3.6、内容平_台建设
为了提高公司内部的沟通效率,总结经验,以及保密原因。应建设一个内部论坛+博客站点。其具备的好处如下:
- 可以记录公司的历史;
- 研发同学之间分享经验;
- 总结转载一些外界比较精品的文章,提高大家的眼界;
- 增加公司内部同学的交流,有利于公司的团队和文化建设;
- 对某些技术问题可以进行讨论,减少因没有达成共识带来的沟通损耗;
众所周知,大型互联网公司通常都有这样一个内部论坛和博客站点。其降低了公司的沟通和交流成本,也增加了公司的技术积累。
意义:
博客增强技术积累,论坛增强公司内部沟通能力。
3.7、权限管理平_台
- 必然和Server端天然高耦合度,因此需要有专门的控制模块负责处理权限问题(负责Server端开发处理,或者前端通过中间层例如Node层介入处理);
- 自动化流程控制,即用户创建、申请、审批、离职自动删除,都应该是由系统推进并提醒相关人士,必要时应能触发报警;
- 权限应有时效性,减少永久性权限的产生;
- 审批流程应清晰可见,每一阶段流程应具体明确;
- 应与公司流程紧密结合,并且提高可修改性,方便公司后期进行流程优化;
意义:
使得公司内部流程正规化、信息化。
3.8、登录系统设计(单点登录)
当公司内部业务线比较复杂但相互之间的耦合度比较高时,我们应该考虑设计添加单点登录系统。具体来说,用户在一处登录,即可以在任何页面访问,登出时,也同样在任何页面都失去登录状态。SSO的好处很多:
- 增强用户体验;
- 打通了不同业务系统之间的用户数据;
- 方便统一管理用户;
- 有利于引流;
- 降低开发系统的成本(不需要每个业务都开发一次登录系统和用户状态控制);
总的来说,大中型web应用,SSO可以带来很多好处,缺点却很少。
意义:
用户体验增强,打通不同业务之间的间隔,降低开发成本和用户管理成本。
3.9、CDN
前端资源的加载速度是衡量用户体验的重要指标之一。而现实中,因为种种因素,用户在加载页面资源时,会受到很多限制。因此上CDN是非常有意义的,好处如下:
- 用户来自不同地区,加入CDN可以使用户访问资源时,访问离自己比较近的CDN服务器,降低访问延迟;
- 降低服务器带宽使用成本;
- 支持视频、静态资源、大文件、小文件、直播等多种业务场景;
- 消除跨运营商造成的网络速度较慢的问题;
- 降低DDOS攻击造成的对网站的影响;
CDN是一种比较成熟的技术,各大云平_台都有提供CDN服务,价格也不贵,因此CDN的性价比很高。
意义:增加用户访问速度,降低网络延迟,带宽优化,减少服务器负载,增强对攻击的抵抗能力。
3.10、负载均衡
目前来看,负载均衡通常使用Nginx比较多,以前也有使用Apache。当遇见大型项目的时候,负载均衡和分布式几乎是必须的。负载均衡有以下好处:
- 降低单台server的压力,提高业务承载能力;
- 方便应对峰值流量,扩容方便(如举办某些活动时);
- 增强业务的可用性、扩展性、稳定性;
负载均衡已经是蛮常见的技术了,好处不用多说,很容易理解。
意义:增强业务的可用性、扩展性、稳定性,可以支持更多用户的访问。
3.11、多端共用一套接口
目前常见场景是一个业务,同时有PC页面和H5页面,由于业务是一样的,因此应避免同一个业务有多套接口分别适用于PC和H5端。
- 后端提供的接口,应该同时包含PC和H5的数据(即单独对一个存在亢余数据);
- 接口应当稳定,即当业务变更时,应尽量采取追加数据的形式;
- 只有在单独一端需要特殊业务流程时,设计单端独有接口;
多端共用接口,是减少开发工作量,并且提高业务可维护性的重要解决方案。
意义:降低开发工作量,增强可维护性。
Git 进行代码版本管理
- 拉分支开发管理
- 提交流程规范
- gitignore 配置
- 代码审查流程
Git 核心工作流程
graph LR
A[工作区] -->|git add| B[暂存区]
B -->|git commit| C[本地仓库]
C -->|git push| D[远程仓库]
D -->|git pull| A
一、Git 基础操作
1. 仓库初始化与配置
# 初始化新仓库
git init
# 克隆现有仓库
git clone https://github.com/user/repo.git
# 配置用户信息
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# 查看配置
git config --list
2. 基础版本控制
# 查看仓库状态
git status
# 添加文件到暂存区
git add filename # 添加特定文件
git add . # 添加所有修改
git add -u # 添加所有已跟踪文件
# 提交到本地仓库
git commit -m "提交说明"
# 查看提交历史
git log
git log --oneline # 简洁版
git log --graph # 图形化显示分支
二、分支管理策略
1. 分支操作
# 创建分支
git branch feature-branch
# 切换分支
git checkout feature-branch
git switch feature-branch # Git 2.23+
# 创建并切换分支
git checkout -b hotfix-branch
# 合并分支
git checkout main
git merge feature-branch
# 删除分支
git branch -d feature-branch
2. 推荐分支模型(Git Flow)
graph LR
A[main] -->|发布| B[生产环境]
C[develop] -->|合并| A
D[feature] -->|开发完成| C
E[release] -->|测试完成| A
F[hotfix] -->|紧急修复| A
三、团队协作流程
1. 远程仓库操作
# 添加远程仓库
git remote add origin https://github.com/user/repo.git
# 推送到远程仓库
git push -u origin main # 首次推送
git push # 后续推送
# 从远程拉取更新
git pull origin main
# 获取远程更新但不合并
git fetch origin
2. 解决代码冲突
- 执行
git pull时发现冲突 - 打开冲突文件,查找
<<<<<<<,=======,>>>>>>>标记 - 手动修改文件,保留需要的内容
- 添加解决后的文件:
git add filename - 提交合并结果:
git commit -m "解决冲突"
四、高级操作技巧
1. 撤销与回退
# 撤销工作区修改
git checkout -- filename
# 撤销暂存区修改
git reset HEAD filename
# 回退到指定提交
git reset --hard commit_id
# 创建新提交撤销之前的修改
git revert commit_id
2. 暂存与清理
# 暂存当前工作
git stash
# 查看暂存列表
git stash list
# 恢复暂存内容
git stash pop
# 清理未跟踪文件
git clean -fd
3. 标签管理
# 创建标签
git tag v1.0.0
# 带注释标签
git tag -a v1.1.0 -m "Release version 1.1.0"
# 推送标签到远程
git push origin --tags
# 删除标签
git tag -d v0.9.0
五、最佳实践指南
-
提交规范
- 使用 Conventional Commits 规范
- 示例:
feat: 添加用户登录功能或fix(login): 修复密码验证漏洞
-
分支管理
main/master分支保持可发布状态- 功能开发使用
feature/前缀分支 - 紧急修复使用
hotfix/前缀分支
-
.gitignore 配置
# 忽略操作系统文件 .DS_Store Thumbs.db # 忽略IDE文件 .idea/ .vscode/ # 忽略依赖目录 node_modules/ vendor/ # 忽略构建产物 dist/ build/ -
代码审查流程
- 使用 Pull Request/Merge Request 机制
- 至少需要1人审查通过才能合并
- 结合 CI/CD 进行自动化测试
六、常用工作流比较
| 工作流类型 | 适用场景 | 特点 |
|---|---|---|
| 集中式工作流 | 小型团队简单项目 | 类似SVN,单一main分支 |
| 功能分支工作流 | 大多数中小型项目 | 每个功能独立分支开发 |
| Git Flow | 有严格发布周期的大型项目 | 定义develop/release等分支 |
| GitHub Flow | 持续部署的SaaS应用 | 简化版Git Flow,无release分支 |
| GitLab Flow | 结合环境部署的项目 | 环境对应分支(production/staging) |
掌握这些Git操作和策略,你将能够高效管理代码版本,有效支持团队协作,并确保代码库的健康稳定。
Hybrid App 开发
Hybrid App 开发中前端工程的具体任务
在 Hybrid App 开发中,前端工程师扮演着核心角色,需要完成以下关键任务:
一、核心架构设计
graph TD
A[Hybrid架构设计] --> B[Web与原生交互方案]
A --> C[性能优化体系]
A --> D[安全机制]
A --> E[多平台适配策略]
1. 混合架构设计
- 桥接方案选型:实现 WebView 与原生通信
- JS Bridge(Android:
@JavascriptInterface,iOS:WKScriptMessageHandler) - Cordova 插件机制
- React Native 桥接方案
- JS Bridge(Android:
- 容器优化:定制 WebView 内核(如腾讯 X5 内核)
- 路由管理:统一原生路由与 Web 路由的跳转逻辑
二、跨平台开发核心任务
1. 业务功能开发
- 响应式 UI 实现:
// 移动端适配方案 const setRem = () => { const width = document.documentElement.clientWidth; document.documentElement.style.fontSize = width / 10 + 'px'; }; window.addEventListener('resize', setRem); - 原生功能调用:
// 调用摄像头示例 function openCamera() { if (window.JSBridge) { JSBridge.callNative('Camera', 'open', {quality: 'high'}); } else { // Web 备用方案 navigator.mediaDevices.getUserMedia({video: true}); } } - 离线功能开发:Service Worker + IndexedDB 实现离线缓存
2. 性能优化专项
| 优化方向 | 具体措施 | 预期效果 |
|---|---|---|
| 启动速度 | 资源预加载 + 骨架屏 | 首屏<800ms |
| 渲染性能 | 虚拟滚动 + GPU加速动画 | FPS>55 |
| 内存管理 | 大对象监控 + 事件解绑 | 内存泄漏<0.1% |
| 包体积优化 | 代码分割 + 按需加载 + 资源压缩 | 主包<2MB |
3. 原生交互深度集成
- 设备能力调用:
- 相机/相册访问
- 地理位置获取
- 传感器数据(陀螺仪、加速度计)
- 生物识别(指纹/面容)
- 原生组件融合:
- 实现原生导航栏与Web内容无缝衔接
- 嵌入原生地图组件
- 使用原生下拉刷新
三、工程化体系建设
1. 开发环境搭建
# 典型混合开发环境
npm install -g cordova
cordova create myapp com.example.myapp MyApp
cd myapp
cordova platform add ios android
cordova plugin add cordova-plugin-camera
2. 调试方案
- 跨平台调试工具:
- Chrome DevTools(Android)
- Safari Web Inspector(iOS)
- Weinre 远程调试
- React Native Debugger
- 真机调试方案:
// 调试模式检测 if (location.hostname === 'debug.myapp.com') { enableDebugTools(); }
3. 构建部署流程
graph LR
A[代码提交] --> B[自动化构建]
B --> C[静态资源优化]
C --> D[生成Web包]
D --> E[集成到原生工程]
E --> F[应用签名打包]
F --> G[发布应用商店]
四、质量保障体系
1. 测试方案
- 自动化测试:
// Appium测试示例 describe('登录功能测试', () => { it('应成功登录', async () => { await driver.findElement(By.id('username')).sendKeys('test'); await driver.findElement(By.id('password')).sendKeys('pass123'); await driver.findElement(By.id('login-btn')).click(); await expect(driver.findElement(By.id('welcome-msg'))).toBeDisplayed(); }); }); - 专项测试:
- 弱网测试(Netem 模拟网络状况)
- 兼容性测试(覆盖 iOS/Android 主流机型)
- 耗电量测试
2. 监控体系
- 性能监控:
// 性能指标采集 window.addEventListener('load', () => { const timing = performance.timing; const loadTime = timing.loadEventEnd - timing.navigationStart; logPerformance('page_load', loadTime); }); - 错误监控:
// 全局错误捕获 window.onerror = (msg, url, line, col, error) => { sendErrorLog({ msg, url, line, col, stack: error?.stack }); };
五、动态化与热更新
1. 动态方案
- 资源热更新:
// 热更新检查 function checkUpdate() { fetch('/manifest.json?t=' + Date.now()) .then(res => res.json()) .then(manifest => { if (manifest.version > currentVersion) { downloadUpdate(manifest); } }); } - 模块化加载:
// 按需加载业务模块 import('./modules/payment.js') .then(module => { module.initPayment(); });
2. 安全加固
- 通信安全:
// JSBridge调用签名 function callNative(method, params) { const sign = md5(method + JSON.stringify(params) + SECRET_KEY); JSBridge.invoke(method, {...params, sign}); } - 代码混淆:
# 使用Terser进行混淆 terser input.js --compress --mangle -o output.js
六、多平台适配策略
1. 平台差异处理
| 平台特性 | 解决方案 |
|---|---|
| iOS 弹性滚动 | -webkit-overflow-scrolling: touch |
| Android 键盘遮挡 | window.resize事件监听 + 滚动调整 |
| 状态栏适配 | Safe Area 安全区域处理 |
| 手势冲突 | 自定义手势识别库(如hammer.js) |
2. 容器特性检测
// 环境特性检测
const isHybrid = !!window.JSBridge;
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
const androidVersion = isHybrid ?
JSBridge.getSystemInfo().osVersion : null;
七、最佳实践建议
-
性能优化优先级:
- 首屏资源 < 200KB
- 主线程任务 < 50ms
- 滚动操作 FPS > 55
-
混合开发原则:
- 核心功能使用原生实现(如支付、安全模块)
- 高频更新内容使用 Web 实现
- 复杂动画优先使用原生组件
-
灾难恢复方案:
// WebView故障降级 try { callNativeFunction(); } catch (e) { showErrorToast(); redirectToWebVersion(); }
Hybrid App 前端工程需要掌握移动端 Web 开发的深度优化技巧,同时深入理解原生平台的特性与限制。通过精心设计的架构、极致的性能优化和稳健的质量保障体系,才能打造出媲美原生体验的混合应用。
一套代码自动适配PC与H5的工程方案
- 用的接口一样,为了组件单一原则和高度节藕,以及区分用户业务埋点,手机端和pc端页面独立开来。手机端和pc端口地址不一样,来区别不同的终端,
- navigator.userAgent判断项目运行在哪种终端
- 接口获取地址,是否有匹配的地址和其对应的其他终端地址,利用router中的全局前置钩子 beforeEach 判断 to.path判断地址
- 跳转,没有跳转到指定终端的首页
卖家模块权限前端实现业务逻辑
- 接口: /api/permission/menu/page 获取当前页面的权限按钮
列表前置操作按钮:配置num: 'btn-app-rla' 对应接口数据的发布应用
列表操作按钮:配置 v-validate="btn-app-copy" 对应数据接口的 复制应用
列表操跳转链接:配置 v-validate="'btn-app-view'" :tableLink="true" 对应数据接口的 复制应用
- 相关文件:
-
- permission-page.js(卖家各个页面权限编号配置文件)
-
- /router/index/index.js 路由配置文件 配置Meta的pageId
-
- app.js自定义指令设置
Vue.directive('validate', {
bind (el, binding, vnode) {
let bntName = binding.value
let $this = vnode.context
$this.$nextTick(() => {
let permission = store.state.permission.buttonPermission
if (permission.length) {
let has_auth = permission.some(val => {
return val.num === bntName
})
if (!has_auth && el) {
if (el.getAttribute('tableLink')) {
el.parentElement.innerHTML = el.innerText
} else {
el.remove()
}
}
}
})
}
})