zoukankan      html  css  js  c++  java
  • 深入研究webpack之Tree Shaking相关属性sideEffects用处

    Tree Shaking我原来也只是了解,这次碰巧深入研究了下,就写个博客记录一下,网上有很多讲Tree Shaking的,我写的这篇跟他们侧重点不一样

    Tree Shaking相关的基础知识

    1 webpack会从入口文件开始不断的获取你的依赖,就像一颗树一样从根节点开始不断往下延伸,只有被依赖的文件才会加入树,注意这不叫Tree Shaking,Tree Shaking是指依赖的文件只需要的一部分,则把不需要的部分代码摇掉

    2 Tree Shaking只能识别es6语法,这点很关键(注意去掉polyfill的模块降级),但是webpack不支持es6打包,也就是说你用import写的代码可以被Tree Shaking,但是你npm别人的库,如果别人不是es写法,那么无法Tree Shaking。比如lodash和lodash-es,后者是es的导入写法,代码就可以被压缩。

    3 Tree Shaking原来是用uglifyjs来做压缩的,现在由于现在不维护uglify-es了(uglify-es is no longer maintained ),现在改用terser了,据说是uglify的一个分支。(对我们使用来说其实没什么感觉,只是了解一下)

    4 什么是副作用,之前看别人的文章看到懵懵的,后面终于理解了,其实很简单
    index.js 如下,就是导入了util.js

    import './vendor/util'   
    

    vendor/util.js 如下,里面有做全局的修改或者console.log什么东西,我这里就是给全局的window加了个属性a,没有导出东西来,却使用了这个js文件,这就是副作用

    // vendor/util.js
    export function a() {
      return 'this is function "a"';
    }
    
    export function b() {
      return 'this is function "b"';
    }
    
    export function c() {
      return 'this is function "c"';
    }
    window.a = 43
    

    有时候我们写代码用这种写法,由于里面没有导入东西进来,webpack准确说是terser就不知道你到底要不要这个东西,万一里面有修改全局的操作你把它丢了肯定不行,如果不丢那你就要去读一遍文件才知道到底有没有副作用,官方文档说是非常耗时且因为js是动态语言所以是非常不可靠的操作,我这里仅仅是写的非常简单,工作中可能业务变得更加复杂。

    Tree Shaking的基础了解完了,接下来讲下我读webpack文档的一些见解

    先发2篇我读过的关于Tree Shaking较好的文章
    webpack官网讲解Tree Shaking的文档:https://webpack.js.org/guides/tree-shaking/#root
    你的Tree-Shaking并没什么卵用:https://segmentfault.com/a/1190000012794598

    根据‘你的Tree-Shaking并没什么卵用’ 这篇文章说UglifyJS完全不能识别副作用,但是我自己做了一些测试发现,目前的webpack4.40.2是可以识别大部分副作用的。
    然后讲下官网的文档,之前说了terser识别副作用特别的耗时且不准确(官方举例是react的hoc无法识别副作用),如果你能指定你的哪些文件有副作用或者所有文件都没有副作用那就皆大欢喜了,于是在package.json里出了一个属性sideEffects

    接下来我做了一些测试关于sideEffects属性,注意terser的Tree Shaking只在生产环境webpack会给你调用来压缩代码,dev是不会压缩代码自然不会Tree Shaking的

    第一种情况,index和util都不变,sideEffects:false,指定所有的文件都没有副作用
    结果是terser完全不去管你这个文件里面写的啥,就是说你给window加个属性a没有执行

    第二种情况,index和util都不变,sideEffects:["./src/vendor/util.js"],指定util是有副作用
    结果terser读了util,知道了你做了什么处理,于是window加个属性a成功执行

    第三种情况,index和util都不变,不加sideEffects,不告诉terser哪些有副作用,叫它自己每个引用了的文件都去看下代码
    结果terser读了util,知道了你做了什么处理,于是window加个属性a成功执行

    第四种情况,index变成如下代码

    import { a } from './vendor/util'
    

    结果和index使用import './vendor/util'的每种情况一样,也就是说你导入了a但是没有使用,在terser看来就是import './vendor/util'差不多

    第五种情况
    index变成如下代码

    import { a } from './vendor/util'
    console.log(a())
    

    结果无论sideEffects怎么设置,window加个属性a都会成功

    通过几次测试下来发现sideEffects属性只是针对你从文件导入了方法却没有使用(或者你压根没有导入方法)的情况生效,从这么看来sideEffects属性其实能做的优化不大,而且只是针对打包速度方面的优化(包已经打好了,访问速度跟它没有关系了),而且很坑,一个前端项目如果不只你一个人参与,你偷偷加个sideEffects属性,然后代码没压缩在dev跑的好好的,放到生产环境突然就失效了,假设人家不知道sideEffects,那抓破脑袋也不知道是咋回事(如果你就是想坑你同事,那你就可以happy了~)

  • 相关阅读:
    PHP实现4种排序算法
    PHP反射获取当前函数的内容
    PHP递归目录的5种方法
    生成随机数组
    empty、isset、is_null的比较
    PHP哈希表碰撞攻击
    XMLHttpRequest的跨域请求
    CI框架SESSION重写
    PHP开发第一个扩展
    PHP面试题集之基础题
  • 原文地址:https://www.cnblogs.com/wzcsqaws/p/11571945.html
Copyright © 2011-2022 走看看