一、tree-shaking是什么?

这个词应该咱们都不陌生了,翻译过来便是“树摇”。

讲一讲Webpack tree-shaking的触发机制

看一下官方的解释:

Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of ES2015 module syntax, i.e. import and export. The name and concept have been popularized by the ES2015 module bundler rollup.

简言之,tree-shaking有助于咱们减少打包后产物的体积,去掉无用的代码。这儿不多说概念,本文的重点还是在于文章标题,咱们重视的是webpacktree-shaking能力以及触发条件。

二、建立Webpack环境

创立项目

mkdir tree-shaking-webpack && cd tree-shaking-webpack

运用pnpm初始化package.json

pnpm init

装置webpackwebpack-cli

pnpm add webapack webpack-cli -D

创立webpack.config.js装备文件

// webpack.config.js
const path = require("path");
module.exports = {
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "bundle.js",
  },
};

修正package.json

{
  "name": "tree-shaking-webpack",
  "version": "1.0.0",
  "description": "",
  "main": "./src/main.js", // 修正进口
  "scripts": {
    "build": "webpack --config ./webpack.config.js" // 添加build指令
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4"
  }
}

创立进口文件

// src/main.js
console.log('hello wolrd')

履行build指令,能够看到现已打包成功了

讲一讲Webpack tree-shaking的触发机制

但是控制台报了个正告,原因是没有装备mode,咱们装备mode为开发形式development即可

// webpack.config.js
const path = require("path");
module.exports = {
  mode: "development", //开发形式
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "bundle.js",
  },
};

再次履行build,控制台不再报错

讲一讲Webpack tree-shaking的触发机制

三、webpack的tree-shaking

1、经过ES6的import和export触发

依据前面tree-shaking介绍中提到,tree-shaking其实依赖了ES6中的importexport

所以假如咱们先做第一个测验:commonJS是否支撑tree-shaking

咱们新增个compute.js文件

// src/compute.js
const add = (a, b) => {
  return a + b;
};
const sub = (a, b) => {
  return a - b;
};
module.exports = {
  add,
  sub,
};

main.js中引证compute.js,而且只运用add办法

const { add, sub } = require("./compute");
console.log(add(1, 2));

履行打包后,发现main.jssub办法也被打打包了

讲一讲Webpack tree-shaking的触发机制

咱们换成ES6标准的导入和导出

// src/compute.js
export default {
  add,
  sub
}
// src/main.js
import { add, sub } from './compute.js'

履行打包,main.js中不再呈现sub办法

讲一讲Webpack tree-shaking的触发机制

所以得出结论,假如要触发tree-shaking,需求经过ES6importexport触发。

2、经过解构的办法触发

在满意第一点的条件下,咱们试想一下,假如咱们是import整个目标,是否会触发tree-shaking呢?例如:

import compute from './compute'
console.log(compute.add(1,2))

由于这个事例的打包文件体积比较小,咱们看不太出来,咱们测验装置一个lodash来试一下,需求注意的是,咱们需求装置的是lodashESM版别,即lodash-es,不然官方默认的lodashcommonJS标准

pnpm add lodash-es

修正main.js的内容

// src/main.js
import { get } from "lodash-es";
console.log(get({ a: 1 }, "a"));

履行打包,并创立index.html文件引进打包后的bundle.js

讲一讲Webpack tree-shaking的触发机制

打开index.html,检查bundle.js的体积巨细为103kb

讲一讲Webpack tree-shaking的触发机制

假如咱们不运用解构的办法,直接引进整个lodash,然后打包

// src/main.js
import _ from "lodash-es";
console.log(_.get({ a: 1 }, "a"));

再次打包后,能够看到,bundle.js的体积巨细现已来到了恐惧的1.6MB

讲一讲Webpack tree-shaking的触发机制

经过tree-shaking之后,bundle.js只打包了lodashget办法,其他无关的办法都被“摇走了”

讲一讲Webpack tree-shaking的触发机制

所以得出结论,假如要触发tree-shaking,需求经过解构的办法触发。

3、开启production形式

细心的同学其实能够发现,上面第一点事例中,经过import的办法导入了compute.js文件,main.js代码中虽然没有了sub办法,但是compute.js依然会把sub办法打包

讲一讲Webpack tree-shaking的触发机制

这是由于webpack对同一文件中的tree-shaking有必要要开启production形式才干收效

// webpack.config.js
const path = require("path");
module.exports = {
  mode: "production", //出产形式
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "bundle.js",
  },
};

再次履行打包,发现sub办法现已不存在了,而且代码还进行了紧缩

讲一讲Webpack tree-shaking的触发机制

4、总结

经过上面的几个事例,webpack假如要实现tree-shaking有必要满意以下几个条件:

  1. 经过ES6importexport,包括npm包也有必要是ESM
  2. 经过解构的办法引进
  3. 同一文件下,需求开启production形式