1. webpack-demo
  2. |- package.json
  3. |- webpack.config.js
  4. |- server.js
  5. |- DEV-server.js
  6. |- /dist
  7. |- /src
  8. |- data.xml
  9. |- icon.png+
  10. |- style.css
  11. |- my-font.woff
  12. |- my-font.woff2
  13. |- print.js
  14. |- index.js
  15. + |- math.js
  16. |- /node_modules
  1. // math.js
  2. export function square(x) {
  3. return x * x;
  4. }
  5. export function cube(x) {
  6. return x * x * x;
  7. }
  1. // index.js
  2. import _ from 'lodash';
  3. import './style.css';
  4. import Icon from './icon.svg';
  5. import Data from './data.xml';
  6. import printMe from './print.js';
  7. import { cube } from './math.js';
  8. function componentPre() {
  9. let element = document.createElement('pre');
  10. element.innerHTML = [
  11. 'Hello webpack!',
  12. '5 cubed is equal to ' + cube(5)
  13. ].join('\n\n');
  14. element.classList.add('hello');
  15. var myIcon = new Image();
  16. myIcon.src = Icon;
  17. element.appendChild(myIcon);
  18. var btn = document.createElement('button');
  19. btn.innerHTML = 'Click me and check the console!';
  20. btn.onclick = printMe;
  21. element.appendChild(btn);
  22. console.log(Data);
  23. return element;
  24. }
  25. function component() {
  26. let element = document.createElement('div');
  27. element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  28. element.classList.add('hello');
  29. var myIcon = new Image();
  30. myIcon.src = Icon;
  31. element.appendChild(myIcon);
  32. var btn = document.createElement('button');
  33. btn.innerHTML = 'Click me and check the console!';
  34. btn.onclick = printMe;
  35. element.appendChild(btn);
  36. console.log(Data);
  37. return element;
  38. }
  39. // document.body.appendChild(component());
  40. let element = componentPre(); // Store the element to re-render on print.js changes
  41. document.body.appendChild(element);
  42. if (module.hot) {
  43. module.hot.accept('./print.js', function () {
  44. console.log('Accepting the updated printMe module!');
  45. document.body.removeChild(element);
  46. element = componentPre(); // Re-render the "component" to update the click handler
  47. document.body.appendChild(element);
  48. })
  49. }

Tree Shaking

webpack 设置 tree shaking 需要在package.json 加上 sideEffects: false 这个,指明无副作用,
还需要设置 webpack.config.js 设置 mode: ‘production’

实验,实际 package.json 加上 sideEffects: false,并没有什么卵用,只要设置 mode: ‘production’ 就会做tree shaking,但是有多少效果就不清楚了。

在使用 tree shaking 时必须有 ModuleConcatenationPlugin 的支持,您可以通过设置配置项 mode: “production” 以启用它。如果您没有如此做,请记得手动引入 ModuleConcatenationPlugin

  1. {
  2. "name": "webpackDemo",
  3. "sideEffects": false,
  4. "version": "1.0.0",
  5. "description": "",
  6. "private": true,
  7. "main": "index.js",
  8. "scripts": {
  9. "test": "echo \"Error: no test specified\" && exit 1",
  10. "watch": "webpack --watch",
  11. "build": "webpack",
  12. "start": "webpack-dev-server --open",
  13. "server": "node server.js"
  14. },
  15. }

请注意,任何导入的文件都会受到树抖动的影响。这意味着如果您css-loader在项目中使用类似的东西并导入CSS文件,则需要将其添加到副作用列表中,以便在生产模式下不会无意中将其删除:

  1. // package.json
  2. {
  3. "name": "webpackDemo",
  4. "sideEffects": [ // 有一些内容虽然没有被使用,但是可能是关联性,所以不能被优化掉。
  5. "./src/some-side-effectful-file.js",
  6. "*.css"
  7. ],
  8. "version": "1.0.0",
  9. "description": "",
  10. "private": true,
  11. "main": "index.js",
  12. "scripts": {
  13. "test": "echo \"Error: no test specified\" && exit 1",
  14. "watch": "webpack --watch",
  15. "build": "webpack",
  16. "start": "webpack-dev-server --open",
  17. "server": "node server.js"
  18. },
  19. }

mode: ‘production’,可以将环境切换为生产环境,代码会自动被压缩打包。

  1. optimization: {
  2. usedExports: true // 标记去掉未使用方法
  3. },

所以,我们所学到的是,为了利用树木摇晃,你必须……

  • 使用ES2015模块语法(即importexport)。
  • 确保没有编译器将您的ES2015模块语法转换为CommonJS模块(这是流行的Babel预设@ babel / preset-env的默认行为 - 有关详细信息,请参阅文档)。
  • "sideEffects"属性添加到项目的package.json文件中。
  • 使用配置选项可启用各种优化,包括缩小和树抖动。production mode

您可以将您的应用程序想象成一棵树。您实际使用的源代码和库代表树的绿色活树。死码代表秋天消耗的棕色枯叶。为了摆脱枯叶,你必须摇动树,使它们掉下来。

解释 tree shaking 和 sideEffects

sideEffectsusedExports(更多被认为是 tree shaking)是两种不同的优化方式。
sideEffects 更为有效 是因为它允许跳过整个模块/文件和整个文件子树。
usedExports 依赖于 terser 去检测语句中的副作用。它是一个 JavaScript 任务而且没有像 sideEffects 一样简单直接。而且它不能跳转子树/依赖由于细则中说副作用需要被评估。尽管导出函数能运作如常,但 React 框架的高阶函数(HOC)在这种情况下是会出问题的。