《十七》对打包后的 JavaScript 文件中的代码进行 Tree Shaking

Tree Shaking 在计算机中表示消除死代码。

Tree Shaking 最早源于 LISP,用于消除未调用的代码,后来也被应用于其他的语言,例如 Javacript、Dart 等。

Javacript 中的 Tree Shaking 依赖于 ESModule 的静态语法分析,不执行任何代码,就可以明确地知道模块的依赖关系。最早源自打包工具 rollup,rollup 主要用于对 ESModule 相关的代码进行打包。Webpack2 开始内置支持 ESModule 和检测未使用模块的能力;Webpack4 正式扩展了这个能力,并且通过 pacjage.json 中的 sideEffects 属性作为标记,告知 Webpack 在编译时哪些文件可以安全地被删除掉;在 Webpack5 中,也提供了对部分 CommonJS 语句的 Tree Shaking 支持。

在 Webpack 中实现 Tree Shaking 可以采用两种不同的方案:usedExports 或者 sideEffects。这两种方案可以独立使用,也可以结合使用。

usedExports:

usedExports:对未使用的函数进行标记,然后就可以通过 Terser 将其删除掉。

production 模式下默认会开启。

  1. 新建 src/math.jssrc/index.js,并编写代码。
    // src/math.js
    export const increase = (num1, num2) => {
      return num1 + num2
    }
    
    export const decrease = (num1, num2) => {
      return num1 - num2
    }
    
    // src/index.js
    import {increase} from './math'
    console.log(increase(10, 20))
    
  2. webpack.config.js 配置文件中进行配置。
    // webpack.config.js
    module.exports = {
      // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式
      mode: 'development',
      // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容
      devtool: 'source-map',
    }
    
  3. 运行 webpack 命令进行打包,会发现,即使 src/math.js 中的 decrease 函数并没有被导入使用,也还是被导出了。
    在这里插入图片描述
  4. webpack.config.js 配置文件中进行配置。
    module.exports = {
      // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式
      mode: 'development',
      // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容
      devtool: 'source-map',
      optimization: {
        // 对未使用的函数进行标记
        usedExports: true,
      }
    }
    
  5. 运行 webpack 命令进行打包,会发现, src/math.js 中的 decrease 函数没有再被导出了,并且被标记多了一行注释 /* unused harmony export decrease */。如果配置了 Terser,这行注释将会被 Terser 解析,然后 Terser 就会根据这行注释将 decrease 函数删除掉。
    在这里插入图片描述
  6. webpack.config.js 配置文件中进行配置。
    const TerserPlugin = require('terser-webpack-plugin')
    
    module.exports = {
      // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式
      mode: 'development',
      // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容
      devtool: 'source-map',
      optimization: {
        // 对未使用的函数进行标记
        usedExports: true,
        // 使用 Terser 将未使用的函数删除掉
        minimize: true,
        minimizer: [
          new TerserPlugin({
            terserOptions: {
              keep_fnames: true,
            }
          })
        ]
      }
    }
    
  7. 运行 webpack 命令进行打包,会发现, src/math.js 中的 decrease 函数没有再被打包到输出文件中了。
    请添加图片描述

sideEffects:

sideEffects:告知 Webpack Compiler 哪些模块有副作用。如果模块有副作用的话,导入了该模块但是并没有使用,打包时该模块将不会被删除掉;如果模块没有副作用的话,导入了该模块但是并没有使用,打包时该模块将会直接被删除掉。

模块有副作用的意思是:模块中的代码有执行一些有副作用的操作。

通过配置 usedExports 实现对整个模块的 Tree Shaking 存在的问题:

  1. 新建 src/format.jssrc/index.js 文件,并编写代码。
    // src/format.js
    export const dateFormat = () => {
      return '2023-10-28'
    }
    
    src/index.js
    import './format'
    console.log('index')
    
  2. webpack.config.js 配置文件中进行配置。
    const TerserPlugin = require('terser-webpack-plugin')
    
    module.exports = {
      // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式
      mode: 'development',
      // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容
      devtool: 'source-map',
      optimization: {
        // 对未使用的函数进行标记
        usedExports: true,
        // 使用 Terser 将未使用的函数删除掉
        minimize: true,
        minimizer: [
          new TerserPlugin({
            terserOptions: {
              keep_fnames: true,
            }
          })
        ]
      }
    }
    
  3. 运行 webpack 命令进行打包,会发现,配置 usedExports 后,dateForamt 函数确实没有被打包到输出文件中,但是对 src/format.js 文件的引入还存在。
    在这里插入图片描述

通过配置 sideEffects 实现对整个模块的 Tree Shaking:

  1. 新建 src/format.jssrc/format.jssrc/index.js 文件,并编写代码。
    // src/format.js
    export const dateFormat = () => {
      return '2023-10-28'
    }
    // 没有副作用
    
    // src/math.js
    export const sum = () => {
      return 30
    }
    // 有副作用
    window.message = 'Hello World'
    
    src/index.js
    import './format'
    import './math'
    console.log('index')
    
  2. webpack.config.js 配置文件中进行配置。
    module.exports = {
      // 由于 production 模式下默认会做很多的优化,此处为了能够更好地查看到 Tree Shaking 的效果,使用 development 模式
      mode: 'development',
      // 此处配置 source-map 是为了能更清晰地查看打包后文件的内容
      devtool: 'source-map',
    }
    
  3. package.json 中配置 sideEffects 来告知 Webpack Compiler 哪些模块有副作用。
    // package.json
    "sideEffects": [
        "./src/math.js",
        // 如果属性值是一个数组,需要为数组添加一个项 `**.css`  来CSS 文件进行配置,否则的话,项目中引入的 CSS 文件会被作为没有副作用的模块,在打包时被删除掉。
        "**.css"
    ],
    

    sideEffects 的属性值可以是数组,来表示哪些模块有副作用;也可以是布尔值,为 true 表示所有模块都有副作用,为 false 表示所有模块都没有副作用。
    在开发中,更推荐编写纯模块。因此,更推荐配置 "sideEffects": false 来将所有模块都作为没有副作用的模块,此时对 CSS 的配置可以放到 webpack.config.js 配置文件中。

    // webpack.config.js
    module: {
       rules: [
         {
           test: /\.css$/,
           use: ["style-loader", "css-loader"],
           // 将匹配到的所有 CSS 文件都作为有副作用的文件
           sideEffects: true,
         }
       ]
     }
    
  4. 运行 webpack 命令进行打包,会发现,没有副作用的 src/format.js 整个文件都没有被打包到输出文件中,有副作用的 src/math.js 被保留了下来。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值