接手了一个项目,打包完index.js居然有十几M,本地还好,部署线上以后
网速快的情况可能十几秒就能加载完,网速慢的话就会出现
“喂,你们项目挂了,白屏一直。。 哦!! 有了有了有了 挂了哈。”
慢到一定境界了。

查询了很多资料,发现原来webpack也不是那么那么的晦涩难懂,真用到的时候,
学学 用用还挺好玩。

  1. 首先是最管用的一招,就是直接在服务端nginx开启gzip压缩。贼好使,开了就管用。具体方法如下:
	gzip on;
	gzip_disable "msie6";
	gzip_static on;
	gzip_vary on;
	gzip_proxied any;
	gzip_comp_level 6;
	gzip_buffers 4 32k;
	gzip_http_version 1.1;
	gzip_min_length 1k;
	gzip_proxied expired no-cache no-store private auth;	
    gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg 
               image/gif image/png;

在这里插入图片描述
具体每一块代表的意思 我这里粘一下,但是其实我这段代码 可以直接粘过去用。

l gzip:决定是否开启gzip模块。

l gzip_disable:(IE5.5和IE6 SP1使用msie6参数来禁止gzip压缩)。指定哪些不需要gzip压缩的浏览器(将和User-Agents进行匹配)。

l gzip_vary:增加响应头”Vary: Accept-Encoding”。

l gzip_proxied:Nginx做为反向代理的时候启用:·

off –关闭所有的代理结果数据压缩· expired –如果header中包含”

Expires”头信息,启用压缩· no-cache –如果header中包含”Cache-Control:no-cache”头信息,启用压缩·

no-store –如果header中包含”Cache-Control:no-store”头信息,启用压缩·

private –如果header中包含”Cache-Control:private”头信息,启用压缩·

no_last_modified –启用压缩,如果header中包含”Last_Modified”头信息,启用压缩·

no_etag –启用压缩,如果header中包含“ETag”头信息,启用压缩·

auth –启用压缩,如果header中包含“Authorization”头信息,启用压缩·

any –无条件压缩所有结果数据

l gzip_types:这个参数是指设置需要压缩的MIME类型,如果不在设置类型范围内的请求不进行压缩。lgzip_comp_level:设置gzip压缩等级,等级越压缩速度越快文件压缩比越小,反之速度越慢文件压缩比越大。范围是1-9,根据需求设定。

l gzip_buffers:设置用于处理请求压缩的缓冲区数量和大小。比如32 4K表示按照内存页(one memory page)大小以4K为单位(即一个系统中内存页为4K),申请32倍的内存空间。建议此项不设置,使用默认值。

l gzip_http_version:用于识别http协议的版本,早期的浏览器不支持gzip压缩,用户会看到乱码,所以为了支持前期版本加了此选项。默认在http/1.0的协议下不开启gzip压缩。

在自己的nginx服务器的server上方加上gzip的这些配置,重启nginx就可以了。

  1. webpack-bundle-analyzer
    安装webpack-bundle-analyzer,这是一个性能分析的插件。具体用法如下。
    在vue.config.js中,写入
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

然后再configureWebpack中,写入

  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
      // 打包后每个文件的内容和大小
      config.plugins.push(new BundleAnalyzerPlugin());
    } else {
      // 开发环境
    }
  },

提到这里的process.env.NODE_ENV,这里多讲一点,从if判断句,能很容易的看出,这是
说在生产环境下启用,这里的打包时所有配置环境是由,
.env.development
.env.production
来进行配置的。

当你对项目打包的时候,其实是运行了 npm run build
在package.json中有一句话,

build,如果未指定mode,则默认去执行.env.production
scripts中build项 build,如果未指定mode,则默认去执行.env.production

如果指定mode,那么写法如下:

"build:outter": "vue-cli-service build --mode outterProduction",

指定mode为outterProduction,则会默认去执行.env.outterProduction

以.env.production为例,在文件中声明设置NODE_ENV和VUE_APP_NODE_ENV的赋值,则在
configureWebpack中可利用process.env.NODE_ENV来判断当前打包环境是否为生产环境。在这里插入图片描述
继续说 webpack-bundle-analyzer,加上上述的语句后,打包会出现性能分析界面:
在这里插入图片描述
可查看那些文件过大,打包总时长等信息。

  1. cdn
    这是个神器,也很简单,直接将vue、vue-router、vuex及element用script方式引入。
    首先public的index.html中 写上
    <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>

在这里插入图片描述
然后在chainWebpack中 加入下述语句 可在打包的时候,忽略node_modules中,这些包的依赖

    config.externals({
      vue: 'Vue',
      vuex: 'Vuex',
      'vue-router': 'VueRouter',
    });
  1. 终极方案,分包splitChunks
    也是在 vue.config.js中,chainWebpack,加入splitChunks,具体写法如下:
	// 分包
    config.optimization.splitChunks({
      cacheGroups: { // 缓存组,将所有加载模块放在缓存里面一起分割打包
        vendors: { // 自定义打包模块
          name: 'chunk-vendors', // 打包后的文件名
          test: /[\\/]node_modules[\\/]/, // 匹配对应文件
          priority: 1, // 优先级,先打包到哪个组里面,值越大,优先级越高
          // initial: 对于匹配文件,非动态模块打包进该vendor,动态模块优化打包
          // async: 对于匹配文件,动态模块打包进该vendor,非动态模块不进行优化打包
          // all: 匹配文件无论是否动态模块,都打包进该vendor
          chunks: 'initial',
          enforce: true, // true/false。为true时,忽略minSize,minChunks
          reuseExistingChunk: true,
        },
        base: {
          name: 'chunk-base',
          // test: /[\\/]node_modules[\\/](element-ui|vue)[\\/]/,
          test: /[\\/]node_modules[\\/](element-ui)[\\/]/,
          priority: 2,
          chunks: 'initial',
          enforce: true,
          reuseExistingChunk: true,
        },
      },
    });
    ```
通过将index.js中依赖的大包弄出来,形成单独的js来实现分包处理,使主index从根源上变小。

SplitChunks插件配置选项:

chunks选项,决定要提取那些模块。
默认是async:只提取异步加载的模块出来打包到一个文件中。
异步加载的模块:通过import('xxx')或require(['xxx'],() =>{})加载的模块。
initial:提取同步加载和异步加载模块,如果xxx在项目中异步加载了,也同步加载了,那么xxx这个模块会被提取两次,分别打包到不同的文件中。
同步加载的模块:通过 import xxx或require('xxx')加载的模块。
all:不管异步加载还是同步加载的模块都提取出来,打包到一个文件中。
minSize选项:规定被提取的模块在压缩前的大小最小值,单位为字节,默认为30000,只有超过了30000字节才会被提取。
maxSize选项:把提取出来的模块打包生成的文件大小不能超过maxSize值,如果超过了,要对其进行分割并打包生成新的文件。单位为字节,默认为0,表示不限制大小。
minChunks选项:表示要被提取的模块最小被引用次数,引用次数超过或等于minChunks值,才能被提取。
maxAsyncRequests选项:最大的按需(异步)加载次数,默认为 6。
maxInitialRequests选项:打包后的入口文件加载时,还能同时加载js文件的数量(包括入口文件),默认为4。
先说一下优先级 maxInitialRequests / maxAsyncRequests <maxSize<minSize。
automaticNameDelimiter选项:打包生成的js文件名的分割符,默认为~。
name选项:打包生成js文件的名称。
cacheGroups选项,核心重点,配置提取模块的方案。里面每一项代表一个提取模块的方案。下面是cacheGroups每项中特有的选项,其余选项和外面一致,若cacheGroups每项中有,就按配置的,没有就使用外面配置的。
test选项:用来匹配要提取的模块的资源路径或名称。值是正则或函数。
priority选项:方案的优先级,值越大表示提取模块时优先采用此方案。默认值为0。
reuseExistingChunk选项:true/false。为true时,如果当前要提取的模块,在已经在打包生成的js文件中存在,则将重用该模块,而不是把当前要提取的模块打包生成新的js文件。
enforce选项:true/false。为true时,忽略minSize,minChunks,maxAsyncRequests和maxInitialRequests外面选项

这里有个小坑,如果你是单页面spa,splitChunks是可以的,他会在打包完的index.html中,自动引入
你分包后的js文件,
但是如果你的项目是多页面的话,那就需要自己在单独加一下依赖js。
在pages中,每个单独页面下增加chunks。
```javascript
module.exports = {
  pages: {
    index: {
      entry: 'src/main.js',
      template: 'public/index.html',
      filename: 'index.html',
      chunks: ['chunk-vendors', 'chunk-base', 'index'],
    }
  },
 }

其实关于分包还有好多讲究,我还没有细细研究,说白了 水平越高的前端开发工程师,分包会越细致,效果也会越好。

5.懒加载(异步组件)
这个大家都知道

在开发的时候,需要合理的划分各模块,做到首屏加载的时候只读取必要的模块,其他模块在需要的时候才从服务器加载。通过这种异步加载组件的方式,在打包的时候就不会把相关的组件打包到首屏相关的js中,可以减少首屏渲染相关文件的大小。

形如:

() => import('@/views/abc.vue')

不管是路由 还是页面,都可以用这种形式。

大致这一通下来,首屏加载能提升60%-70%,甚至更高。

我的页面从最初十几秒优化下来以后变成3-4秒就可以进入,我猜还有进步空间,
大家一起发掘吧。fighting~

Logo

前往低代码交流专区

更多推荐