为什么要升级
我们 App 框架是基于vue2
+ webpack3
支持国际化的多页面应用,比较通用。文件目录结构大概如下
arduino
project/
├── README.md
├── package.json
├── babel.config.js // Babel配置
├── build/ // webpack配置相关
├── static/ // 静态资源目录
├── src/
│ ├── assets/ // 静态资源文件夹(图片、字体等)
│ ├── components/ // 共享组件
│ ├── pages/ // 多个页面或路由入口
│ │ ├── user/
│ │ │ ├── locales/ // 用户模块相关的国际化语言包
│ │ │ │ ├── en/ // 英语语言包
│ │ │ │ │ └── messages.js
│ │ │ │ ├── zh-CN/ // 简体中文语言包
│ │ │ │ │ └── messages.js
│ │ │ │ └── ... // 其他语言包
│ │ │ ├── login/
│ │ │ │ ├── index.vue // 登录页面主组件
│ │ │ │ ├── main.js // 登录页面入口js
│ │ │ │ └── index.html // (可选)登录页面入口
│ │ │ ├── register/
│ │ │ │ ├── index.vue // 注册页面主组件
│ │ │ │ ├── main.js // 注册页面入口js
│ │ │ │ └── index.html // (可选)注册页面入口
│ │ ├── page2/
│ │ └── ...
│ └── utils/ // 工具函数及公用模块
└── .gitignore
框架使用两年后,发现可以从以下方向进一步优化:
-
框架不支持新的 ES 语法,比如
?.
。初步研究方案:需要升级到 babel7,包括它所依赖的 npm 包,那么影响的页面是全量的,全量回归! -
框架构建速度慢。页面数量80个左右,本地服务启动时间约 118 秒,生产构建时间 205 秒。我们另一个项目也是基于此框架,页面数量200个左右,本地服务慢到无法启动。
-
页面的公共样式和 js 并没有提取,生产构建包大小 20MB。如果能提取公共文件,比如各页面公用的 vue、vue-i18n 和 lodash 等库可以合并为一个 js 公用。这样构建包会更小,运行时各页面可以共用缓存,同时减少页面首屏渲染时间。
-
页面部分静态资源HTTP缓存设置不正确。会导致发版本后文件有更新,用户访问命中到旧的文件。
- 有些静态资源比如 style.css,是通引入的,并没有交给 webpack 管理。生产构建后如下
ini<link rel="stylesheet" href="style.css">
- 静态资源响应头HTTP缓存设置如下,也就是强制缓存2小时。
rubyCache-Control:max-age=7200
-
使用
webpack-bundle-analyzer
分析构建结果:有冗余的js引入。 -
使用
Chrome lighthouse
分析,建议去掉冗余js和css,优化静态资源加载顺序 -
static
目录下的文件是全部复制到构建目录的,包含了大量无用的文件 -
i18n文件多个页面共用,打包进每个页面,增加了包大小。
i18n文件放在页面级别
pages/user/login和pages/user/register两个页面用i18n文件是这样写的
css
module.exports = {
back: '返回',
login: {
title: '登录'
...
},
register: {
title: '注册'
...
}
}
这种目录结构的优点:
- login和register页面都共用一些国际化Key,比如"back"
- 共用的国际化Key,一处修改,全局生效
缺点也很明显
-
很难评估某个国际化Key是否是共用的。勉强用了,需要更新的时候,由于难以评估影响范围,只好在页面再声明一份。
- 比如back的值需要改为"取消",影响到的页面都要评估下
-
构建包包含的国际化文件冗余。比如login页面包括了语言文件中的register对象。
结论:国际化文件放在页面级别
各页面有独立的locales, 调整目录结构如下:
scss
src/
2├── pages/
3│ ├── user/
4│ │ ├── login/
5│ │ │ ├── locales/ // 登录页面相关的国际化语言包
6│ │ │ │ ├── en/ // 英语语言包
7│ │ │ │ ├── zh-CN/ // 简体中文语言包
8│ │ │ │ └── ... // 其他语言包
9│ │ │ ├── index.vue // 登录页面主组件
10│ │ │ ├── main.js // 登录页面入口js
11│ │ │ └── (index.html) // (可选)登录页面入口HTML
12│ │ ├── register/
13│ │ │ ├── locales/ // 注册页面相关的国际化语言包
14│ │ │ │ ├── en/ // 英语语言包
15│ │ │ │ ├── zh-CN/ // 简体中文语言包
16│ │ │ │ └── ... // 其他语言包
17│ │ │ ├── index.vue // 注册页面主组件
18│ │ │ ├── main.js // 注册页面入口js
19│ │ │ └── (index.html) // (可选)注册页面入口HTML
20│ └── ... // 其他页面或功能模块
login和register有自己独立的locales,优点如下
-
修改locales不会影响其他页面
-
构建包只包括当前页面下的locales文件
总结
i18n文件放在页面级别,项目构建包大小平均减少30%。
框架升级为Vue-cli
当前框架基于webpack3, 而webpack3 发布于2017年,最新的webpack版本是5。Vue-cli集成了webpack的能力,配置比webpack简单,首先想到的是框架升级为Vue-cli5。
升级步骤
-
node版本升级16+。因为vue-cli依赖。
-
配置文件
vue-config.js
的主要配置说明:- 页面多入口pages
- 提取各页面公共库:vue和vue-i18n为公共js,取名chunk-libs.js
- 其他逻辑和原框架webpack配置基本一致。
arduino
// 。。。省略处理多页面入口pages
module.exports = defineConfig({
// ...
pages, // 多页面入口
configureWebpack: config => {
config.resolve = {
// ...
};
config.plugins.push(
new webpack.DefinePlugin({
// ...
})
);
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
// 复制static目录
new CopyWebpackPlugin({
pattern:[{ from: 'static', to: 'static'}]
})
);
config.plugins.push({
apply: compiler => {
// 构建完成后,处理逻辑
compiler.hooks.afterEmit.tap('AfterEmitPlugin', () => {
})
}
})
}
},
chainWebpack (config) {
// ...
// 提取各页面公共vue和vue-i18n为公共js, 取名为chunk-libs.js
config.optimization.splitChunks({
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\/]node_modules[\/](vue|vue-i18n)/,
priority: 10,
chunks: 'initial'
}
}
})
}
})
升级效果
生产构建速度提升约4倍。本地服务启动时间107秒,生产构建时间56秒,包大小17.3MB。
框架升级为Webpack5
为什么要改Vue-cli为webpack5?
- 需要修改构建配置提升页面性能,Vue-cli的可定制性不如webpack, 比如: 提取css,压缩css, 去冗余css, 提取公共js等。
- Vue-cli相关资料没有webpack丰富
- webpack5更流行更通用,易于交流
- Vue-cli封装了webpack,webpack更接近原理
升级步骤
-
项目结构
-
样式文件挪到
src/assets/css
目录。由页面入口文件main.js引入,这样webpack loader会对样式文件压缩、去冗余处理、提取公共样式文件、生成带hash的文件
arduinoimport '@/assets/css/style.css'
- 图片挪到
src/assets/images
目录。这样webpack会压缩图片,并生成带hash的图片 1```
-