打包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```
相关推荐
王解8 分钟前
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(3)
前端·webpack·es6
杨荧2 小时前
【JAVA毕业设计】基于Vue和SpringBoot的宠物咖啡馆平台
java·开发语言·jvm·vue.js·spring boot·spring cloud·开源
NoloveisGod4 小时前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing4 小时前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
理想不理想v4 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试
EasyNTS5 小时前
无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
前端·javascript·vue.js
guokanglun5 小时前
Vue.js动态组件使用
前端·javascript·vue.js
糊涂涂是个小盆友7 小时前
前端 - 使用uniapp+vue搭建前端项目(app端)
前端·vue.js·uni-app
开心工作室_kaic10 小时前
ssm111基于MVC的舞蹈网站的设计与实现+vue(论文+源码)_kaic
前端·vue.js·mvc
bug爱好者11 小时前
如何解决sourcetree 一打开就闪退问题
前端·javascript·vue.js