有意思的webpack——tree-shaking

what

首先,咱们来看一张图。(很形象,借用别处)css

如图所示,咱们的js文件就至关于这棵树,tree-shaking就至关对摇动这个操做,目的是让枯黄的叶子和坏掉的苹果掉下来。说到这里,tree-shaking的原理就是,经过摇动咱们的js文件,剔除掉DCE(Dead Code Elimination)。是一种优化性能的方式。前端

why

具体说,每个webpack项目中,都有一个入口,至关于树的主干,依赖了不少模块,至关于树枝。在咱们的实际使用的过程当中,咱们其实只是使用了模块里的某个方法,咱们须要把不使用的树枝给摇落下来,也就是过滤掉这些无用的代码。起到性能优化的目的。webpack

用到这一方法的工具备rollUp,webpack,cc。该文章只介绍webpack中tree-shaking的使用。web

原理

tree-shaking的本质是消除无用代码。无用代码也就是所谓的dead code elimination。json

function test(){
        const a = 1;
        return a+1;
        // dce 不会被执行的代码
        const b = 2; 
        return b;
    }
    test();
复制代码
function test(){
        const a = 1;
        if(false){
           .... 
        }
        const b = 2;
        return b;
    }
    test();
复制代码

什么是Dead Code Elimination?

  • 不会被执行的代码。
  • 代码执行的结果不会被用到。
  • 代码只写不读。

传统的编译型语言中,都是将DCE从AST(抽象语法树)中删除掉。那JavaScript是怎么作到呢?性能优化

JavaScript怎么剔除DCE的呢?

webapck的DCE是uglify作的,你可能会问,那tree-shaking 是作什么呢?tree-shaking只是帮助DCE。打个比方,就好像咱们要从一堆水果里面,拿掉苹果。首先咱们得把苹果选出来。tree-shaking就是一个选苹果的过程。可是拿掉苹果是选出来以后的操做。bash

实践

目录结构: babel

// ./src/index.js

import printMe from "./print.js"; // unused
import { cube } from './math.js';
import menu from './menu.js'; // unused
import './styles.css';
// if(process.env.NODE_ENV !== 'production'){
//   console.log('development mode!')
// }
function component(){
  var element = document.createElement('pre');
  element.innerHTML = [
    'hello webpack',
    '5 cubed is equal to ' + cube(5)
  ].join('\n\n')

  return element;
}
document.body.appendChild(component());
复制代码

mode='development'

webpack的mode='development'会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。app

打包结果:ide

虽然标识出来是不被用到的,可是依然打进去了。

mode='production'

mode='production'会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin.

打包结果:

在production的时候,这些都被过滤掉了。达到了咱们去除dead code的目的。

使用注意事项

先思考一个问题,为何tree-shaking是最近几年流行起来了?而前端模块化概念已经有不少年历史了,其实tree-shaking的消除原理是依赖于ES6的模块特性。

require能够吗?

// import _ from "lodash";
import printMe from "./print.js";
import { cube } from './math.js';
// import menu from './menu.js';
const menu = require('./menu.js');
import './styles.css';
.....

复制代码

production模式下,require的也被打进去了。因此require这种动态引入的是不行的。require须要js执行的时候才知道。import是属于静态引入。

借用官网注意事项:

  • 使用ES2015模块语法(即import和export)。
  • 在项目 package.json 文件中,添加一个 "sideEffects" 属性。(这个是告诉webpack能够过滤掉无用的代码,也能够根据条件设置对应的文件)
  • 确保没有 compiler 将 ES2015 模块语法转换为 CommonJS 模块(这也是流行的 Babel preset 中 @babel/preset-env 的默认行为 )
  • 经过将 mode 选项设置为 production,启用 minification(代码压缩) 和 tree shaking。
相关文章
相关标签/搜索