zhiqiang21 / blog

记录前端开发日常点滴。为梦想Coding...

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

由浅入深理解Babel_20200903

zhiqiang21 opened this issue · comments

背景:

客服:“xxx页面在用户的手机上白屏了!!!”
前端:“我靠,当时是经过测试上线的啊,而且ios和安卓都找了多个不同的机型机型测试了!!,肯定不是前端的问题...”
BOSS:“快点看看啥问题,有客户进线投诉了”
前端:“知道用户什么手机型号,系统版本是多少么?”
....

上面的对话是我的工作中经常遇到的一种。当面对前线反馈的H5页面“白屏”问题,通常第一时间能够想到的方法就是找到同型号的手机去复现定位问题。


对于前端来说,大多数时间都是花费在了定位问题上,解决问题可能真的只需要2分钟

VueReact 普及的情况下,ES6 也在被广大的开发者使用。在使用Babel编译我们的源码为生产环境代码的时候,阅读Babel文档时,应该都会遇到过下面的问题:

QQ20200724-161659.png

使用Babel困难的原因主要有两个:

  • 同时在维护多个项目,每个项目Babel版本和配置不统一;
  • Babel自身发版较快,网上搜到的中文文档也是不同英文水平的人翻译的。英文版不多读几遍,同时使用代码编译看产出结果 ,很难理解相关配置的作用。

这里的第一篇文章主要为大家介绍我们开发过程中最经常用到的配置的,以及这些配置的详解,对我们生产环境代码的影响。

本片文章所有配置都以 Babel7 官方文档为准。

1.Babel插件的作用

在我们ES6写代码的时候,肯定会见过下面这几个东西。

  • stage-0
  • stage-1
  • stage-2
  • stage-3
  • stage-4

ES6 不同阶段的提案,越往后就越有可能成为规范的一部分。成为规范意味着:这些语法将在浏览器厂商某个将来的版本中默认支持
当提案成为标准规范。随着浏览器的更新默认支持了新语法。某些插件对我们的Babel已经是多余的了。而且随着提案在更新,当我们要使用新规范就得在我们的配置里面去添加更多的插件。

1.1单独添加插件带来的影响:

  • 加载的插件越来越多,编译速度会越来越慢(反正大家都在说babel编译速度慢);
  • 随着用户浏览器的升级,对ECMA规范的支持逐步完善,编译至低版本规范的必要性在减少(比如ES6 -> ES5),多余的转换不单降低执行效率,还浪费带宽。

我们能不能根据用户的需求或者还是配置自动加载需要用到的插件呢?

在以上需求背景下 bable-preset-env 应运而生了:babel根据用户自己配置的环境自动去加载编译插件。比如node、浏览器环境等。

浏览器环境配置有三种方式:

第一、是直接写在.babelrc文件里面:

{
  "presets": [
    ["env", {
      "modules": false,
      // 卸载bablerc配置文件中使用targets指定
      "targets": {
        "browsers": [
            "> 1%",
            "last 2 versions",
            "iOS >= 6.0",
            "not ie > 0",
            "not ie_mob  > 0",
            "not dead"
        ]
      }
    }],
    "stage-2"
  ],
  "plugins": [
    ["transform-runtime"]
  ]
}

第二、是写在package.json文件里面:

// 写在package.json文件中使用browserslist 指定
"browserslist": [
    "last 2 versions",
    "> 1%",
    "iOS >= 7",
    "not ie > 0",
    "not ie_mob  > 0",
    "not dead"
  ],
"dependencies": {}

第三、就是写在babel-loader的配置里面

{
    loader: 'babel-loader',
    options: {
        presets: [
            ["@babel/env", {
              "modules": false,
              "useBuiltIns": "usage",
              "corejs": 3,
              "targets": {
                "browsers": [
                    "> 1%",
                    "last 2 versions",
                    "iOS >= 6.0",
                    "not ie > 0",
                    "not ie_mob  > 0",
                    "not dead"
                ]
              }
            }]
          ],
        plugins: [
            ["@babel/plugin-transform-runtime"]
        ]
    }
}

2. browserslist配置详解

上小结提到对于指定兼容浏览器环境配置有三种写法。最推荐的就是写在package.json里面。比如在开发过程中也会用到scssstyluspostcss等预编译工具,都会用到一个autoprefix插件。这个插件可以给我们使用的css3属性添加浏览器厂商前缀。如果写在package.json里面 js 代码和 css的代码可以使用一份配置保持一致性。

因为 postcssbabel-preset-envautoprefix都是用了同一个node_modules browserslist包来加载浏览器配置.具体的配置规则可以参考下面的文档:

https://github.com/browserslist/browserslist

那么 browserslist 加载浏览器环境配置插件是不是有优先级呢?根据源码中的描述:

https://github.com/browserslist/browserslist/blob/master/node.js#L301

读取浏览器环境配置的顺序如下,如果你同时配置了多个浏览器配置,插件在编译时会提示你“有多个浏览器环境配置文件”的报错提示。

image.png

有配置了browserslist,那么babel怎么做到根据配置的浏览器列表对 JS 语法进行转换,对API进行polyfill呢?