从零搭建一个现代化前端项目的实战经验分享
开篇:为什么想写这篇文章?

作为一名在互联网公司摸爬滚打了几年的前端开发者,我经历过多个从零开始构建项目的情况。有的是公司新业务线需要启动,有的是老项目维护成本太高必须重构,也有的是我自己业余时间折腾的一些小项目。
无论哪种情况,“从零开始”从来都不是一件容易的事。你不仅要选技术栈、搭框架、定规范,还要考虑后续的可维护性、性能、协作效率等等。特别是在团队逐渐变大后,很多细节问题就开始浮现出来了。
今天,我想结合最近参与的一个中型管理系统项目,来分享一下我是如何从零构建一个现代化前端项目的,包括遇到的问题、技术选型的心路历程、踩过的坑以及一些个人建议。希望对刚准备开新项目的你有所帮助。
背景介绍:一次典型的中后台系统重构

事情要从半年前说起,我们部门负责的一套企业内部的资产管理平台已经运行了好几年,前后端都是基于 AngularJS(没错,不是 Angular)和 Java JSP 的架构。
由于历史原因,代码结构混乱、依赖杂乱无章、页面加载慢、调试困难、难以维护等问题越来越突出。最终领导拍板决定:全面重构这套系统。
而我的任务是:作为主负责人之一,从零构建新的前端项目,并尽可能保留原有功能模块的迁移路径。
我们的目标:
- 使用主流现代技术栈,方便招人、维护、迭代;
- 构建速度快、打包体积小;
- 支持多人协作开发,有统一规范;
- 良好的性能表现,尤其关注首次加载速度;
- 未来具备扩展能力,比如 PWA、国际化等。
搭建过程中的挑战

刚开始接到这个任务时,说实话还挺兴奋的。终于可以不受旧项目限制,自由选择自己喜欢的技术栈了。
但现实很快打脸。虽然有很多技术可以选择,但如何做最优组合、如何保证长期可维护性,才是真正考验人的地方。
具体挑战包括:
- 选型太多,反而难以下决定。Vue vs React?Vite vs Webpack?
- 如何设计合适的目录结构? 既要清晰又要灵活。
- 怎么管理多人协作中的冲突?
- 性能优化要从一开始就考虑。
- 跨浏览器兼容性不能忽视,尤其是一些 IE 环境还在用。
- 自动化流程怎么做?ESLint、TypeScript、Prettier、Husky、Commitlint …… 全都要配好。
- 如何快速接入已有的接口和服务?
这些问题都直接关系到项目的成败,而且没有标准答案。每一步都需要结合实际需求做出权衡。
技术选型与架构设计
主流技术栈的选择
前端框架:Vue 3 + TypeScript
我们最初讨论过是否使用 React,但在团队调研后发现,大部分成员对 Vue 更熟悉,加上 Vue 3 对于中后台系统的友好度更高(特别是 Composition API 和响应式语法糖),最终选择了 Vue 3 + TypeScript 的方案。
构建工具:Vite
一开始我其实有点保守,打算用 Webpack,毕竟它成熟稳定,插件生态丰富。但我们尝试了 Vite 后就彻底被打动了。
- 开发服务器冷启动速度飞快,几乎秒开
- HMR 反应灵敏
- 内置对 TypeScript、CSS 预处理器、JSX、Vue 单文件组件的支持
- 支持按需编译,非常适合现代前端工程
所以最后毫不犹豫地选了 Vite。
状态管理:Pinia 替代 Vuex
Vuex 已经有些过时了,官方推荐 Pinia。我们也第一时间用了上来,结果非常顺利。
- 类型友好(尤其是配合 TypeScript)
- 模块化结构清晰
- 写法更简洁直观
UI 库:Element Plus(搭配暗黑主题)
因为我们做的是一个企业级管理系统,UI 层面需要大量组件支撑。Ant Design Vue 当然也很不错,但我们团队之前有使用 Element 的经验,加上 Element Plus 对 Vue 3 支持很好,最终选定了它。
另外,用户反馈说他们希望界面不要太刺眼,所以我们还加了个暗黑模式切换功能。
项目结构设计
src/
├── assets/ # 静态资源
├── components/ # 通用组件
├── layouts/ # 布局组件
├── router/ # vue-router 配置
├── store/ # pinia 模块
├── services/ # 接口请求封装
├── views/ # 页面组件
├── utils/ # 工具函数
├── App.vue
└── main.ts
这样的结构兼顾了清晰度和可扩展性。每个模块职责明确,适合团队协作。
实施过程中的一些关键点
1. 模块划分与路由懒加载
项目初期我就意识到,随着功能增加,包体积会成为瓶颈。于是我们在路由层面做了懒加载配置:
const routes: Array<RouteRecordRaw> = [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('../views/Dashboard.vue'),
meta: { title: '仪表盘' }
},
{
path: '/assets',
name: 'Assets',
component: () => import('../views/Assets.vue'),
children: [
{
path: 'list',
name: 'AssetList',
component: () => import('../views/Asset/List.vue')
},
...
]
}
]
这样可以在不同层级实现异步加载,提升首屏性能。
2. 请求服务封装:Axios + 中间件机制
为了统一处理错误码、拦截器、token 刷新等逻辑,我们对接口层做了统一封装。
// services/request.ts
import axios from 'axios'
const request = axios.create({
baseURL: '/api',
timeout: 10000
})
request.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
}, err => Promise.reject(err))
request.interceptors.response.use(response => {
return response.data
}, async error => {
// 错误处理逻辑
return Promise.reject(error)
})
export default request
之后我们在各个 service 文件中复用它:
// services/assets.ts
import request from './request'
export function fetchAssets(params) {
return request.get('/assets', { params })
}
export function createAsset(data) {
return request.post('/assets', data)
}
这样做之后,不仅统一了调用方式,也便于统一添加日志、埋点等功能。
3. 国际化支持(i18n)
虽然目前只有中文,但我们还是提前引入了 vue-i18n:
import { createI18n } from 'vue-i18n'
import zh from '@/locales/zh.json'
import en from '@/locales/en.json'
const i18n = createI18n({
legacy: false,
locale: 'zh',
fallbackLocale: 'en',
messages: {
zh, en
}
})
app.use(i18n)
然后在组件里就可以通过 $t 来调用翻译内容:
<h1>{{ $t('welcomeMessage') }}</h1>
这种做法让我们为后期多语言支持埋下伏笔。
4. 性能优化实践
- 使用
v-once或memoization减少重复渲染 - 图片懒加载(
<img v-lazy="url">) - 引入 Lighthouse 进行性能评分指导优化
- 合理拆分 chunk,避免单个包过大
- Gzip 压缩部署 CDN 加速访问
- 首屏优先加载策略
- 使用骨架屏预占位(element-plus-skeleton)
我们最终实现了首屏加载小于 1s,Lighthouse 分数稳定在 90+。
踩坑记录和解决方法
坑一:Vite + 微前端环境兼容问题
我们的项目需要集成进一个微前端架构中(基于 qiankun)。Vite 默认的打包策略是以现代 ES Module 的方式输出,但在某些不支持动态导入的子应用环境中就会报错。
解决方案:
改用 build.lib 模式,并指定输出格式为 umd:
build: {
lib: {
entry: resolve(__dirname, 'src/entry.ts'),
name: 'MyApp',
fileName: (format) => `my-app.${format}.js`
}
}
同时,在 qiankun 的生命周期钩子中挂载:
// 子应用入口
export async function mount(props) {
const app = createApp(App)
app.mount('#sub-root')
}
坑二:IE11 不兼容 Proxy & Reflect
Vue 3 默认使用 Proxy 进行响应式追踪,但在 IE11 上无法正常运行。
解决思路:
- 降级到 Vue 2?代价太大。
- 使用 polyfill 是唯一出路。
我们在项目中引入了 proxy-polyfill,并在入口文件顶部注入:
import 'proxy-polyfill'
虽然性能略有下降,但在兼容性和功能完整性上达到了平衡。
坑三:TypeScript + Vue 3 的组件类型定义问题
Vue 3 中虽然支持 <script setup> 语法,但与 TypeScript 结合使用时,某些泛型或函数参数推导会出现问题。
例如:
const props = defineProps<{
items: Item[]
}>()
有时候 IDE 会提示找不到变量,或者类型未被正确推断。
解决方法:
升级 Vue 相关的 TypeScript 插件版本,并确保 VSCode 安装了 Vue Language Features (Volar) 插件。
此外,尽量使用显式的 defineProps 和 defineEmits,而不是隐式提取。
效果总结:上线后的真实反馈
经过两个多月的开发和测试,项目如期上线。整体效果超出预期:
| 指标 | 上线前 | 上线后 |
|---|---|---|
| 首屏加载时间 | 6~7s | <1s |
| 打包体积 | ~5MB | ~1.5MB |
| 新人上手难度 | 高(文档少) | 中等(有文档+脚手架) |
| Lighthouse Score | ~55 | ~92 |
| Bug 数量 | 多且分散 | 少且集中 |
更重要的是,这次重构之后,我们建立了一套完整的开发流程和规范,使得后续开发效率大大提升。
经验分享:给正在起步项目的你几个建议
1. 技术选型不要盲目追求热门,适合团队最重要
我见过太多项目为了追热点选了个完全陌生的技术栈,结果半途而废。建议根据团队现有能力 + 明确的业务场景来做决策。
2. 自动化流程要尽早完善
别等到最后才配 ESLint、TypeScript、Git Hooks。越早配上越好,否则后面改起来就像修一栋没地基的大楼,处处受限。
3. 性能优化要前置
很多人觉得“先完成功能再优化”,其实不然。像懒加载、目录结构设计这些,一开始就决定了项目能不能跑得快。等出问题再改,代价极大。
4. 文档和模板也要重视
我们最后整理了一个自己的 CLI 初始化模板(基于 plop.js),每次新建模块或页面都能一键生成基础代码。新人入职两天就能独立提 PR。
5. 调试技巧和工具真的很重要
推荐几个我常用的工具:
- Vue Devtools:Vue 生态标配调试神器
- Source Map 查看:帮助定位压缩后的错误来源
- Chrome Performance 面板:用来分析加载瓶颈
- Mock.js + Mockoon:本地模拟接口数据很方便
- Lighthouse:性能打分工具,强烈推荐加入常规检测流程
写在最后:关于成长和技术选择的思考
这几年下来,我一直坚信一句话:技术没有高下之分,只有合适与否。
每一个项目、每一个团队、每一个业务阶段都会面临不同的挑战。作为前端开发者,我们要学会的不只是写出漂亮的代码,更是要在复杂需求中找到最适合的解决方案。
这次从零搭建新项目的经历,让我对整个前端工程体系有了更深的理解。也让我更加坚定了一个信念:优秀的前端项目,应该是易读、易维护、易扩展、易协作的。
如果你现在正准备开启一个新的项目,希望这篇文章能给你带来一些启发和帮助。
愿你在未来的开发路上,每一次 “从零开始”,都是一次成长的机会。
(本文部分内容涉及公司项目细节,已脱敏处理。欢迎留言交流!)

评论 0