优化 Vue 项目编译文件大小

与其说是优化 Vue,不如说主要是在 webpack 打包的配置中作些文章,使得 Vue 编译后的文件尽量的小。如下介绍本身在项目中进行优化的过程,其中的内容也许并不适合于每一个项目,但总体思路是差很少的。

定位问题

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

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

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

而后执行:css

npm run analyze

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

image_1boript2gp7jl2nqcmud7kpsm.png-524kB

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

使用按需加载优化

这里主要是对 lodash 进行优化。当咱们在使用 lodash 时,若是使用:java

import _ from 'lodash'

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

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

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

// 方法一:会致使加载所有的 lodash 库
import _ from 'lodash'
_.get()

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

即在不添加其余插件和配置的状况下,webpack 还作不到如此智能。nginx

想要实如今使用方法一的状况下,也能按照咱们使用过的方法真正「按需加载」,则须要使用插件并添加配置:web

首先执行:

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。

image_1borqhoh016un1gt7b8f1b25djp13.png-505.8kB

这以后,咱们还能够根据分析结果,针对性地进行优化。如更换时间库为更轻量级的 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 浏览器端渲染 )


参考

  1. 实例 PK ( Vue服务端渲染 VS Vue 浏览器端渲染 ) - segmentfault
  2. 使用vue-cli生成的vendor.js文件太大,有办法减小体积吗? - segmentfault
  3. Webpack 打包优化之体积篇
  4. babel-plugin-lodash
  5. Nginx开启Gzip压缩大幅提升页面加载速度 - 博客园
  6. Nginx启用Gzip压缩js无效的缘由 - 博客园
  7. Wabpack系列:在webpack+vue开发环境中使用echarts致使编译文件过大怎么办? - 博客园
  8. Webpack 打包优化之速度篇
  9. 开启gzip 若是浏览器端不支持解压 页面会怎么样? - 知乎
  10. 如何写一手漂亮的 Vue
相关文章
相关标签/搜索