框架的价值更多体现在应用层次上面,是一种整合作用,通常框架是一套大而全的特定问题域的解决方案,它与库的主要区别无外乎控制反转、可扩展性和不可修改,尤其控制反转是框架具备的典型特征:在框架里面,程序的控制流程不由调用者决定,而由框架决定,而对于若干相似的库,调用者可以自由切换库和选择性调用库 API,再直白一些,框架是一套规范而库是一堆砌方法。

每个团队都有一个框架梦,我们也不例外,只要遇到的足够复杂的问题,对团队的整体效率与稳定不断造成冲击的时候,往往就是去做问题归纳和推出框架的时候,这次我们聊一聊关于 PC 网站的网页前端开发方案,我们遇到的问题和对于框架的初步尝试,为保持给大家轻松的阅读体验和更宽的视角,本文不会深入代码细节,至于源码将来我们某天开源后大家便可一睹芳容。

启动框架的初心

一切技术决策皆有特定业务背景,我们在日常的开发中,主要面临如下三类场景:

  • 中后台的单页 PC ERP/CRM 等系统,上百种权限的十几个角色在后台各自的工作界面,每个角色都有十几个到几十个独立页面的业务流程,比如物流专员的发车调度、销售助理的加价推新等等,对于这些系统有可能是一个独立入口的 SPA,也有可能是多个独立入口的多 SPA 集合,在同一个仓库内维护

  • 前台的 PC 网站,几十个关联性不强的页面,没有太复杂的逻辑,主要做展示,比如公司官网

  • 在手机浏览器上的 H5 网站,几十上百个有强业务逻辑的页面,也有角色的区分,比如有交易业务的移动版商城

在小菜前期三四年的创业历程中,我们扎根在销地做撮合型的 toB 交易,所有的协同流程都移动化,交易也依托于独立的 APP,彼时也正是移动互联网崛起的时候,我们对于 PC 系统的建设和沉淀比较简单粗暴,公司中台只有一个囊括了几乎所有角色的 ERP(含 CRM 部分功能)后台,上百个页面,jQuery 与 React 共存, 通过 webpack 设计了多入口的打包方案,每一个独立的子系统(面向某类角色的业务流程页面)都独立打包,但随着我们的业务规模攀升和生鲜供应链的上下游打通,业务场景越来越多,特定层面的业务越来越垂直细分,包括中台和工具层面的建设,整个大中台开始有了雏形,十几个后台 PC 系统像雨后春笋一样快速启动,仓促上线,同时数量上也丝毫没有没看到减速的态势,我们必须有一套标准方案在做到快速的复制来降低重复开发与维护的成本,不为炫技只为解决问题就是我们的初心。

遇到了那些挑战

在这样的业务背景下,我们遇到了巨大的挑战,主要是如下几方面:

生态丰富却失去约束

我们知道  React 自身单薄,但是周边生态异常丰富,每有一个新特性出来就会多出非常多的轮子,在眼花缭乱的周边中,我们早期也迷失其中:

  • 在跨组价通信和状态管理上,我们用过 context、event-emiiter、redux、mobx 还有基于 redux 包装的 rematch等,比如 16 年起 redux 异步解决方案就有非常多的轮子:thunk、saga、redux-observable 等,而在中后台项目,尤其是 CMS 类型项目,几乎不会涉及竞态的问题,有些方案实现的有点牛刀杀鸡

  • 在 css in js 方案上,有原始的 sass/less scope 方案、css modules 、 style-components 、jss 等同样让人眼花缭乱,很容易选择新的和舍弃旧的

  • 在路由上,有 react-router 、reach-router、react-navigation 等。我们虽然沿用了 react-router, 但也不舒适,在路由权限这里我们自己完全去定制开发

整个过程趟过来,我们会发现 react 周边工具都能衍生出自己的生态,这样的裂变组合,导致我们前期的前端工程千奇百怪,交叉开发时,进入的新同学理解成本很大。

基础环境升级困难

当我们想要享受到基础工具升级带来的好处,比如早前 webpack2 的 tree shaking,webpack3 的 common chunks 策略更改,那么每个项目都需要升级一遍,就会陷入重复开发的泥淖中,而这些对于业务的同学最好是弱感知的,可以获得更好的开发体验,效率和开发幸福感自然会提升。

代码无分层,测试难

早期的代码是一个巨大的 class,数据请求对象也揉在 class 内,这个 class 会变得非常大,不可维护。按照关注点分离的原则,UI 层和数据层应当分离,只有这样,UI 测试和数据层的测试才能独立,多人开发才能成为可能。

工具函数散落 没有版本管理

前端和后端基于网关通信,我们会封装调用网关的请求工具,而各个项目都有自己的实现,一旦出问题,不仅排查起来没有规律,也无法集中解决,维护性很差。

开发环境差异化

当出现很多内部子系统时,每个系统启动命令和打包命令都不一致,让我们的心智成本非常的高,这个在我们开发了前端发布系统后暴露的尤其严重,我们取消了本地发包发布,都转移给运维发布平台去做执行,但在迁入发布平台时,每个项目的发布命令不同,就需要写出不同的运维脚本,完全是差异化的规则,并且一旦遇到紧急线上重启项目,还需要逐个分清楚它的命令参数,效率很低。

新启项目慢 响应业务的速度慢

那么多内部系统,每新启动一个 PC 系统,从登录到本地用户态与网关的保持,与权限系统的对接(限制页面的路由访问层级),整个系统的工程目录重新梳理等等各方面重新来一遍,整个配置过程弄下来一天就过去了,偶尔还碰到 webpack 和 babel 的bug,让新项目的搭建非常的耗时。

问题多多,全部总结下来就是随着系统的变多,没有框架约束的项目会面临三个问题:维护性差、效率低、扩展性差。

如何给框架定位

针对上述问题,我们希望在复用性、规范性、可维护性上产出一套方案,重点不是做出一个什么框架,而是系统解决掉前端工程上的这些问题,所以我们并不纠结这个框架的自研程度或者概念上的正确性,它一定是逐年逐季度迭代的,也一定会随着业务不断受到巨大挑战甚至某一天会夭折,但在特定的连续时间段内,能解放我们的成产效率,为业务带来更好的支持,它的目的就达到了。

因此结合我们业务多变,系统繁多,中后台居多的特征,我们把这个框架定义成:轻量级框架 + 自助餐搭配,具体的意思如下:

轻量框架 = (工程化工具包 + 模板市场)  *  可升级 工具包 = 开发工具 + 上线工具 + 监控工具 模板市场 = 中后台项目 + 轻量工程(例如官网首页)+ H5 工程

它可以兼容到我们的中后台项目以及 H5 工程,同时能搭建轻量级的非 SPA 工程,不能囊括进来的项目就不用该框架搭建,同时它对新人同学足够的友好。
模板市场会承载一部分无法纳入框架管理的定制需求,满足解决不同场景的需要,例如 H5 和 PC 的模板不同,最典型的便是兼容性要求不一样。

具体程序载入的策略和执行的策略则交给框架去约束,简单说就是业务代码按照框架的约定(实现框架的接口),就能让你的业务代码程序跑起来,不按我的约定,就不能跑起来,更别提上线了。

我们想要达到的效果是:业务开发不用关心基础环境的任何问题,基础环境有 bug,只要提出 issue,解决后直接升级基础框架即可。提高开发效率,减少解决重复 bug 的情况,最终提高业务响应速度。

如何设计工具包

上面的工具包载体就是 cli (command line tool), cli 的功能块如下:

这里简单地介绍下 cli 相关的命令,cli 的交互式命令行依赖了 2 个核心的三方包,分别是:

  • commander:用于处理命令行内的参数

  • inquier:  处理交互式命令行的问答

init

在 init 阶段选择需要初始化的模板(模板来自模板市场,现在可以简单认为模板市场就是一个代码仓库)根据选择的类型去仓库内拉取相应的代码,然后安装 node_modules 包,整个工程就搭建起来了。

dev

dev 则是启动本地开发环境,有时我们需要本地启动不同的环境查看效果。在命令行设计时,我们可以针对常见的三个环境做不同的启动命令。如启动测试环境 dev:test, 就会依赖项目中针对不同环境配置的参数做整体替换。

build

build 则是打包本地的项目,也同样可以根据不同环境做不同的打包策略。

deploy

可能大多数公司也会从这个阶段过渡过来,所以提一下。在早前没有接入发布平台前,我们是本地发布的,html scp 到应用服务,静态资源走CDN,此时的 deploy 也需要针对不同环境做不同的打包策略。接入发布平台后,这个命令就应当被废弃了。本地打包带来的问题非常多,服务器权限、lock问题、协作效率等等。

test

依托 jest 对项目进行关键点的测试。测试固然非常重要,想做到100%覆盖率则会耗费非常多的时间,我们不强求100%覆盖,只要求对工具函数和业务组件做到覆盖。

对 webpack 的思考

前面我们简单介绍了几个常用命令,dev、build、deploy 都和 webpack 强相关。我们常常会将 webpack 相关的命令都放在 package.json 内,webpack 也同样存在于项目内。但这样就会出现之前所说两个问题,分别是基础环境重复配置暴露基础环境配置容易被修改,最终业务项目各自为政,难以维护。

所以,我们需要对业务开发者屏蔽 webpack 配置,将 webpack 的配置放入 cli 的工程内,当在业务项目中调用全局的命令时则根据响应的对应的子命令参数,获取对应的 webpack 配置。

将 webpack 的配置收敛在全局则会出现无法扩展的问题,为了满足不同业务项目的需求,我们约定在业务项目的根目录内存放一份配置文件,在调用命令时会先读取响应的配置合并到内存中,这里会涉及 webpack 配置合并的问题, 可使用 webpack-merge 或者 webpack-chain 这样的工具进行合并。

工具链辅助

框架周边一定是围绕着各种工具链,并且它的重要性不亚于框架本身:

关于效率

  • 数据 mock      mocks.js 定制

  • 简化路由配置  glob 读取文件夹作为路由

  • 所改即所见     webpack-dev-server 的 hotreload(H5 营销活动系统)与保持状态的 react-hot-reload(长业务流程需要保留state)

  • 代码生成器         定制生成  pageFile、service、model 文件的命令

关于质量

  • code lint 基于 eslint 定制,配合 husky 做到开发时、提交时、上线时的校验

  • 提交规范 commit-lint

  • 指定代码规约做 code review

发布

  • 缓存策略

    • 动态资源 html 放应用服务器,走协商缓存

    • 静态资源 hash化,放入 CDN,走强缓存

  • 发布策略

    • html scp 上传到应用服务器,这件事前期是项目负责人本地发布,后期是发布平台操作

    • cdn 资源 hash 化,永久缓存

如何做到可升级

  • 基础配置收敛进全局

  • 通用组件、工具函数用 npm 包管理

cli 遵循语义化,升级与否由开发者自己决定。为了及时通知到开发者,我们可以在 npm run dev 脚本里加入一段脚本用于 check 本地 cli 的版本和最新的cli版本是否一致,如果不一致则吐出 CHANGELOG 的链接,然后由业务开发同学阅读后选择是否升级。

光是解决基础环境的升级还不够,在业务系统中我们将通用的请求函数、异常处理、通用的组件也统统抽成 npm 包,各个业务团队利用 npm 语义特性可以进行无痛的升级。所以,鼓励将业务中搜集到的问题和好的解决方案抽出并发布 npm 包。

关于模板市场

利用 yeoman 定制相关的 templates,而各个模板需要各条线的业务同学贡献过来,目前使用最多的是中后台的项目,因此质量最好的中后台相关的。

React 的工程化

前面所讲的是工具包相关的,这部分讲讲业务代码部分的工程化,工具是开发效率的利器,虽然开发环境问题已经被 cli 解决,工程化规范是保证业务项目牢靠的关键,需要一套规约。

自助餐清单

  • css in js:  jss 搭配 less/sass

  • 状态管理:  rematch

  • 路由:react-router

  • ui 库:ant-design

  • 测试框架:jest

  • mock 工具:mock.js

简版工程结构

.├── assets // 全局的静态资源│   ├── icon│   └── index.js├── components // 全局的components│   ├── index.js│   ├── menu│   │   ├── index.js│   │   └── index.less│   └── slider│       ├── index.js│       └── index.less├── pages // 页面,约定每一个页面都是一个路由│   ├── 404│   │   └── index.js│   └── user│   |  ├── service.js // 存放本页面需要的数据请求对象和业务逻辑|   |  ├── models|       |    |     └── index.js //存放本页面自己的 rematch model 文件|       |    └── index.js|     └── login│        └── index.js├── routes // 自动路由配置│   └── index.js├── services // 存放数据请求对象│   ├── index.js│   └── user│       └── index.js├── store // 状态管理│   ├── index.js│   └── models│       └── user.js└── utils // 工具函数

工程结构按照功能结构划分,没有将所有的分层文件提升到最顶层,减少来回切换的心智成本,并且明确了服务层,既解耦界面和逻辑,又方便测试。

路由权限

路由权限上,我们会从后端拉取当前用户拥有的路由表,在 react-router 加入 component 处加入路由级权限校验的逻辑。

状态管理

关于状态管理,我们选择了 rematch,简单易用,也刚好够用,适合的就是最好的。状态管理可以让数据和逻辑抽离 UI 层,可以做到更高的测试也降低了巨型 class 组件的维护成本。

服务层

服务层存放数据请求对象,即请求接口。除此以外,一些较重的业务逻辑也会放入 service 内管理,我们希望状态管理竟可能轻量,将其中较重的逻辑收敛入 service 中管理。这么做的目的:

  • 复用一些 comb 的接口

  • 态管理层的心智负担,例如一些字段的default

  • 方便测试一些关键业务点

与后端交互

RESTFul 部分抽出公用的网关工具函数并放入私有的 npm 包进行版本管理,GraphQL 部分抽出 pc 版的 gpm 包对接 GQServer。

单页和多页

从 webpack 配置上看,除了入口配置有点不同,其他部分几乎是一样的。单页通常适用于业务之间联系较为紧密的整体应用,例如CRM系统。多页则适用于页面非常多,并且彼此之间没有太多关系的应用,例如营销 H5 系统。

中后台系统中我们应该按照业务域划分出各自的子系统,不应该将全部的页面都放入同一个工程。起初内部的 ERP 系统从 Java VM 模板中迁移出来,不得以用多页形式进行过渡。现在切出业务子系统,各个小系统由各个小团队自己维护,解耦且拥有单页良好的体验,越来越多的业务子系统的启动,也是我们做框架的必要性之一。

总结

实现框架的全链路建设是一个长周期的事情,需要持续不断的投人力进去,虽然听上去很高大上,但执行起来还是相对琐碎,尤其是框架推出阶段和升级阶段,基本上框架的实现者就是在当客服,当然相对优质的升级文档或者版本间的兼容程度会降低这种工作量,无论怎样,对于团队来说,有大量业务场景支持的框架会迸发它更大的价值,对于个人来说,参与框架的建设是一个很考核全方位能力的过程,而对于所有使用框架的同学来说,则多了一个顺手的工具同时也多了一个可以学习的封装范例,也正因为如此我们对于这件事情持 open 的态度,目前我们只是实现了它的从 0 到 1,还有监控集成、单元测试覆盖、发布系统接入、差异化打包方案、系统模板平台等等很多有意思的方向还没有更多的同学加入去共创去建设,还有相当长一段路要走。

框架设计:PC 端单页多页框架如何设计与落地相关推荐

  1. 千锋教育Web前端——PC端企业类型整页制作

    千锋教育Web前端--PC端企业类型整页制作 文章目录 千锋教育Web前端--PC端企业类型整页制作 一.PC端的布局 二.源码 1.CSS源码 2.HTML源码 三.运行结果 一.PC端的布局 通栏 ...

  2. ESP32E基于Thonny——python框架,PC端进行局域网控制led亮灭

    ESP32基于Thonny--python框架,PC端进行局域网控制led亮灭 用中文讲,该如何实现这个功能呢? 1:成功连接wifi 2:能循环正常接收数据 3:判断接收的数据,使led亮灭 就3步 ...

  3. PC端企业类型整页制作

    PC端的布局 通栏 自适应浏览器的宽度 版心 固定一个宽度,并且让容器居中 源码 HTML源码 <!DOCTYPE html> <html lang="en"&g ...

  4. vue2.0桌面端框架_Vue PC端框架

    Vue PC端框架 472019.02.22 10:30:20字数 1,749阅读 54,067 1. Element Element,一套为开发者.设计师和产品经理准备的基于 Vue 2.0 的桌面 ...

  5. PC端动态视频背景引导页(非自适应)

    简介: 新人学习,看了几天html css视频写了这个引导页,代码还不规范,目前还在学习中,希望各位大佬勿喷 网盘下载地址: http://kekewangLuo.net/3Y9J4ZPjy380 图 ...

  6. html手机pc不同页面,PC端和手机端如何同时生成静态页

    静态页是和图片类似的静态资源,访问静态资源不会经过程序处理,不会根据浏览器返回不同页面.要同时支持PC端和手机端浏览器,且要生成静态页时,最好使用bootstrap之类的技术,实现自适应页面设计. 如 ...

  7. php 可以做pc客户端吗,vue.js能做pc端吗

    vue.js能做pc端,因为Vue是一套构建用户界面的渐进式框架,不管是用在PC端还是用在移动端,只要提供对应的API及数据相应就可以:但是PC端单页面对于搜索引擎可能不太友好,无法让搜索引擎把整个网 ...

  8. PC端键盘热键如何与页面交互

    什么是热键 在交互设计中,快捷键和键盘热键是提高用户效率和提升用户体验的重要手段之一.在PC端应用和网页设计中,合理运用键盘热键可以帮助用户快速完成操作,提高工作效率和使用体验.本文将介绍PC端键盘热 ...

  9. 14.------------------------------------------------------------------------------【PC端品优购项目】

    文章目录 [PC端品优购项目]前端小抄(14) 电商-主页 电商-分类列表页 电商-注册页 一.品优购项目规划 1.1 网站制作流程 1.2 品优购项目整体介绍 1.3 品优购项目的学习目的 1.4 ...

最新文章

  1. C#程序如何对接比特币钱包节点?
  2. oracle DBA 常用表和视图
  3. 【完结】如何掌握基于图像和视频的人脸表情识别,这9篇文章可以作为一个参考...
  4. 5、线程终止方式:pthread_cleanup_push/pthread_cleanup_pop()
  5. matlab电压稳定极限,电力系统电压稳定性的Matlab建模分析
  6. trace java_使用java动态字节码技术简单实现arthas的trace功能。
  7. 微型计算机天逸510s光驱,主机届的小钢炮,性能最强NAS——天逸510S Mini
  8. 监控apache脚本原理
  9. Unity游戏资源逆向工具
  10. xrd计算晶面间距_xrd如何计算晶格间距(1)
  11. 2022-2028年中国林业碳汇行业市场发展规模及投资机会分析报告
  12. Unity Editor 编辑器介绍
  13. C++ RQNOJ 星门龙跃
  14. 全国城市-拼音-编号Json数据(只城市)
  15. win11装安卓应用(2022精简版教程)
  16. Java笔试面试-Executors
  17. DP算法:动态规划算法
  18. 未来计算机的发展趋势展望,未来计算机发展的5种趋势
  19. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver.的解决办法及原因
  20. java之高级的IO流,字符流与字节流

热门文章

  1. “屏蔽”掉不用输入法选项
  2. 服务器上文件导出到本地,服务器文件导出到本地
  3. 【echarts】解决动态条形图Bar Race国旗emoji在PC端不显示的问题
  4. 百度收录批量查询 如何批量查询百度年月日的收录数量
  5. Accordion( 分类) 组件
  6. c语言中长整型变量的值一定大于短整型常量的值,c语言第3讲 常量、变量与标志符 整型、实型、字符型数据.ppt...
  7. 极限学习机(ELM) 算法及MATLAB程序实现
  8. ultraiso制作u盘系统linux,使用UltraISO制作ubuntu安装u盘启动盘图文教程
  9. ie不支持html56,是否浏览器设置有问题?
  10. [4750g] 升级BIOS 禁用独显解决linux下发热问题