从零搭建一个现代化前端项目,我踩过的坑和学到的经验
早上8点,咖啡刚泡好,工位还没完全热乎——这大概是我过去三年在这家医疗软件公司最熟悉的日常。作为团队里为数不多坚持早起写代码的“异类”,我经常在同事们陆续打卡时,已经把当天最复杂的逻辑理得差不多了。
不过最近有点心不在焉。干满三年了,手里维护的几个老项目用的还是 Vue 2 + Webpack 4 的组合,每次打开控制台看到那堆 deprecation warnings 就头疼。上周五晚上加班修复一个因 moment.js 引起的打包体积爆炸问题时,终于下定决心:是时候从头搞一个现代化前端项目了。
正好公司新立项了一个面向医生端的智能问诊辅助系统(内部代号“白大褂助手”),产品经理拍着胸脯说“这次咱们用最新技术栈”,虽然这话我听过八百遍,但这次居然真的批了技术选型自由权——当然,前提是别拖上线 deadline。
于是,我拉着两个实习生,开始了这场“现代化前端基建之旅”。
为什么不能直接 copy-paste 老项目?
很多人以为前端项目无非就是 vue create 或 create-react-app 一把梭。但在医疗行业,事情没那么简单。
我们之前有个项目因为用了过时的 ESLint 配置,导致某次 CI 构建时自动格式化把关键医学单位“mg/kg”改成了“mg / kg”(多了空格),测试没覆盖到,结果线上医生差点开错药量——还好运维大哥眼尖,在灰度阶段就发现了。从此我们对“自动化”三个字又爱又怕。
所以这次,从零开始不是炫技,而是为了可控。
技术选型:在“新潮”和“靠谱”之间走钢丝
首先明确几个硬性约束:
- 必须支持 TypeScript(医疗数据结构复杂,类型安全是底线)
- 构建速度要快(实习生等不起5分钟的 dev server 启动)
- 要能无缝集成我们现有的 OAuth 2.0 和 FHIR(Fast Healthcare Interoperability Resources)API
- 国际化支持(产品说未来要出海)
基于这些,最终敲定:
- 框架:React 18 + Vite(告别 Webpack 的冷启动噩梦)
- 状态管理:Zustand(轻量、无样板代码,比 Redux 好维护多了)
- UI 库:Ant Design(虽然有点重,但表单、表格、日期选择器对医疗场景太友好)
- Lint/Format:ESLint + Prettier + Husky + lint-staged(强制提交前检查,避免再出“空格事故”)
- 部署:GitHub Actions + AWS S3 + CloudFront(运维组只认这套)
有意思的是,这次选型过程中,我试了试最近火出圈的 Amazon Q。它确实能根据自然语言生成基础配置,比如我输入:“帮我配一个 React + TypeScript + Vite 项目,支持 ESLint 和 Prettier,并在 pre-commit 时运行 lint-staged”,它几秒就吐出了一套 .eslintrc.cjs、.prettierrc 和 package.json 脚本。
但问题也来了:Amazon Q 生成的配置过于“通用”,比如它默认开启 @typescript-eslint/no-explicit-any,可我们在对接某些老旧后端接口时,不得不临时用 any 过渡。结果第一天就让实习生卡了半天。
相比之下,GPT-4o 在解释“为什么某个规则会报错”上更胜一筹。比如当 lint-staged 报错 Cannot find module 'eslint' 时,GPT-4o 不仅指出可能是 pnpm 的 hoisting 问题,还建议我在 package.json 中显式添加 eslint 到 devDependencies —— 这种上下文理解能力,目前 Amazon Q 还差一口气。
📌 小贴士:别迷信 AI 自动生成代码,尤其是在有行业特殊约束的场景。AI 是好助手,但不是决策者。
初始化项目:Vite 真香,但坑也不少
执行:
npm create vite@latest white-coat-assist -- --template react-ts
cd white-coat-assist
npm install
5 秒内 dev server 跑起来,热更新丝滑如德芙——那一刻我真的想给 Vite 团队磕一个。
但很快遇到第一个坑:Ant Design 默认不支持 ES Module 按需加载。直接 import { Button } from 'antd' 会导致整个库被打包进去,首屏加载直接飙到 3MB。
解决方案是用 unplugin-antd + babel-plugin-import(虽然 Vite 不用 Babel,但这个插件社区适配得不错):
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import unpluginAntd from 'unplugin-antd'
export default defineConfig({
plugins: [
react(),
unpluginAntd({ importStyle: true }), // 自动按需引入样式
],
})
同时安装:
npm install -D unplugin-antd babel-plugin-import
搞定后,Bundle 分析显示 antd 相关代码从 2.1MB 降到 300KB,舒服了。
代码质量防线:Husky + lint-staged 真不能省
还记得那个“空格事故”吗?这次我铁了心要把质量门禁做死。
配置如下:
// package.json
{
"scripts": {
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write ."
},
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
然后初始化 Husky:
npx husky-init && npm install
编辑 .husky/pre-commit:
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
现在,任何人 git commit 时,都会自动格式化并修复可修复的 lint 错误。如果存在不可修复的问题(比如用了 any 且没加注释),commit 直接失败。
实习生第一次遇到时差点哭出来:“哥,我就是改了个注释啊!” 我笑着告诉他:“欢迎来到专业前端的世界。”
GitHub:不止是代码托管,更是协作中枢
这次我们把整个流程都搬到了 GitHub:
- Issues:拆分用户故事(比如“医生能查看患者过敏史”)
- Projects:用看板管理进度(To Do / In Progress / Review / Done)
- Actions:自动化测试 + 构建 + 部署预发环境
- Code Review:强制至少一人 approve 才能 merge
特别值得一提的是 GitHub Copilot。虽然它不能替代思考,但在写重复性代码时效率提升明显。比如写一个 FHIR Patient 资源的解析函数:
// 输入注释:
// Parse FHIR Patient resource and extract name, birthDate, gender, and allergies
// Copilot 自动生成:
function parsePatient(patient: fhir.Patient) {
return {
name: patient.name?.[0]?.text || '',
birthDate: patient.birthDate || '',
gender: patient.gender || 'unknown',
allergies: patient.extension?.filter(ext =>
ext.url === 'http://hl7.org/fhir/StructureDefinition/allergyintolerance'
) || []
};
}
准确率大概 80%,剩下 20% 需要手动调整(比如 allergy 的 extension URL 实际是另一个),但省去了查文档的时间。
性能与体验:医疗场景下的特殊考量
医生用系统时往往在高压环境下,页面卡顿一秒都可能影响判断。所以我们做了几件事:
- 字体加载优化:使用
font-display: swap避免 FOIT(字体未加载时空白) - 图片懒加载:患者影像资料用
loading="lazy" - 关键 CSS 内联:首屏样式直接塞进
<style>标签 - 错误边界兜底:任何组件崩溃不导致整个页面白屏
还专门写了性能监控埋点,记录:
- 首屏渲染时间(FCP)
- 可交互时间(TTI)
- API 请求耗时
数据上报到公司自研的监控平台(别问,问就是“借鉴”了 Sentry)。
成果与反思
项目上线两周,医生反馈“比旧系统快多了”,产品经理难得没提新需求(奇迹!)。Lighthouse 评分从旧项目的 45 提升到 92,构建时间从 4 分钟降到 28 秒。
但我也意识到:现代化 ≠ 追新。Rust 最近让我很心动(连写个 CLI 工具都想用它),但在前端领域,稳定性和团队熟悉度永远排第一。这次没上 Next.js 或 Remix,就是因为团队对 SSR 经验不足——宁可少点 fancy feature,也不能让实习生天天 debug hydration mismatch。
最后:关于跳槽和成长
写这篇文章时,我其实已经更新了简历。三年医疗软件经验,加上这次完整的现代化项目实践,应该够我去看看外面的世界了。
但无论去哪,我都不会忘记那个因一个空格差点酿成医疗事故的夜晚。技术可以迭代,工具可以更换,唯独对细节的敬畏,是一个开发者最不该丢掉的东西。
共勉。
附:核心依赖版本参考(2024年6月)
| 工具 | 版本 | 说明 |
|---|---|---|
| React | 18.2.0 | 启用并发模式 |
| Vite | 4.4.0 | 构建工具 |
| TypeScript | 5.0+ | 类型系统 |
| Ant Design | 5.12.0 | UI 组件库 |
| ESLint | 8.44.0 | 代码检查 |
| Prettier | 3.0.0 | 代码格式化 |
| Husky | 8.0.3 | Git 钩子 |
| lint-staged | 13.2.3 | 提交前检查 |
注:所有依赖均通过
npm outdated定期检查更新,避免“依赖地狱”。

评论 0