tree shaking

## 背景
先来讲下本篇文章的背景,我在自己搭建脚手架的时候,使用css-loader 和 style-loader 处理样式,打包后,插入 style 的代码可以在打包后的js文件中找到,但是html文件中插入style标签的代码并没有生效,相应的,我的css代码也并没有生效
## 原因
后来查了一下,因为我设置的模式(mode)是production,在webpack4.0以后,production模式下是自动开启tree shacking 的,关于tree shacking 对css的处理,可以参考官方文档的一段话(v 4.42.1)

> 注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
```
{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}
```

## Tree  Shacking 的一些概念


### Tree  Shacking是什么

顾名思义,摇树,你可以将应用程序想象成一棵树。绿色表示实际用到的源码和 library,是树上活的树叶。灰色表示无用的代码,是秋天树上枯萎的树叶。为了除去死去的树叶,你必须摇动这棵树,使它们落下。
tree shaking 就是这样一个术语,用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。

- 在不使用 Tree Shacking 的情况下,一个文件中,只要有一个方法被使用到了,整个文件都会被打包到bundle中去,使用后,只会把用到的那个方法打包进去
- 依赖于 ES2015 模块系统中的静态结构特性,只有使用ES6的语法才支持

### Tree Shacking 机制

首先了解一个概念,DCE(dead-code elimination),无用代码擦除,如以下几种代码:

- 代码不可到达,永远不会被执行 
- 代码执行的结果不会被用到
- 代码只会影响到死变量(只写不读)
- ...

识别无用代码是利用的ES6模块的特点:

- (import时)只能作为模块顶层的语句出现
-  import的模块名只能是字符串常量
-  import binding是无法擦除的


识别出后,使用 uglifyjs 压缩插件在压缩阶段 在 bundle 中删除它们。


### 副作用

在纯ES6代码中,我们做到这些是很容易的,然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。

> 所谓纯粹部分,是与副作用代码相对,副作用这个概念来源于函数式编程(FP),纯函数是没有副作用的,也不依赖外界环境或者改变外界环境。纯函数的概念是:接受相同的输入,任何情况下输出都是一样的。

> 非纯函数存在副作用,副作用就是:相同的输入,输出不一定相同(像是http请求函数)。或者这个函数会影响到外部变量、外部环境。

> 函数如果调用了全局对象或者改变函数外部变量,则说明这个函数有副作用。

> 在webpack的官方解释是:

> 「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。


有多种方法可以设置让一些文件避免Tree  Shacking 的影响

1、通过 package.json 的 "sideEffects" 属性来实现

```
{
  "name": "your-project",
  "sideEffects": false
}

```

如同上面提到的,如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack,它可以安全地删除未用到的 export 导出,默认是这样设置的。

如果你的代码确实有一些副作用,那么可以改为提供一个数组:

```
{
  "name": "your-project",
  "sideEffects": [ // 标记为有副作用
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}
```

方法二:

```
rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
                sideEffects: true // 标记为有副作用
           },
      ],

```


还有其他通过插件标记的,感兴趣的可以了解一下

 

 

参考文档: tree shaking 官方文档

posted @ 2020-05-06 12:00  九萌萌  阅读(301)  评论(0编辑  收藏  举报