优化Vue项目编译文件大小的方法步骤


Posted in Javascript onMay 27, 2019

与其说是优化 Vue,不如说主要是在 webpack 打包的配置中做些文章,使得 Vue 编译后的文件尽可能的小。以下介绍自己在项目中进行优化的过程,其中的内容也许并不适合于每个项目,但整体思路是差不多的。

定位问题

要想进行优化,首先我们得清楚问题所在。即:是哪些代码/依赖包导致最后的编译文件过大?

这里,我们需要使用 webpack-bundle-analyzer 工具。修改 package.json 文件,添加:

"analyze": "NODE_ENV=production npm_config_report=true npm run build"

然后执行:

npm run analyze

便会在浏览器中打开一个页面,展示编译后的文件大小及各部分内容大小。以下是项目在优化前的分析结果:

优化Vue项目编译文件大小的方法步骤

从图中可以看出,最后编译出的 vendor.js 文件达到了 5MB,其中主要来自 echarts。此外,由于 element-ui 在使用时已经注意到按需加载组件,所以可优化的部分不多;而 lodash 由于没有按需加载,所以成为需要优化的另一个核心部分。

使用按需加载优化

这里主要是对 lodash 进行优化。当我们在使用 lodash 时,如果使用:

import _ from 'lodash'

_.get(obj, 'key', 'default_value')

这种方式的话,则在编译时会默认将 lodash 的全部内容进行编译打包。

webpack 的介绍中确实提到了按需加载,但这个概念可能会出现理解上的偏差,下面我们举例说明:

// 方法一:会导致加载全部的 lodash 库
import _ from 'lodash'
_.get()

// 方法二:只会加载其中的 get 方法
import get from 'lodash/get'
get()

即在不添加其他插件和配置的情况下,webpack 还做不到如此智能。

想要实现在使用方法一的情况下,也能按照我们使用过的方法真正「按需加载」,则需要使用插件并添加配置:

首先执行:

npm i --save-dev babel-plugin-lodash babel-cli babel-preset-es2015

然后修改 .babelrc

{
 "plugins": ["lodash"],
 "presets": ["es2015"]
}

之后修改 webpack.prod.conf.js

module: {
  loaders: [{
    'loader': 'babel-loader',
    'test': /\.js$/,
    'exclude': /node_modules/,
    'query': {
      'plugins': ['lodash'],
      'presets': ['es2015']
    }
  }]
}

这之后便可以实现按需加载 lodash 了。重新进行分析,会发现 lodash 部分的大小已经可以忽略不计了。

对于其他的,如 Element-UI 之类的第三方库,如果我们只使用到了为数不多的组件,建议查找相应的按需加载插件和配置方式,这样可以极大的减少该部分编译的大小。

路由懒加载

当我们配合 Vue-Router 构建单页应用时,大量的组件会导致首屏加载缓慢,如官方文档所言:

当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

只需将原有的:

import Test from '../pages/test'

export default new Router({
  routes: [
    {
      path: '/test',
      name: 'test',
      component: Test
    }
  ]
});

改为:

const Test = () => import('../pages/test')

export default new Router({
  routes: [
    {
      path: '/test',
      name: 'test',
      component: Test
    }
  ]
});

注意首行的不同。

第三方库懒加载

在实际开发中,可能存在这样的场景:

在某个组件/文件中需要使用 moment 第三方库来进行时间处理,但其他组件根本用不到。

如果我们这样引入 moment:

import moment from 'moment'

export default {
  data () {
    
  },
  mounted () {
    
  }
}

则该库会合并在 vendor.js 中,造成首屏加载缓慢。

为了解决这个问题,我们可以改成以下引入方式:

export default {
  name: '',
  beforeCreate () {
    import('moment').then(module => {
      this.moment = module;
    });
  },
  data () {
    return {
      moment: null
    }
  }
}

这种方式可以使得 moment 库只在该组件使用处引入。注意,这种方式需要考虑「moment 调用时机与 moment 使用的先后问题」。

注:如果该组件是页面级别的组件,则使用「路由懒加载」中的方法就可以了。

使用 CDN 外部加载

如上所示,echarts 模块占了很大的部分,由于没有找到 echarts 按需加载的插件,这里我们通过外部引用的方式来减少编译的大小。

首先,我们修改 index.html,从 CDN 中引入 echarts 文件:

<script src="https://cdn.bootcss.com/echarts/3.7.0/echarts.min.js"></script>

注意,如果需要地图组件,也需要一并引入。

这之后我们需要删除所有 import echarts from 'echarts' 的代码,即不再通过这种方式引入 echarts。

但问题来了,如果这么做的话,webpack 在打包的时候会发现 echarts 变量不存在而停止编译。解决办法是,我们需要在 webpack 配置中告知编译器,对于 echarts 变量使用了引入外部资源的方式。需要修改 webpack.base.config.js

module.exports = {
  externals: {
    "echarts": "echarts"
  },
}

这之后我们便可以直接使用 echarts 这一变量而不会导致编译错误了。

当我们将所有采用之前方式引入 echarts 的代码删除或注释之后,再次进行分析,会发现编译大小少了很多。

经过以上两步,原本 5M 的编译文件变为了 1.67 M。

优化Vue项目编译文件大小的方法步骤

这之后,我们还可以根据分析结果,针对性地进行优化。如更换时间库为更轻量级的 spacetime 等。

服务器端开启 gzip

使用 gzip 可以进一步压缩文件,使得服务器传递给浏览器的文件是经由压缩之后的,待浏览器收到之后再解压缩。要使用这一方式,需要服务器端的支持,这里以 Nginx 为例。

nginx.conf 中,添加如下配置:

gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/javascript;
gzip_vary off;

之后刷新页面( 注意禁用缓存 ),观察 js、css 等资源文件的请求中是否包含 Content-Encoding: gzip,如果存在,则表明 gzip 已成功。

注意,在 gzip_types 中规定了哪些请求类型会使用 gzip 进行压缩。对于没有使用 gzip 的资源文件,可将其 Content-type 类型加入 gzip_types 之中。

服务器端渲染

注意,在以上对打包过程的优化中,受影响的主要是 vendor.js 文件中第三方库的部分( gzip 方法会影响全部资源文件 )。

如果我们想继续进行优化,就需要考虑服务器端渲染了。

Vue 的作用机制实际是使用 js 向 html 中挂载组件,如果我们能够将这一过程放在服务器端进行,就可以不再向浏览器传输一部分驱动文件,从而进一步减少浏览器所需的文件大小。不过这一过程需要服务器的额外支持,有兴趣的同学可以参考:实例 PK ( Vue服务端渲染 VS Vue 浏览器端渲染 )。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中函数声明优先于变量声明的实例分析
Mar 01 Javascript
jquery插件如何使用 jQuery操作Cookie插件使用介绍
Dec 15 Javascript
JavaScript静态类型检查工具FLOW简介
Jan 06 Javascript
在JavaScript中操作时间之getYear()方法的使用教程
Jun 11 Javascript
JS仿淘宝实现的简单滑动门效果代码
Oct 14 Javascript
jQuery实现只允许输入数字和小数点的方法
Mar 02 Javascript
JavaScript基础之AJAX简单的小demo
Jan 29 Javascript
webstorm添加vue.js支持的方法教程
Jul 05 Javascript
canvas基础绘制-绚丽倒计时的实例
Sep 17 Javascript
关于react中组件通信的几种方式详解
Dec 10 Javascript
vue中组件通信的八种方式(值得收藏!)
Aug 09 Javascript
vue单文件组件无法获取$refs的问题
Jun 24 Javascript
了解JavaScript表单操作和表单域
May 27 #Javascript
分享一个vue项目“脚手架”项目的实现步骤
May 26 #Javascript
使用JS判断页面是首次被加载还是刷新
May 26 #Javascript
Node.js 多进程处理CPU密集任务的实现
May 26 #Javascript
小程序封装路由文件和路由方法(5种全解析)
May 26 #Javascript
vue2.0 实现富文本编辑器功能
May 26 #Javascript
富文本编辑器vue2-editor实现全屏功能
May 26 #Javascript
You might like
用PHP调用数据库的存贮过程!
2006/10/09 PHP
pw的一个放后门的方法分析
2007/10/08 PHP
PHPMailer发送HTML内容、带附件的邮件实例
2014/07/01 PHP
PHP使用Redis实现防止大并发下二次写入的方法
2017/10/09 PHP
PHP面向对象程序设计内置标准类,普通数据类型转为对象类型示例
2019/06/12 PHP
JavaScript中继承的一些示例方法与属性参考
2010/08/07 Javascript
jQuery实现鼠标经过图片预览大图效果
2014/04/10 Javascript
JavaScript操作Oracle数据库示例
2015/03/06 Javascript
深入理解JavaScript函数参数(推荐)
2016/07/26 Javascript
javascript验证手机号和实现星号(*)代替实例
2016/08/16 Javascript
Node.js测试中的Mock文件系统详解
2016/11/21 Javascript
Angularjs中的ui-bootstrap的使用教程
2017/02/19 Javascript
JavaScript纯色二维码变成彩色二维码
2020/07/23 Javascript
jQuery 添加样式属性的优先级别方法(推荐)
2017/06/08 jQuery
jQuery实现一个简单的验证码功能
2017/06/26 jQuery
微信小程序之前台循环数据绑定
2017/08/18 Javascript
基于React+Redux的SSR实现方法
2018/07/03 Javascript
解决bootstrap中下拉菜单点击后不关闭的问题
2018/08/10 Javascript
Node.js的进程管理的深入理解
2019/01/09 Javascript
async/await优雅的错误处理方法总结
2019/01/30 Javascript
从0到1构建vueSSR项目之node以及vue-cli3的配置
2019/03/07 Javascript
Vue 解决多级动态面包屑导航的问题
2019/11/04 Javascript
VUEX 数据持久化,刷新后重新获取的例子
2019/11/12 Javascript
uni-app从安装到卸载的入门教程
2020/05/15 Javascript
Python字符串逐字符或逐词反转方法
2015/05/21 Python
Python中的连接符(+、+=)示例详解
2017/01/13 Python
python机器学习之KNN分类算法
2018/08/29 Python
python实现蒙特卡罗方法教程
2019/01/28 Python
解决TensorFlow调用Keras库函数存在的问题
2020/07/06 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
毕业生多媒体设计求职信
2013/10/12 职场文书
单位活动策划方案
2014/08/17 职场文书
违纪检讨书
2015/01/27 职场文书
2015年节能降耗工作总结
2015/05/22 职场文书
SpringCloud之@FeignClient()注解的使用方式
2021/09/25 Java/Android
vue+elementUI实现表格列的显示与隐藏
2022/04/13 Vue.js