最近在做一个项目,技术栈为vue全家桶 + element-ui + echarts,打包后发现有1.44M,首屏体验很差。这能忍?果断开始优化。下面说说我是如何将一个打包后1.44MB的项目变成打包后只有0.42MB,性能提升70% 的。

优化过程

  1. 准备:

    vue-cli提供了一个很方便的查看代码打包后体积的命令,只需在正常的打包命令后加一个--report即可,这样打包完成后会自动开启一个页面,展示各个依赖包的大小。

    npm run build --report
    复制代码
  2. 优化前:

    先看看优化前的大小吧

    这是打包前本地localhost中首屏加载的js文件,只有一个app.js3.2MB)(注意是本地,未打包,未压缩)

    这是打包后的截图,体积为1.44MB,打包时间为72s

  3. 第一次优化:路由懒加载

    说到优化,第一个肯定考虑的是懒加载啦,马上在vue和vue-router的官方文档里找到了解决方案

    结合 Vue 的异步组件和 Webpack 的代码分割功能,轻松实现路由组件的懒加载

    具体做法的话如下:

    首先要安装一个插件Syntax Dynamic Import使项目支持动态import

    cnpm install -S babel-plugin-syntax-dynamic-import
    复制代码

    然后修改.babelrc文件

    // .babelrc 中的plugins数组中多加一个"syntax-dynamic-import"
    {
      "plugins": ["syntax-dynamic-import"]
    }
    复制代码

    最后修改router.js,将所有路由都改为动态加载

    //router.js
    
    //原来的写法:import Home from '@/components/PC/Home'
    //改成下面这种形式(其他路由同理)
    const Home = () => import('@/components/PC/Home')       
    复制代码

    OK,第一次优化完成。让我们打包看看结果如何吧。

    上面两张图分别是本地打包前首屏加载的js资源(经计算大约为3.1MB)的截图和打包后的截图(1.44MB),打包时间为 55s。注意我红色框出来的部分,和优化前相比较打包的结果多了几个以0 1 等数字开头的js文件,这其实就是我们的路由文件被分离了出来,首屏只加载了需要的0.js3.js文件,等到我们切换到其他路由的时候才会加载其他的2.js或者4.js,而不是像以前那样全部包含在了app.js中一次性全加载出来。

    和优化前相比,打包后大小没变,但是打包时间减少了,首屏加载的js资源也少了0.1MB(坑爹么不是!!)。

    打包体积没变,首屏才少了0.1MB?效果这么差,你特么在逗我?

    别着急打我,听我解释。打包体积没变是因为不管路由怎么懒加载,实质上需要的路由文件还是那么多,大小是不变的,所以体积没变。而首屏才少了0.1MB,是因为这个项目本来就是个很小的项目,只有4个页面,而且这个项目的首页引入了echarts本来就相对来说比较大。

    所以说这一步路由懒加载的优化是完全ok的,效果不好是因为是我项目的原因,少了的那0.1MB是剩余未加载的路由文件大小。

    如果你的项目有很多个页面,那么路由懒加载的效果应该会不差。

    我们再次看看这个图

    发现左边黄色的框echarts和右边蓝色的框element-ui体积占了大头,我们先看element-ui占了556KB,现在开始针对element-ui进行第二次优化

  4. 第二次优化:element-ui组件按需加载

    针对element-ui的优化,没啥好说的,具体做法,直接看文档里面的按需引入吧。 照着文档优化了以后,再次打包查看结果:

    这次优化后,打包用了45s,总大小由1.44MB变成了1.16MB

    而且element-ui模块所占的大小也由556kb变成了267kb,效果还行。但是这点提升怎么满足的了我?解决了element-ui,我们看看另外一个模块echarts:

    element-ui还要过分!!足足占了606kb,马上针对最大的boss----echarts进行优化。

  5. 第三次优化:使用 CDN 外部加载资源

    这次优化主要是针对echarts,在其文档里也有提到按需加载,但是这次我们不用按需加载了,我想把echarts彻底干掉!我们这次要使用webpackexternals参考这里

    防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。具有外部依赖(external dependency)的 bundle 可以在各种模块上下文(module context)中使用,例如 CommonJS, AMD, 全局变量和 ES2015 模块。

    具体做法:

    首先在index.html中引入echarts的外部CDN(如果需要地图组件,也需要一并引入)

    //index.html
    <script src="https://cdn.bootcss.com/echarts/4.1.0/echarts.min.js"></script>
    复制代码

    然后在webpack.base.config.js中,做如下改动

    //webpack.base.config.js   module.exports中增加externals对象
    module.exports = {
        externals: {
            "echarts": "echarts"        //默认是配置引用的库(这里是echarts)暴露出的全局变量
        },
    }
    复制代码

    查看优化结果:

    这是打包前的本地首屏加载资源的截图,可算出这次一共加载了1.31MB(没有算上echarts.min.js,因为那是CDN资源),相对于第一次优化后的3.1MB已经少了很多了。

    打包后的截图如下

    可以看到打包后的体积只有434.7KB,而且这次打包只花了34s,最重要的是echarts也真的被干掉了!!

    惊不惊喜!!意不意外!!

    ### 各次优化的表格

    懒得看图的同学可以直接看下面这张表格

    #

    打包后体积

    压缩后体积

    首屏js资源

    打包耗时

    优化前

    1.44M

    425K

    3.2M

    72s

    第一次优化(路由懒加载)

    1.44M

    434K

    3.11M

    55s

    第二次优化(element-ui按需加载)

    1.16M

    381K

    1.3M

    45s

    第三次优化(引入外部CDN)

    434K

    121K

    1.3M

    34s

    可以看出,我们的优化还是很有成效的,各种体积和打包耗时差不多减少了70% 左右。

    ### 总结

    这部分一定要看啊啊啊

    • 遇到webpack打包性能问题,先执行npm run build --report分析一波,然后根据分析结果来做相应的优化,谁占体积大就干谁
    • 路由很多的复杂页面,路由懒加载是肯定要做的
    • 现在很多库都有提供按需加载的功能,有需要的话可以按照官方文档的做法来按需加载
    • webpack提供的externals可以配合外部资源CDN轻松大幅度减少打包体积,适用于echartsjQuerylodash这种暴露了一个全局变量的库
    • 千万不要忘了开启Gzip压缩
    • 本文讲的只是针对于webpack层面的优化,性能优化不只这些,还有其他方面的优化,比如页面渲染优化(减少重排)网络加载优化等。

亲爱的阿乾
885 声望22 粉丝

此时无能为力,此心随波逐流