6
Author: God Q Superman
Translator: Front-end Xiaozhi
Source: medium

If you have dreams and dry goods, search [Moving the World] attention to this Shawanzhi who is still washing dishes in the early morning.

This article has been included in GitHub https://github.com/qq449245884/xiaozhi . There are complete test sites, materials and my series of articles for interviews with first-tier manufacturers.

When I was chatting with my friends about Webpack a while ago, I suddenly mentioned Tree Shaking, but I am ashamed that I have no way to explain how Webpack achieves Tree Shaking, so I took the time to read the Webpack files on the first day of this annual vacation, Then write down what you understand. If you are also interested, please read it together🙌.

What is Tree Shaking

Tree Shaking is an optimization, a common term used in JavaScript to denote the removal of useless code, the origin of the name Tree Shaking seems to mean "When you shake a tree vigorously, only Green leaves will remain, and other dead leaves will fall to the ground.” And those green leaves are the real useful code in the packaged file.

When using it, it should be noted that Tree Shaking can only be used on static structure (for example: import and export ), and 0620d9009a15e1 such as dynamic structure require not be detected. For example, import must be at the top of the file if it is to be loaded into a module , but require can be used anywhere. For example, in the following scenario, you must wait until runtime to know what module is:

let module = null;

if (Math.random() * 10 > 5) {
  module = require('module1');
} else {
  module = require('moudle2');
}

Before starting to understand the work of Tree Shaking, some people should be curious. Even if you have never set up Tree Shaking in Webpack, the useless code will be removed!

That is because of the need to perform Tree Shaking ModuleConcatenationPlugin (Figure I), and in addition there is a Webpack mode , especially if you have not been to set mode value, that mode will by default be production (Figure II), then production ModuleConcatenationPlugin will be turned on in the default options (also Figure 2), so it's not surprising that you don't usually notice it, because Webpack does it for you.

image.png

image.png

How Tree Shaking works

Because Production will open ModuleConcatenationPlugin for you, so when we experiment later, we need to change the mode to none (the Webpack file says that none is the mode to turn off all optimization settings).

A simple initialization example configuration will be attached here. If you are interested, you can clone it and play with it.

First, create a math.js and src under string.js , and then write a separate method to do export , which are add and composeString respectively:

const add = (a, b) => a + b;

export default { add };

const composeString = (a, b) => `${a} ${b}`;

export default { composeString };

Open src under index.js , put add and composeString into import , but only use the add method:

import { add } from './math';
import { addString } from './string';

console.log(add(1, 2))

Finally, execute npm run build or terminal in webpack for packaging. After packaging, we will find that although we only have import add for use, the content of the packaged file will still have composeString :

image.png

But this is normal. After all, we haven't done any processing yet, and Webpack doesn't know which code you use or not when packing, so there is no way to remove composeString for you.

So what kind of code is useful and what isn't? ?

  1. The most obvious definition should be that it is useful if it is implemented. Like add in the example above.
  2. The code with side effect is also used. Like index.js above, it seems that no method is provided, but it will leave log in console during library . In addition, 0620d9009a1821 that will change the execution environment also has side effect of polyfill .

The first case is relatively easy to distinguish, but if it is the second case, you can choose to set it with the sideEffects property in Webpack.

sideEffects

sideEffects can be set to Boolean or Array , when you set it to false , it means that the project will not have sideEffects , that is, export will always be used to determine whether to use it. In addition, sideEffects will depend on providedExports to find 0620d9009a1895 of all export in the module :

image.png

Here's sideEffects is used:

{
  "name": "tree-shaking",
  "sideEffects": false,
  "version": "1.0.0",
  ...
}

As long as package.json is added to sideEffects , and the value is set to flase , it means that all the codes in the project do not have side effect , so Webpack can remove the unused export code when packing.

After adding sideEffects and packing, you will not see composeString in the result:

image.png

Then now we go to src to create another polyfill.js , create a custom method for Array in ployfill.js , and then put it in import to index.js :

index.js

import './polyfill';
import { add } from './math';
import { addString } from './string';

console.log([].customMethod());

polyfill.js

Array.prototype.customMethod = () => {
  console.log('customMethods');
};

If we package the above code, polyfill.js will not be caught by providedExports because there is no export , and it will not be packaged into Production , which will cause an error during execution if the project uses customMethod of Array . Faced with this situation, it is necessary to inform in the sideEffects property that polyfill.js has side effects. The setting method is as follows:

{
  "name": "tree-shaking",
  "sideEffects": ["./src/polyfill.js"],
  "version": "1.0.0",
  ...
}

In this way ,polyfill.js will be packaged directly:

image.png

Finally, two things to note:

  1. If you also use the import.css style in your project, remember to put the file name ending in .css in sideEffects, such as sideEffects: ["*.css"] .
  2. webpack.config.js in optimization also has sideEffects , but the value set here is for node_modules .

useExported

The role of useExported and sideEffects are both used to determine whether to remove the code, but according to the instructions in the Webpack file, useExported is the real Tree Shaking:

image.png

usedExports use terser judgment code has no side effect , if not used, and no side effect , it would mark on its behalf during packaging unused harmony , and minify (with UglifyJS or other tools) when removed.

Before testing usedExports , add square and math.js to export :

const add = (a, b) => a + b;

const square = (a, b) => a * b;

export { add, square };

Next, add optimization.usedExports webpack.config.js

module.exports = {
  ...
  optimization: {
    usedExports: true,
  }
};

Then package the project and you will find that it is only export , but the square will be marked with unused harmony export :

image.png

Then we use uglifyjs-webpack-plugin to shake the unused square from the tree:

npm install -d uglifyjs-webpack-plugin

The settings for webpack.config.js are as follows:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  ...
  optimization: {
    usedExports: true,
    minimize: true,
    minimizer: [
        new UglifyJsPlugin({
            uglifyOptions: {
                compress: { unused: true },
                mangle: false,
                output: {
                    beautify: true
                }
            },
        })
    ],
  }
};

After setting minimizer , pack it again, and you can see that square has been removed:

image.png

The difference between usedExports and sideEffects is that usedExports can use declarative sentences as a unit to determine whether there is side effect , but sideEffects allows Webpack to skip an entire file when packaging, as long as the file appears in sideEffect , it is directly packaged, and it is unnecessary. Side effects were assessed by terser .

Summarize

  1. Tree Shaking can only be used in static structure . If babel in the project will compile static structure into dynamic structure , it needs to be set separately.
  2. When using sideEffects, it should be written in package.json , if it is to optimize the third-party library, it should be written in webpack.config.js in optimization .
  3. usedExports is Tree Shacking. When using it, it will automatically determine the unused code and mark the annotation of unused harmony . If you want to remove it, you need to use minify .

The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool Fundebug .

original:
https://medium.com/starbugs/%E7%B2%BE%E6%B96%E7%9A%84%E6%89%93%E5%8C%85-webpack-%E7%9A%84-tree-shaking-ad39e185f284

comminicate

If you have dreams and dry goods, search [Moving the World] attention to this brush bowl wisdom who is still washing dishes in the early morning.

This article has been included in GitHub https://github.com/qq449245884/xiaozhi . There are complete test sites, materials and my series of articles for interviews with first-tier manufacturers.


王大冶
68.1k 声望105k 粉丝