前端单页面拆分多个单页面
问题现状
- 后端采用 多服务 + nginx 的技术架构 根据业务拆分成不同的项目,具体服务通过location由nginx转发代理到不同的机器(端口)上。
- 前端采用的是 dva + roadhog 的 SPA 页面。在前期路由少,页面小的情况下,开发顺畅无压力。
- 随着开发的不断进行,前端开发的瓶颈渐显,前端代码量不断增加,引入的第三方包不断扩大,每次动态编译花费时间不断加大,最终打包文件不断变大。
- 每次发布版本必须全量发布,即使是改动一点点的功能,无法按模块发布前端代码。
- 开发人员在开发阶段必须通过
--max_old_space_size
命令强制分配内存来避免node进程out of memory
项目前端相关指标:
\ | 业务代码大小 | 打包后代码总量 | 路由数量 | 编译总时长 | 热加载时长 |
---|---|---|---|---|---|
总量 | 5.26 MB | 35.5MB | 近100个 | 20分 | 45 s |
可以看到前端编译的时间已经极大的影响了开发人员的开发时间和开发效率
改进目标
- 以
功能模块
为第一维度分割大项目。 - 尽量不影响用户体验。
- 切换到新页面同步左侧菜单栏的状态。
- 子项目可以分开独立发布上线。
解决思路
- 将旧项目的部分功能拉出来,独立成多个单独可正常运行的子项目。
- 借鉴后端 nginx 的分发思想,通过
location
分发到不同静态目录。 - 将子项目前端代码部署到多个路径(甚至是机器),每个子项目独立发布,互不影响。
实现步骤
1. 前端项目拆分
- 更新前端路由模式,从
hash
模式改为history
模式
/src/index.js:
import browserHistory from 'history/createBrowserHistory';
const app = dva({
history: browserHistory(),
});
- 修改路由配置,删除非本项目的路由
- 从model、service、route删除非本项目的文件
- 删除非本项目的依赖,并更新
package.json
- 删除
/src/index.ejs
首页文件中非本项目的文件引入
2. nginx分发
- 增加子路径的分发,有多个增加多个
nginx.conf:
location /sub-path/ {
alias /xxx/dist/; #静态文件路径
try_files $uri $uri/ /xxx/dist/index.html; #404时重新定向到静态文件目录下的index.html下
}
- 修改根目录的处理方式,由root更新为alias(防止root权重问题导致nginx不执行try_files)
nginx.conf:
location / {
alias /xxxx/dist/; #静态文件路径
try_files $uri $uri/ /xxxx/dist/index.html; #404时重新定向到静态文件目录下的index.html下
}
3. 404路径优化
- 前端404路由由渲染页面优化为重定向资源,把路由控制权转交给
nginx
- 为防止
前端404路由
和nginx404路由
同时存在导致无限刷新需缓存一个更新状态在本地,防止死刷新
tryRefresh() {
if (window.sessionStorage.getItem('refresh') === 'true') {
window.sessionStorage.removeItem('refresh');
this.show404 = true;
} else {
window.sessionStorage.refresh = 'true';
this.show404 = false;
window.location.href = window.location.href;
}
}
4. 菜单状态同步
- 根据url路径,同步更新左侧菜单栏的状态
setDefaultOpenKeys() {
try {
const { location: { pathname } } = this.props;
let keys = [];
const pathItems = pathname.replace('/', '', 1).split('/');
const pathItemsWithoutLast = pathItems.slice(0, pathItems.length-1);
this.setState({
openKeys: pathItemsWithoutLast,
});
} catch (err) {
// what you do
}
}
5. 配置项目自动发布
- 配置发布相关,自测,上线代码
最终结果
将前端代码拆分成为一个基础模板和3个子项目。
- 前后数据对比:
\ | 业务代码大小 | 打包后代码总量 | 路由数量 | 编译总时长 | 热加载时长 |
---|---|---|---|---|---|
项目 - 旧 | 5.26 MB | 35.5MB | 近100个 | 20分 | 45 s |
项目模板 | 0.45 MB | 2MB | 2个 | 15s | 1 s |
子项目一 | 3.5 MB | 28MB | 近70个 | 12分 | 7 s |
子项目二 | 4.2 MB | 12MB | 10个 | 4分 | 5 s |
子项目三 | 2 MB | 9.16MB | 16个 | 1.5分 | 2 s |
待优化点
- 有些公共的文件没有抽离出来,导致子项目总和是大于原项目的。抽离出公共文件和依赖,防止资源浪费。
- 常量的公共接口可以做sesionStorage缓存(例如菜单栏),防止项目切换重复调用接口造成浪费。
飞鸟尽,良弓藏