如何设计一个前端业务开发框架
目的
提效 + 提质
1、不做重复的活儿
2、少做脏活儿、累活儿
3、相同的功能,随着时间越来越好(组件化 + 持续改进)
通用能力下沉,开发人员只需专注于上层业务的开发。
策略
业务开发框架 + 通用组件库。
业务开发框架
初期文件拷贝,后续加入 kingfisher 脚手架。
通用组件库
独立项目,以 npm 包的形式发布,业务层通过 npm install 的方式引入使用。
非 UI 组件,和技术栈解耦;
UI 组件和指定版本的 UI 框架绑定。
通用内容
MIT:文档
使用文档
示例
调试文档
常见问题列表
基础技术框架
这块包含技术框架的选型、构建工具等。
| 分类 | 技术选型 | 备注 |
|---|---|---|
| 框架 | Vue3 | |
| 构建 | Vite | |
| 状态管理 | Pinia | |
| CSS | Less | |
| 风格主题 | Tailwind CSS | |
| UI 库 | Element Plus | 移动端这个是不是不合适? |
代码规范
代码风格
prettier + eslint + sonarlint
命名规范
可以沿用之前的3D 开发的命名规范
目录结构
目前的 GUI 不需要了,应该改为 components。
另外层级需要细分下,比如 components、和 HTTP 请求相关的、配置相关的等等。
一些问题
store 该放 src 下还是放 views/pages 下?
Pinia 支持模块化,因此似乎放 views/pages 下更合适。
放 src 下。
官方结构:
.
├── assets
│ ├── base.css
│ ├── logo.svg
│ └── main.css
├── components
│ ├── icons
│ │ ├── IconCommunity.vue
│ │ ├── IconDocumentation.vue
│ │ ├── IconEcosystem.vue
│ │ ├── IconSupport.vue
│ │ └── IconTooling.vue
│ ├── HelloWorld.vue
│ ├── TheWelcome.vue
│ └── WelcomeItem.vue
├── router
│ └── index.ts
├── stores
│ └── counter.ts
├── views
│ ├── AboutView.vue
│ └── HomeView.vue
├── App.vue
└── main.ts
数据请求
这里很适合适配器模式 + 装饰器/拦截器。
安全
各种传输协议、加解密算法、设备指纹等。
overseafront\http-request\src\axios\httpgw\utils.js
HTTP 请求接口
axios
网关拦截处理:请求和响应的拦截。
@overseafront\http-request\src\axios\interceptors.js
客户端请求接口
比如行情数据的获取。
或者出于安全考虑,有一些请求会通过客户端加密通道转发。
服务端推送
SSE
事件通信
EventBus (这个是对我们做 Demo 帮助最大的,因为经常要不同组件之间联动)
EventBus 似乎更适合 AI F10 这种跨不同业务类型组件通信的场景,其他场景都用 Pinia 吧。
在 Vue 3 中,Pinia 是一个全新的状态管理库,它被设计为 Vuex 的替代品,并且与 Vue 3 的 Composition API 紧密结合。Pinia 提供了一种更简洁、更直观的方式来管理状态,同时保持了可扩展性和灵活性。
以下是使用 EventBus 和 Pinia store 的一些比较:
EventBus:
- EventBus 是一个全局的事件发射器,可以用于在组件之间传递消息。
- 它简单易用,不需要额外的配置,适合于简单的事件传递。
- 但是,EventBus 不是响应式的,这意味着它不能自动更新依赖于事件的组件状态。
Pinia Store:
- Pinia 是一个状态管理库,提供了一种集中管理应用状态的方式。
- 它与 Vue 3 的 Composition API 紧密集成,可以很容易地在组件中使用。
- Pinia store 是响应式的,状态的任何更改都会自动触发组件的更新。
- 它还支持时间旅行调试,并且可以更好地维护大型应用的状态。
选择 EventBus 还是 Pinia store,主要取决于以下因素:
- 应用规模:对于小型或中等规模的应用,EventBus 可能足够用。但对于需要复杂状态管理的大型应用,Pinia store 会更加合适。
- 响应性:如果你需要状态更改自动更新视图,Pinia store 是更好的选择,因为它是响应式的。
- 可维护性:随着应用的增长,使用 Pinia store 可以更好地维护和管理状态。
- 开发体验:Pinia 提供了更好的开发体验,例如自动类型推断、时间旅行调试等。
总的来说,如果你正在使用 Vue 3,并且需要一个强大且易于使用的状态管理解决方案,Pinia store 通常是更好的选择。它不仅提供了响应式的状态管理,还与 Vue 3 的新特性(如 Composition API)紧密集成,使得状态管理更加直观和强大。
风格主题
Token 机制。
多语言
数据文件
通过多语言翻译平台配置多语言文件。注意,该平台要求你必须提供中文版和英文版的翻译,其他语言是可以在平台上翻译的。
可以通过命令行插件拉取平台上配置好的多语言文件。
手炒里面的语言类型,是写入 User Agent 的,因此可以基于我们公司的多语言代码规范实现getLang()方法。
前端应用
采用的是vue-i18n
UI 组件
布局
Message 提示框
失败兜底页
公司特性
注意:封装这部分通用函数时,需要考虑到不同的系统(Android、iOS 等)和 APP(手炒、AInvest、基金等),屏蔽其差异性,向上提供统一的 API。
3、埋点
主动调用的埋点
我们用的是海外的埋点 v3 版本
注意:文档提到不支持 html 标签上绑定自定义属性 data-ovse-stat-click 的方式。
1 | |
DOM 绑定的交互埋点
通过 custom-directives 实现。
1 | |
4、分享
调用的是客户端协议
F10
http://cf.myhexin.com/pages/viewpage.action?pageId=1187355712
那如果分享到微信,要传递一个小图标,这种是设置哪个参数呢:
这个是客户端统一设置的同花顺图标,我们改不了
kingfisher
这个是最新的,对低版本存在兼容性问题。
1 | |
http://cf.myhexin.com/pages/viewpage.action?pageId=1074635612
微信&QQ 二次分享
http://cf.myhexin.com/pages/viewpage.action?pageId=470188125
回流
鉴权
登录
获取用户信息
日志上报
ELK(Elasticsearch、Logstash 、Kibana)
APM
应用程序性能监控(Application Performance Monitoring)。
平台
判断是哪个平台(Android、iOS、H5…)
5、可视化对接
我们的项目中一定会有接入可视化图表的需求,这个模块就是为了解决这些问题的。
6、LLM 对接
因为现在的项目基本都和 LLM 相关,我们需要与时俱进,跟上节奏,因此这个模块也是必不可少的。
业务相关
业务组件
编写规范
主要是数据结构的声明、事件的传递等等。
展示
需要有一个组件展示的页面,方便让产品和设计师知道当前有哪些组件,从中直接选择后使用。
否则只是代码层面的组件,产品和设计根本无从感知,就无法推广用起来。
可以把 storybook 集成到项目中,这样就可以直接在项目中看到组件的展示。
解决方案
动画
GSAP
Lottie
可视化
各个业务方的开发模板
B2C Web
宋策:
现在各个团队的项目模板都在 Kingfisher 上,
https://testfund.10jqka.com.cn/public/whw/kingfisher-temp/dist/#/usage
这个是通用模板,我们 PCWEB 业务团队自己的模板是在上面选择:
模板所在部门:b2cpcweb
模板类型:跨端模板(Kingfisher)
技术栈:
注:这是个通用基础模板,未包含公司业务特性(比如带有 埋点、分享、鉴权、获取用户信息、平台判断、风格主题、多语言等等这些的,以及一些业务 UI 组件库等)
AInvest
吴迪东:
之前在 kingfisher 上接过一套,不过最近好久没迭代了。
今年的项目是往物料开发上转移,上次组内讨论是要弄一个物料的模版,这个和之前的项目模版差异还挺大的。
技术栈
vue3+vant+pinia+vue-i18n+vue-router+vite+less+dayjs
项目结构
.
├── assets
│ ├── images
│ │ ├── icon_back_dark.png
│ │ ├── icon_back.png
│ │ ├── icon_down_dark.png
│ │ ├── icon_down.png
│ │ ├── icon_empty_dark.png
│ │ ├── icon_empty.png
│ │ ├── icon_fetch_failed_dark.png
│ │ ├── icon_fetch_failed.png
│ │ ├── icon_info_dark.png
│ │ ├── icon_info.png
│ │ ├── icon_refresh_dark.png
│ │ └── icon_refresh.png
│ ├── lang
│ │ ├── en.ts
│ │ └── zh.ts
│ └── styles
│ ├── common.less
│ ├── font.less
│ ├── index.less
│ ├── localTheme.less
│ ├── reset.css
│ └── vantOverload.less
├── components
│ ├── Empty
│ │ └── index.vue
│ ├── fetchFailed
│ │ └── index.vue
│ └── skeleton
│ └── index.vue
├── config
│ ├── env.ts
│ ├── hqIndexConstant.ts
│ ├── interface.ts
│ ├── lang.ts
│ ├── project.ts
│ ├── statInfo.ts
│ ├── themeVar.ts
│ └── time.ts
├── directives
│ ├── autoColor.ts
│ └── index.ts
├── hooks
│ ├── useAssets.ts
│ └── useCommonStoreState.ts
├── request
│ ├── api.ts
│ ├── fetchAdapter.ts
│ └── interface.ts
├── router
│ └── index.ts
├── store
│ └── index.ts
├── utils
│ ├── clientInterface.ts
│ ├── elk.ts
│ ├── formatTime.ts
│ ├── handleData.ts
│ ├── stat.ts
│ └── tsUtils.ts
├── views
│ ├── home
│ │ └── index.vue
│ └── cbProxy.ts
├── App.vue
├── env.d.ts
└── main.ts
@overseafront/utils
工具函数库。
我们额外可以补充的:UUID、各种常用的 formatter、单位处理
1 | |
封装了客户端和 web 的实现,比如这种:
1 | |
@overseafront/http-request
@overseafront/backwash-v2
回流库。
技巧
常用类型定义,比如股票名称、代码
通过v-auto-color指令实现数值的自动颜色设置
通过 hook(src\hooks\useAssets.ts)根据当前风格,自动加载不同的图片
fetchAdapter 的设计,数据可以取自多个源(HTTP、客户端接口)
route 的处理:多语言、页面标题、页面统计
1 | |
store 的设计:客户端信息、用户信息、多语言判断、主题判断
src\store\index.ts
utils:客户端接口、ELK 日志、格式化时间(这个得看看,包括美国时间处理)、数字精度和单位处理、埋点
F10
林吕贝:
目前都是走 KAmis 了,示例项目
UI 库用的是公司的 AtomUI,没有用开源库。和开源的对比,比如 vant、antv 之类的:还是差很多的,不过根据我们公司设计来,用 atomUI 稍微好一些;如果没有设计要求,用第三方的就很完美了。
手炒
做得不多,Pass
基金
负责人:李博深
之前是 React 技术栈,现在转为 Vue 了。
基金现在因为业务类型比较杂的原因、算是没有标准模版,用的是 kingfisher 脚手架里的 basic 下的跨端模板模板。这里有不少基于 kingfisher 的组件调用示例,可以参考下。
李博深整理了个文档:如何写基金前端代码,很值得参考,特别是计划部分,可以作为我们的需求来源。
这个同级的页面,有各个模块的具体实现方案。
Warning:这个是基于 Vue 2.7.14 的。
技巧
页面拆解

海外并购重组
KAmis
这种开发模式,是我这种手残党的未来。
解决什么问题
沉淀问题
本地组件是缺乏强制沉淀意识的。
让开发从脏活儿累活儿中解放出来
埋点、样式微调、改个文本等等这些,都是重复劳动,我们需要让开发从这些重复劳动中解放出来,让产品和运营自己用可视化的方式去处理掉。
能力
KAmis 平台支持:
- 布局
- 组件
- LowCode
- 发布
- 数据解析(一个数据用在多个组件)
不支持:
- 数据源接入(还是需要业务方自己开发后端数据接口)
常见问题
第三方依赖如何导入
CDN
如何实现万能组件
看组件开发人员自己,暴露个整体的 option 即可。