配置 babel

168 阅读3分钟

1、作用

1、语法转换、插件 preset-env (高级 --> 低级)

2、通过 Polyfill 方式在目标环境中添加缺失的功能(扩展Api)

3、源码转换(模块转化等...)

2、相关模块

@babel/core:核心模块
@babel/preset-env:处理新的语法
  • babel 预设,一组预先设定的插件
    • 只转换语法:箭头函数
    • 不转换全局函数和实例方法:Promise、async-await、Array.from | Array.prototype.includes
    • 由于上一步的缺点,需要引入 polyfill
  • 结合配置项 useBuiltIns 使用,按需引入 polyfill
@babel/polyfill:处理全局函数、新的静态、原型方法
  • 功能垫片
    • a、包含 core-js 和一个自定义的 regenerator runtime 来模拟完整的 ES2015+ 环境
    • b、Promise 和 WeakMap、Array.from、Array.prototype.includes(包含静态方法、原型方法)
    • c、polyfill 将添加到全局范围(glob)和类似 String 这样的原生原型(prototypes)
  • 应用到 "生产环境"
  • 从 Babel 7.4.0 版本开始不建议使用了,建议直接包含 core-js/stable
  • 缺点:
    • a、更改原型
    • b、引入过量的辅助函数
  • 5、由于以上缺点,需要配合 '@babel/plugin-transform-runtime' 使用
@babel/runtime:运行态辅助函数包
  • 运行态 "辅助函数" 的npm包
    • a、转换后的代码上面增加了好几个函数声明,称之为辅助函数
    • b、如果每个文件里都有好多被转换的代码,所有文件都会被注入类似的函数
    • c、@babel/runtime把所有语法转换会用到的辅助函数都集成在了一起
  • 不会污染全局 空间和内置对象原型(按需引用)
    • 使用 async/await 时,自动引入 @babel/runtime/regenerator

    • 使用 ES6 的静态事件或内置对象时,自动引入 @babel/runtime/core-js

    • 移除内联babel helpers并替换使用@babel/runtime/helpers 来替换

@babel/plugin-transform-runtime:包含 @babel/runtime、core-js
  • 自动引入 @babel/runtime 下的辅助函数( @babel/runtime/helpers )
    • 例如使用class类函数:class Person {}
    • a、使用 plugin-transform-runtime
      • var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
      • var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
      • var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
    • b、不使用plugin-transform-runtime,每个文件内都会有此方法
      • function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
      • function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
      • function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  • 当代码里使用了core-js的API
    • 自动引入@babel/runtime-corejs3/core-js-stable/
    • 以此来替代全局引入的core-js/stable;
  • 当代码里使用了Generator/async函数
    • 自动引入@babel/runtime/regenerator
    • 以此来替代全局引入的regenerator-runtime/runtime;
  • 作用2和3其实是在做API转换,对内置对象进行重命名,以防止污染全局环境

3、常用配置

module.exports = {
  presets: [
    [
      // 预设一堆插件:
      '@babel/preset-env',
      {
        // 转码之后,要兼容的浏览器
        targets: {
          chrome: '80',
          ie: '8'
          //   esmodules: true // 表示直接转化为ES6模块规范,而不会转码到require
        },

        // 是否将 ES 模块语法转换为其他模块类型
        // 1、默认为 auto:"amd"、"umd"、"systemjs"、"commonjs"、"cjs"、"auto"、false
        // 2、设置为 false 将保留 ES 模块, require() ==> import ...
        // 3、Es 模块语法可以用来webpack做tree shaking
        modules: false,

        // 1、提供 js 的运行环境:3、2
        // 2、需要结果 core-js@3 插件使用
        corejs: 3,

        // 作用:控制 polyfill 的加载方式
        // 1、默认为false,不加载 polyfill
        // 2、entry:需要手动引入 polyfill 需要的api
        //    1、需要手动引入:require("@babel/polyfill")
        //    2、babel处理后,会引入全部的 polyfill 方法
        //    3、此时版本时 corejs2,如果为 corejs3 会报错
        // 3、usage:自动引入 polyfill 需要的api,window.promise = ...
        //    例如:如果使用到了 Promise 会自动引入下面两个 polyfill
        //    require("core-js/modules/es6.object.to-string.js");
        //    require("core-js/modules/es6.promise.js");
        //    function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
        //    function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
        //    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
        useBuiltIns: 'usage'

        // 设置为true时,它会尽可能的将ES6+代码转化为ES5标准代码
        // loose: true
      }
    ]
  ],
  plugins: [
    [
      // 1、包含 @babel/runtime、core-js
      // 2、动态引入 @babel/runtime 下的辅助函数
      '@babel/plugin-transform-runtime',
      {
        // 需要结合 @babel/runtime-corejs3 插件使用
        // 1、作用2和3其实是在做API转换,对内置对象进行重命名;避免污染全局
        // 2、corejs
        //    不使用时:promise 挂在到window上 require("core-js/modules/es6.promise.js");
        //    使用后:var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
        corejs: {
          version: 3 // 优先级高于,preset-env的corejs
        }
      }
      // {
      //   helpers: true, // 是否要自动引入辅助函数包
      //   corejs: false, // 是否做API转换,即不对Promise这一类的API进行转换。而在开发JS库的时候设置为2或3
      //   regenerator: true, // 是否做API转换,
      //   useESModules: false, // 是否使用ES6的模块化用法
      //   absoluteRuntime: false // 自定义引入@babel/runtime/模块的路径规则,取值是布尔值或字符串
      // }
    ]
  ]
}