如何使用Tree-shaking减少代码构建体积

2,914 阅读3分钟

前言

在实际配置Webpack过程中总会遇到一些坑,Tree-shaking就是其中之一,按照教程中一步步配置,你会发现配了半天还是不生效,本文 就是为了解决这个问题而写,希望看到这篇文章的同学能少走一些弯路。

什么是Tree-shaking

Tree-shakingWebpack用来删除冗余代码的一种手段,那冗余代码又是指什么,请看以下代码:

// ~index.js
import { foo } from './content.js';

foo();


// ~content.js
export function foo() {
    alert('I am foo');
}

// 没有被index.js引入,为冗余代码
export function bar() {
    alert('I am bar');
}

函数bar由于没有被引用,因此bar为冗余代码。通过使用Tree-shaking,让bar在打包的时候自动被删除掉,从而减少了代码的构建体积。

如何配置

1、在package.json文件中将sideEffects设为false

sideEffects设为false,告诉Webpack没有文件有副作用,所有文件都可以Tree-shaking,这样会识别全局导入css为无用代码,造成全局导入css被删除。例:import'./styke.css',打包后style.css会被删除,为了解决这个问题,可在css相关loader重新设为truesideEffectstrue表示文件有副作用,不可以Tree-shaking

// ~package.json
{
  "name": "webpackdemo",
  "version": "1.0.0",
  "author": "dengshangli",
  "license": "ISC",
  "description": "",
  "sideEffects": false,
  ...
}

2、将css相关loader中sideEffects设为true

sideEffects设置为trueWebpack会将css代码识别为有副作用,避免Tree-sahking执行全局import 'styles.css'失效。

// ~webpack.config.js
module.exports = {
    module: {
        rules: [{
          test: /\.css$/,
          use: ExtractTextPlugin.extract({
            use: [
              {
                loader: 'css-loader',
                options: {
                   //开启css模块化
                    modules: { localIdentName: '[path][name]__[local]--[hash:base64:5]' },
                    sourceMap: true,
                },
             }, 
              'postcss-loader'
            ],
          }),
           // 将css代码识别为有副作用,避免tree-sahking执行全局import 'styles.css'失效
          sideEffects: true,
          exclude: /node_modules/,
        }],
    },
  ...
}

3、使用TerserPlugin,js代码压缩插件

TerserPluginWebpack内置,无需安装,不使用TerserPlugin无法冗余代码无法删除成功,Tree-shaking本身只是为冗余代码添加上标记,真正去除冗余代码是通过压缩工具来进行的。

// ~webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    // 开启js代码压缩,生产环境自动为true
    minimize: true,
    // 压缩器
    minimizer: [
      // js代码压缩插件,tree-shaking必须使用
      new TerserPlugin(),
    ...
    ],
  },
  ...
}

4、让@babel/preset-env不编译ES6模块语句

modules设置为 false,就是告诉 babel 不要编译模块语句,注意,这里不是不编译代码,而是不编译import/export 语句。这会让 Babel 保留我们现有的 ES6 import/export语句,保留的原因是Tree-shaking只支持ES6的模块化导入导出,CommonJs及其他模块化代码无法删除成功。

// ~.babelrc
{
  //babel预设,目的是为了方便配置,集成了多个插件
  "presets": [
    ["@babel/preset-env", { "modules": false }]
  ],
  // babel插件
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

注意事项

  • 以上配置Webpack版本为4.41.5,理论上4.0以上就可以
  • Tree-shaking只支持ES6的模块化导入导出
  • Tree-shaking只有在生产环境中构建才生效

总结

本文只是简单讲解了Tree-shakingWebpack中如何配置,很多细节还没来得及去去深究,例如使用@babel/preset-env插件预设时将配置项modules设置为false,让其不编译ES6模块语句,那这样在不支持import语句的浏览器中代码岂不是执行不了,查看构建后的源码发现并不存在import语句,希望有大神为我解惑。