聊一聊Babel7.x+Webpack(babel7.4+的使用感受

Babel

它是一个编译器可以让你使用最新版本的ES规范比如ES2015(ES6),ES2016(ES7),ES2017(ES8)的写法并把它编译成老的ES5的写法。

首先babel的转换其实做了两件事情

  • 语法转换
let array = [1, 2, 3, 4, 5, 6];
array.includes(item => item > 2);
----------------------------> 转换后

var array = [1, 2, 3, 4, 5, 6];
array.includes(function (item) {
  return item > 2;
}); 
  • 新API的polyfill兼容
let array = [1, 2, 3, 4, 5, 6];
array.includes(item => item > 2);
new Promise()

async function a(){
    console.log(1);
}


--------------------------->转换后
"use strict";

require("regenerator-runtime/runtime");

require("core-js/modules/es6.promise");

require("core-js/modules/es6.object.to-string");

require("core-js/modules/es7.array.includes");

var array = [1, 2, 3, 4, 5, 6];
array.includes(function (item) {
  return item > 2;
});
new Promise();

function a() {
  return regeneratorRuntime.async(function a$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          console.log(1);

        case 1:
        case "end":
          return _context.stop();
      }
    }
  });
}

但是但是,"平平无奇"的babel本身只会转义语法,但是我们还想用Promise,Object.assign等等。所以就会有这么大一堆不明所以的东西

@babel/polyfill,@babel/preset-env,@babel/plugin-transform-runtime,@babel/runtime

@babel/polyfill

很容易理解,它就是各种API垫片,只要在主入口引用import '@babel/polyfill',就能完美使用各种新的API,完全没有任何需要配置的地方。

但是但是,这样就是把整个第三方垫片引入,打包出来会非常的大。所以就用到接下来的@babel/preset-env

@babel/preset-env

@babel/preset-env 主要干的事情呢,根据你的设置表示你要啥,它就给你啥,不多给也不少给。
使用@babel/preset-env最主要的配置字段就是useBuiltInstarget

//babel.config.js
const presets = [
  [
    "@babel/env",
    {
      targets: {
        "browsers": ["> 1%", "last 2 versions", "not ie 
<h4>target</h4>
<p>target表示所以编译的代码运行的环境,可以是浏览器,可以是node,只要设置相应的字段,它就能根据规则插入和转义相应的语法跟API</p>
<p>例如以下的<code> "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]</code>表示兼容市场占有率>1%,浏览器的最新两个版本,ie8以下不兼容</p>
<h4>useBuiltIns</h4>
<p>useBuiltIns有三种取值,不同的取值会影响API的导入方式</p>
<ul>
<li>false<p>就是不用polyfill,如果在业务入口 <code>import '@babel/polyfill'</code>, 会无视 .browserslist 将所有的 polyfill 加载进来。</p>
</li>
<li>entry<p>需要手动<code>import '@babel/polyfill'</code>,它会根据<code>targets</code>中的配置来过滤出polyfill</p>
</li>
<li>usage<p>不需要手动<code>import '@babel/polyfill'</code>(加上也无妨,编译时会自动去掉), 且它会根据<code>targets</code>中的配置来过滤出polyfill + <strong>业务代码使用到的新 API 按需进行 polyfill。</strong></p>
<p>useage并不会对第三方包做检测,所以如果某些第三包使用高级的API那么在低版本的浏览器上也是会报错的,例如:<code>Array.from</code></p>
</li>
</ul>
<p><strong>基本上的开发使用<code>@babel/preset-env</code>+<code>@babel/polyfill</code>已经完全很完美了</strong></p>
<p><strong>但是以上看起来好完美,但是还有一个巨大问题!!!</strong></p>

"use strict";

require("regenerator-runtime/runtime");

require("core-js/modules/es6.promise");

require("core-js/modules/es6.object.to-string");

require("core-js/modules/es7.array.includes");

var array = [1, 2, 3, 4, 5, 6]; array.includes(function (item) { return item > 2; }); new Promise();

function a() { return regeneratorRuntime.async(function a$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: console.log(1);

    case 1:
    case "end":
      return _context.stop();
  }
}

}); }


<p>以上所有的垫片的导入都是直接挂载在<strong>全局对象</strong>上的,对于写业务API的时候这样并不影响使用,但是如果对于开发第三方包的情况,<strong>babel-polyfill 会污染全局变量,给很多类的原型链上都作了修改</strong>,这种情况就会变得非常不可控。</p>
<h4>@babel/plugin-transform-runtime和@babel/runtime 让Babel在更进一步</h4>
<p>更改babel配置</p>

const presets = [ [ "@babel/env", { targets: { "browsers": ["> 1%", "last 2 versions", "not ie

其中的corejs参数有坑,后面说!

我们在来看看打包结果

"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");

var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));

var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));

// import "@babel/polyfill"
var array = [1, 2, 3, 4, 5, 6];
array.includes(function (item) {
  return item > 2;
});
new _promise.default();

function a() {
  return _regenerator.default.async(function a$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          console.log(1);

        case 1:
        case "end":
          return _context.stop();
      }
    }
  });
}

是不是很神奇所有的新api都包裹在一个对象里,没有去污染全局变量。

soga,既然这么神奇,为嘛不直接一步到位用这种方法呢?

我们仔细一点看的话,发现下面的代码并没有被转化,这就是babel/plugin-transform-runtime的缺点了,它并没有去转义实例新API的方法,如果在代码里使用到了新API的实例方法,这里是会跪的。

var array = [1, 2, 3, 4, 5, 6];
array.includes(function (item) {
  return item > 2;
});

还需要留意的一点,在package.json下@babel/plugin-transform-runtime是在devDependencies,@babel/runtime是在dependencies下(因为里面都是转化的API垫片)

  "devDependencies": {
    "@babel/plugin-transform-runtime": "^7.7.6",
  },
  "dependencies": {
    "@babel/runtime": "^7.7.6"
  }

@babel/runtime内部集成了

  • core-js

    转换一些内置类 (Promise, Symbols等等) 和静态方法 (Array.from 等)。绝大部分转换是这里做的。自动引入

  • regenerator

    作为 core-js 的拾遗补漏,主要是 generator/yield 和 async/await 两组的支持。当代码中有使用 generators/async 时自动引入。

最后大杀器,无敌巨坑:corejs3

我们应该经常在其他文档和使用说明中看到 runtime 不支持实例方法,确实在之前的使用中,无论是 Babel 7.0.0 ~ 7.4.0 抑或 Babel < 7.0.0, 对此都无能为力。只能通过配置 corejs (可选 false | 2)来决定是否使用 babel/runtime-corejs 替代core-js 抑或 polyfill (可选 true | false)来决定是否全局引入新的内置函数(new built-ins),然而其实这两者并没有根本改变, corejs: 2 实际上等同于 7.0.0 版本之前的 polyfill: true。
重点: 真正的改变出现在 Babel 7.4.0 之后,你可以选择引入 @babel/runtime-corejs3,设置 corejs: 3 来帮助您实现对实例方法的支持。

如果在Babel 7.4之后的版本,更改配置corejs : 3

const plugins = [
  [
    "@babel/plugin-transform-runtime",
    {
      "corejs": 3,   //"corejs": false // 可选 false | 2 | 3
      "helpers": true,
      "regenerator": true,
      "useESModules": false
    }
  ]
]

module.exports = { presets,plugins };

在看转化结果

var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));

var array = [1, 2, 3, 4, 5, 6];
(0, _includes.default)(array).call(array, function (item) {
  return item > 2;
});

它连实例API都转了,(早干嘛去了,前端ER真的学不动了!!!!

最后附上Webpack版本Babel配置

``` { "presets": [ [ "@babel/preset-env", targets: { "browsers": ["> 1%", "last 2 versions", "not ie

原文链接:segmentfault.com

上一篇:构造函数与class实现类的区别,以及ES5实现ES6的class关键字
下一篇:Nodejs - 在阿里云轻量服务器上部署Node环境

相关推荐

  • 🚀webpack 4 beta — try it today!🚀

    Now that webpack is a #0CJS (Zero Configuration) out-of-the-box bundler, we will lay groundwork in 4...

    3 年前
  • 🔥一步一步的带你走进Webpack4的世界

    前言 webpack是当下最热门的前端资源模块化管理和打包工具,它可以将许多松散的模块按照依赖和规则打包成符号生产环境部署的前端资源,还可以将按需加载的模块进行代码分割。

    8 个月前
  • (独家!)webpack 5 changelog 全文翻译

    ★ webpack 团队于北京时间 10 月 12 日凌晨发布了 v5.0.0-beta.0 版本,本文译自 webpack/changelog-v5。此部分主要面向非插件开发的 webpack 使...

    1 年前
  • 面试必备!webpack 中那些最易混淆的 5 个知识点

    前两天为了优化公司的代码打包项目,恶补了很多 webpack4 的知识。要是放在几年前让我学习 webpack 我肯定是拒绝的,之前看过 webpack 的旧文档,比我们内部项目的文档还要简陋。

    1 年前
  • 面试官:请手写一个webpack4.0配置

    确认过眼神,你还是没有准备秋招的人?时间仓促。自京东6月8号开启管培生的招聘,就意味着秋招的开始。然而你还在等着秋天的到来?今年形势应该更为严峻,随着各大技术(vue,webpack,react,微信...

    2 年前
  • 面向小白的 webpack 配置

    前几天面试,问到 webpack 的插件。虽然知道,但没有记住名字,在这里写个笔记,用来复习。 const path = require('path') module.exports = { ...

    2 个月前
  • 随着WebPACK定义全局变量

    随着WebPACK定义全局变量 ...

    3 年前
  • 阔别两年,webpack 5 正式发布了!

    HI,继 Vue 3 和 React 17 之后,我又来啦!印记中文已经完成了 webpack v5 中文文档的同步及翻译工作,大家可以无缝进行阅读哦。 文档地址请认准:webpack.docsch...

    9 天前
  • 配置webpack中externals来减少打包后vendor.js的体积

    在日常的项目开发中,我们会用到各种第三方库来提高效率,但随之带来的问题就是打包后的vendor.js体积过大,导致加载时空白页时间过长,给用户的体验太差。为此我们需要减少vendor.js的体积,从本...

    2 年前
  • 配置webpack中dev.env.js、prod.env.js,解决不同命令下项目启动和打包到指定的环境

    前后端分离的项目开发中,我们有开发环境、测试环境、预生产环境和生产环境。 1、开发环境下调试接口的时候,一般都会有好几个接口地址(开发服务器上的,本地的,接口开发人员的,七七八八的接口地址),要根据...

    2 年前

官方社区

扫码加入 JavaScript 社区