Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

babel7的配置与优化。 #13

Open
sl1673495 opened this issue Mar 15, 2019 · 6 comments
Open

babel7的配置与优化。 #13

sl1673495 opened this issue Mar 15, 2019 · 6 comments

Comments

@sl1673495
Copy link
Owner

sl1673495 commented Mar 15, 2019

网上关于babel7的文章很多,但是大多都没有实践,很多讲的模棱两可。
本文将手把手的带你看各种配置下的输入输出转换,彻底让你了解babel7到底该怎么去配置和优化。

首先我们知道进入了babel7的时代,stage-0这种已经作为不推荐使用的present了,最流行的应该是@babel/present-env 顾名思义让babel拥有根据你的环境来编译不同代码的需求。

targets

我们先配置最基础的.babelrc配置

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "chrome": "58",
          "ie": "10"
        }
      },
    ]
  ],
}

targets配置的意思就是让babel根据你写入的兼容平台来做代码转换,这里我们指定ie10为我们要兼容的最低版本,来看下面es6代码的输出。

输入: src/main.js

const a = () => {}

输出: dist/main.js

var a = function a() {};

这里因为ie10是不支持es6语法的,所以代码被全部转换,如果我们把ie10这条去掉,因为高版本的chrome是支持es6大部分语法的,所以代码就不会被做任何转换了。

browserlist 这里是具体的可配置列表,可以根据你自己项目的兼容性要求来配置。

useBuiltIns

首先我们来看一行简单的代码

a.includes(1);

includes作为数组的实例方法,在某些浏览器其实是不支持的,babel默认的转换对于这种场景并不会做处理,同样不会处理的包括WeakMap, WeakSet, Promise等es6新引入的类,所以我们需要babel-polyfill为我们这些实例方法等等打上补丁。

在很多项目中我们会看到项目的main.js入口顶部require了babel-polyfill包, 或者指定webpack的entry为数组,第一项引入babel-polyfill包,这样的确没问题而且很保险,但是很多场景下我们可能只是使用了少量需要polyfill的api,这个时候全量引入这个包就显得很不划算,babel给我们提供了很好的解决方案,那就是useBuiltIns 这个配置,下面来看实例。

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "targets": {
          "chrome": "58",
          "ie": "10"
        }
      },
    ]
  ],
}

输入: src/main.js

a.includes(1)
Promise.reject()

输出: dist/main.js

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

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

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

a.includes(1);
Promise.reject();

babel帮我们做好了代码分析,在需要用到polyfill的地方再帮你引入这个单独的补丁,这样就实现了按需引入~

@babel/plugin-transform-runtime

这个插件是帮我们把一些babel的辅助方法由直接写入代码专为按需引入模块的方式引用,
我们先来看不使用这个插件时候,我们对于es6 class的转换。

输入: src/main.js

class A {}

输出: dist/main.js

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var A = function A() {
  _classCallCheck(this, A);
};

看似没问题,转换的很好,但是如果在很多模块都用了class语法的情况下呢?辅助函数_classCallCheck就会被重复写入多次,占用无意义的空间。
解决方法就是引入@babel/plugin-transform-runtime
.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "targets": {
          "chrome": "58",
          "ie": "10"
        }
      },
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime",
  ]
}

输入: src/main.js

class A {}

输出: dist/main.js

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var A = function A() {
  (0, _classCallCheck2.default)(this, A);
};

这样就解决了辅助函数重复写入的问题了。

总结

babel7的版本下,利用present-env做按需转换,利用useBuiltIn做babel-polyfill的按需引入,利用transform-runtime做babel辅助函数的按需引入。

@webgzh907247189
Copy link

webgzh907247189 commented Sep 26, 2019

useBuiltIns 的usage 和 entry 有什么区别???

usage 看明白了
entry ,貌似要先引入@babel/polyfill ,然后内部进行按需引入,是这样吗
应该还要配置一个corejs 版本,不然有些最新的特性语法,无法编译出来。像flat

@CommanderXL
Copy link

@webgzh907247189 使用 entry 的配置项的话需要在代码里面手动引入 @babel/polyfill ,这样通过babel 编译后的代码会将所有的 polyfill 都引入到你的编译后的代码里面去。这里也可以参考下[email protected]文档里面有关 babel 的 useBuiltIns 的说明

@webgzh907247189
Copy link

webgzh907247189 commented Sep 28, 2019

@CommanderXL 感谢你的回答。。大佬能否看下https://github.com/webgzh907247189/designPattern/blob/master/babel/index.js
为何我测试用了require('@babel/polyfill') 但是最终输出没有引用。十分感谢

@CommanderXL
Copy link

@webgzh907247189 额,你是在node环境下去运行代码的。@babel/polyfill里面涉及到的东西没必要输入到你的代码里面了。直接作为一个package来使用就好了。

一般在web环境下,代码需要编译,肯定不能在本地直接引入package,那么这个时候就需要把@babel/polyfill所提供的polyfills打包到最后需要编译输出的代码。

可以见我写的demo

@tulies
Copy link

tulies commented Oct 21, 2019

想问一下,用了@babel/plugin-transform-runtime和@babel/runtime,在@babel/preset-env中还需要配置useBuiltIns和corejs吗。。 我整的一脸懵逼,没有做到提取代码,减少代码体积。

@CommanderXL
Copy link

@tulies 这个得看你具体运用的场景了。比如你是使用babel编译一个工程应用项目,用 @babel/preset-env + useBuiltIns: 'entry' + browserlist 的方式基本上就可以 cover 住你项目的代码所运行的场景了。但是如果你是需要使用 babel 去构建一个 library 的话,就用 @babel/plugin-transform-runtime 这种方式。这块具体的内容可以参加 babel 的官方文档上的说明。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants