深入浅出webpack之tree shaking以及其他优化

115 阅读3分钟

tree shaking

  • 什么是tree shaking

    • tree shaking是一个计算机术语,表示消除死代码(dead_code)
    • 最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么我们在进行函数式编程的时候,尽量使用纯函数的原因之一)
    • 后来tree shaking也被应用于其他的语言,比如javascript dart
  • javascript的tree shaking

    • 对javascript进行tree shaking是源自于打包工具rollup
    • 这是因为tree shaking依赖于ES Module的静态语法分析(不执行任何代码,可以明确知道模块的依赖关系)
    • webpack2正式内置支持了ES2015模块和检测未使用模块的能力
    • 在webpack4正式扩展了这个能力,并且通过package.json的sideEffects属性作为标记,告知webpack在编译时,哪里文件可以安全的删除掉
    • webpack5中,也提供了对部分commonjs的他tree shaking的支持
  • webpack实现tree shaking

    • usedExports:通过标记某些函数是否被使用,之后通过terser来进行优化

      • 将mode设置为development模式

        • 为了可以看到 usedExports带来的效果,我们需要设置为 development 模式
        • 因为在 production(默认usedExports:true,minimize:true)模式下,webpack默认的一些优化会带来很大影响
      • 设置usedExports为true和false对比打包后的代码

        • 在usedExports设置为true时,会有一段注释:unused harmony export mul

        • 这段注释的意义是什么呢?告知Terser在优化时,可以删除掉这段代码

              module.exports = {
                  // 省略其他配置
                  mode:"development",
                  optimization:{
                      // 作用是标注出来那些函数没有被使用
                      usedExports:true// production模式下默认为true
                  }
              }
          

          image.png

      • 这个时候,我们将minimize:设置true:

        • usedExports设置为false时,mul函数没有被移除掉

        • usedExports设置为true时,mul函数有被移除掉

                  module.exports = {
                      // 省略其他配置
                      mode:"development",
                      optimization:{
                          // 作用是标注出来那些函数没有被使用
                          usedExports:true// production模式下默认为true
                          minimize:true
                      }
                  }
          

          image.png image.png

    • sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用

      • sideEffects用于告知webpack compiler哪些模块是有副作用的
      • 副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义
    • 在packagejjson中设置sideEffects的值

      • 如果我们将sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports
      • 如果有一些我们希望保留,可以设置为数组
    • 比如我们有一个formatjs、style.css文件

      • 该文件在导入时没有使用任何的变量来接受

      • 那么打包后的文件,不会保留format.is、style.css相关的任何代码

        image.png

        image.png

  • css的tree shaking

    • 安装 purgecss插件 npm i purgecss-webpack-plugin -D
    • 配置 purgecss (生产环境)
    const path = require('path')
    const PurgeCssWebpackPlugin = require('purgecss-webpack-plugin');
    // 一般不用单独安装,其他插件已经有安装,可直接使用
    const glob = require("glob");
    module.exports = {
        mode:"production",
        plugins:[
            new PurgeCssWebpackPlugin({
                // 表示匹配src目录下所有文件夹下的所有文件,不包含文件夹
                paths:glob.sync(`${path.resolve(__dirname,'../src')}/**/*`,{nodir:true}),
                safelist:function(){
                    return {
                        standard:["html","body"]
                    }
                }
            })
        ]
    }

什么是HTTP压缩

  • HTTP压缩是一种内置在浏览器和客户端之间的,以改进传输速度和带宽利用率的方式

  • 常见压缩格式

    • compress -UNIX的“compress”程序的方法(历史性原因,不推荐大多数应用使用,应该使用gzip或deflate ) ;
    • deflate -基于deflate算法(定义于RFC 1951的压缩),使用zlib数据格式封装;
    • gzip-GNU zip格式(定义于RFC 1952),是目前使用比较广泛的压缩算法;
    • br-一种新的开源压缩算法,专为HTTP内容的编码而设计,压缩程度很高,但是兼容性不太好;
  • HTTP压缩的流程是什么

    • 第一步:HTTP数据在服务器发送前就已经被压缩了;(可以在webpack中完成)

    • 第二步:兼容的浏览器在向服务端发送请求时,会告知服务器自己支持哪些压缩格式 image.png

    • 第三步:服务器在浏览器支持的压缩格式下,直接返回对应的压缩后的文件,并且在响应头告知浏览器

      image.png

  • webpack对文件进行HTTP压缩

    • 安装插件 npm i compression-webpack-plugin -D
        const CompressionPlugin = require('compression-webpack-plugin');
        module.exports = {
            // 省略其他配置
            plugins:[
                // 一般情况下使用默认设置即可
                new CompressionPlugin({
                    // 表示只有以css和js结尾的文件才被压缩
                    test:/\.(css|js)$/i, 
                    // 表示以哪种压缩方式进行压缩,默认是gzip
                    algorithm:"gzip",
                    // 表示文件大小大于这个值才被压缩,默认是0
                    threshold:0,
                    // 表示 压缩后的文件大小/源文件大小小于这个值才会被压缩,默认是0.8
                    minRatio:0.8
                })
            ]
        }
    

    image.png

HTML文件中代码压缩

  • 我们之前使用了HtmlWebpackPlugin插件来生成HTML的模板,事实上它还有一些其他的配置
  • inject:设置打包的资源插入的位置:true、 false 、body、 head
  • cache:设置为true,只有当文件改变时,才会生成新的文件(默认值也是true)
  • minify: 默认会使用一个插件html-minifier-terser,不需要单独下载 image.png