打包Size减小 80%--App 框架优化

为什么要升级

我们 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

框架使用两年后,发现可以从以下方向进一步优化:

  1. 框架不支持新的 ES 语法,比如?.。初步研究方案:需要升级到 babel7,包括它所依赖的 npm 包,那么影响的页面是全量的,全量回归!

  2. 框架构建速度慢。页面数量80个左右,本地服务启动时间约 118 秒,生产构建时间 205 秒。我们另一个项目也是基于此框架,页面数量200个左右,本地服务慢到无法启动。

  3. 页面的公共样式和 js 并没有提取,生产构建包大小 20MB。如果能提取公共文件,比如各页面公用的 vue、vue-i18n 和 lodash 等库可以合并为一个 js 公用。这样构建包会更小,运行时各页面可以共用缓存,同时减少页面首屏渲染时间。

  4. 页面部分静态资源HTTP缓存设置不正确。会导致发版本后文件有更新,用户访问命中到旧的文件。

    1. 有些静态资源比如 style.css,是通引入的,并没有交给 webpack 管理。生产构建后如下
    ini 复制代码
    <link rel="stylesheet" href="style.css">
    1. 静态资源响应头HTTP缓存设置如下,也就是强制缓存2小时。
    ruby 复制代码
    Cache-Control:max-age=7200
  5. 使用webpack-bundle-analyzer分析构建结果:有冗余的js引入。

  6. 使用Chrome lighthouse分析,建议去掉冗余js和css,优化静态资源加载顺序

  7. static目录下的文件是全部复制到构建目录的,包含了大量无用的文件

  8. i18n文件多个页面共用,打包进每个页面,增加了包大小。

i18n文件放在页面级别

pages/user/login和pages/user/register两个页面用i18n文件是这样写的

css 复制代码
module.exports = {
    back: '返回',
    login: {
        title: '登录'
        ...
    },
    register: {
        title: '注册'
        ...
    }
}

这种目录结构的优点:

  1. login和register页面都共用一些国际化Key,比如"back"
  2. 共用的国际化Key,一处修改,全局生效

缺点也很明显

  1. 很难评估某个国际化Key是否是共用的。勉强用了,需要更新的时候,由于难以评估影响范围,只好在页面再声明一份。

    1. 比如back的值需要改为"取消",影响到的页面都要评估下
  2. 构建包包含的国际化文件冗余。比如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,优点如下

  1. 修改locales不会影响其他页面

  2. 构建包只包括当前页面下的locales文件

总结

i18n文件放在页面级别,项目构建包大小平均减少30%。

框架升级为Vue-cli

当前框架基于webpack3, 而webpack3 发布于2017年,最新的webpack版本是5。Vue-cli集成了webpack的能力,配置比webpack简单,首先想到的是框架升级为Vue-cli5。

升级步骤

  1. node版本升级16+。因为vue-cli依赖。

  2. 配置文件vue-config.js的主要配置说明:

    1. 页面多入口pages
    2. 提取各页面公共库:vue和vue-i18n为公共js,取名chunk-libs.js
    3. 其他逻辑和原框架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?

  1. 需要修改构建配置提升页面性能,Vue-cli的可定制性不如webpack, 比如: 提取css,压缩css, 去冗余css, 提取公共js等。
  2. Vue-cli相关资料没有webpack丰富
  3. webpack5更流行更通用,易于交流
  4. Vue-cli封装了webpack,webpack更接近原理

升级步骤

  1. 项目结构

    1. 样式文件挪到src/assets/css目录。由页面入口文件main.js引入,这样webpack loader会对样式文件压缩、去冗余处理、提取公共样式文件、生成带hash的文件

    arduino 复制代码
    import '@/assets/css/style.css'
    1. 图片挪到src/assets/images目录。这样webpack会压缩图片,并生成带hash的图片 1```
相关推荐
持续前行15 小时前
vscode 中找settings.json 配置
前端·javascript·vue.js
JosieBook15 小时前
【Vue】11 Vue技术——Vue 中的事件处理详解
前端·javascript·vue.js
安逸点15 小时前
Vue项目中使用xlsx库解析Excel文件
vue.js
一只小阿乐15 小时前
vue 改变查询参数的值
前端·javascript·vue.js·路由·router·网文·未花中文网
小酒星小杜16 小时前
在AI时代下,技术人应该学会构建自己的反Demo地狱系统
前端·vue.js·ai编程
Code知行合壹16 小时前
Pinia入门
vue.js
今天也要晒太阳47316 小时前
element表单和vxe表单联动校验的实现
vue.js
依赖_赖17 小时前
前端实现token无感刷新
前端·javascript·vue.js
hhcccchh18 小时前
学习vue第十三天 Vue3组件深入指南:组件的艺术与科学
javascript·vue.js·学习
zhengxianyi51518 小时前
ruoyi-vue-pro本地环境搭建(超级详细,带异常处理)
前端·vue.js·前后端分离·ruoyi-vue-pro