## 背景 先来讲下本篇文章的背景,我在自己搭建脚手架的时候,使用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 官方文档