Webpack-优化技巧

我们构建的初始大小

我们处理一个构建时收到了以下两条错误消息: Vue 建议包大小不超过 244 KiB。我们一共有 14 项 assets 的大小超限了。此外还有四个入口点的大小也超过了建议值。以下是我将构建的大小减半的具体方法。

是什么让构建包变得这么大?

首先我需要了解构建包为什么会变得这么大。为此我安装了 webpack-bundle-analyzer。它能提供包中所有项目大小的可视指南。

1
npm install --save-dev webpack-bundle-analyzer

接下来我对 webpack 做了些配置,然后就能在 vue.config.js 文件中使用它了。我的 vue.config.js 文件现在是这个样子:

1
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')

插件装好后我再次运行构建,可以看到构建包的大小是 2.48MB。从图中可以找出影响体积的罪魁祸首有:

  • vue-echarts
  • vuetify
  • moment
  • lodash

减少 Lodash 的大小

Lodash 占用了 70.74KB 的空间。我们框架中的所有应用只有两处用到了 Lodash,才两个方法就占这么多空间不太划算。 我们加载的还不止是 lodash,而且还加载了 vue-lodash。所以第一步就是从 package.json 中删除 vue-lodash,本来就用不着它。 下一步是只从 lodash 中导入我们需要的两个项目,不再加载整个库。我们使用的是 cloneDeep 和 sortBy。我换掉了之前会导入整个 lodash 库的调用:

1
import _ from 'lodash';

新的调用应该只导入我们需要的两个项目。为此我把导入目标从 lodash 改成了 lodash/core:

1
import { cloneDeep, sortBy } from 'lodash/core';

改动完成后,构建包大小从 2.48MB 减少到了 2.42MB。下图显示了构建的当前大小。 在这里,我们可以看到构建包中 lodash 的部分有多大。

减少 moment.js 的大小

Moment.js 在我们的包中占用了 234.36KB 的空间。查看分析视图可知,这部分数据中绝大部分是国际化语言环境,用来支持一大堆语言版本。我们根本不会使用 moment.js 的这部分功能,所以它就算是包里的无用数据了。 还好我们可以直接删除它。原来的调用会导入所有 moment.js 内容:

1
import moment form 'moment';

我们可以改成只导入日期操作代码,如下所示:

1
import moment from 'moment/src/moment'

做这种替换可能会出现一个问题,至少在我们的代码库中遇到了这个问题。有 18 处代码会导入 moment.js,我本可以在代码中执行全局搜索和替换的。但是如果我们向框架添加一个新的应用程序,开发人员很可能会使用默认调用来导入 moment.js,那样的话我们又会导入所有国际化语言环境了。 所以妥协方案是在 webpack 中创建一个快捷方式别名。该快捷方式将用’moment/src/moment’替换所有导入’moment’的调用。我们可以使用 resolve 在我们的 vue.config.js 文件中添加该别名并进行设置。我的 vue.config.js 文件现在变成这样。 现在运行我们的构建,可以看到包大小已经缩减到 2.22MB。 观察视图中的 moment.js,可以看到国际化区域设置完全没有加载。 删除 moment.js 中的语言环境后,每当我启动服务器运行我的代码时都会发生错误,说它无法找到./locale。经过一些研究我发现这是 moment.js 的一个存在多年的已知问题:moment.js 总是会加载 locales,还假定 locales 存在。你不能让 moment 只加载日期操作函数。 为了解决这个问题,我使用内置的 webpack IgnorePlugin 忽略了这个消息。下面是我添加到 vue.config.js 文件中的插件代码:

1
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

减少 Vuetify.js 的大小

下一个目标是 Vuetify.js。Vuetify 占用 500.78KB 空间。一个产品就占这么多空间实在不是个小数字。 Vuetify 提供了一种他们称之为“点菜”的功能,允许你仅导入你要使用的 Vuetify 组件,从而减小 Vuetify 的体积。这里的挑战在于我们有如此多的应用程序,找出来哪些组件是完全不会被用到的也不是容易的事情。 在当前版本的 Vuetify(当我写这篇文章的时候版本为 1.56)中,他们提供了一个名为 vuetify-loader 的产品。它将遍历你的代码并找出你正在使用的所有组件,然后只将这些组件导入你的构建包。注意:vuetify v2 将内置此功能。在 v2 版本发布之前,你必须使用 vuetify-loader 来按需导入组件。Vuetify 文档提到,我们要获得所有所需的样式就要在 stylus 中导入它们。 这时我发现我们还在用旧版 vuetify.js。所以我决定先把 vuetify 升级到最新版本。我还同时安装了样式和 vuetify-loader:

1
npm install vuetify vuetify-loader stylus stylus-loader style-loader css-loader --save

我用来导入 Vuetify 的插件代码有一些自定义主题,可以使用我们公司的调色板。以下是我目前使用的 Vuetify 插件: 我需要将“从 Vuetify 导入”更改为“从 vuetify/lib 导入”。我还会导入 stylus 以获得所有样式。然后插件代码会变成: 最后一步是告诉 webpack 使用 vuetify-loader 插件,让它只导入我们需要的组件。我得把插件添加到插件数组里。现在 vue.config.js 文件变成这样: 之后运行构建,包大小减少为 2MB。

减少 vue-echarts 的大小

Vue-echarts 不是我包中最大的项目。Vue-echarts 运行在 echarts 之上。和 Vuetify 一样,我用的这两种产品都还是旧版本。运行下面的命令将它们升级到最新版本:

1
npm install echarts vue-echarts --save

我对 vue-echarts 的 GitHub repo 做了一些研究,查看了所有已解决的问题,发现最新版本的 vue-echarts 允许你通过更改导入的内容来加载较小的包。以前我使用下面的命令导入它:

1
import ECharts from 'vue-echarts';

现在我改成了这样:

1
import ECharts from 'vue-echarts/components/ECharts.vue';

然后运行构建,应用包大小降至 1.28MB。

结   论

目标是精简生产环境上的应用包体积。

  • 版权声明: 本博客所有文章,未经许可,任何单位及个人不得做营利性使用!转载请标明出处!如有侵权请联系作者。
  • Copyrights © 2015-2023 翟天野

请我喝杯咖啡吧~