Skip to content

192114/babel-lesson

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

babel 在webpack中的配置 文档https://babeljs.io/docs/en/

@babel/preset-env

babel-preset-env 是一系列插件的合集,官方已不用再使用 preset-201x 和 preset-latst 之类的包,env 包可以根据配置自动处理兼容代码

文档https://babeljs.io/docs/en/babel-preset-env

  • targets(针对你的项目指定生成的代码环境,个人喜欢将broswerslist配置在package.config中)
  • loose(松散转换,默认false,推荐false)
  • modules(将es6模块转换成其他模块类型,"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false, defaults to "auto",设置成false不进行转换,推荐设置成false)
  • useBuiltIns(这个选项配置了 @babel/preset-env 如何处理 polyfills,"usage" | "entry" | false, 默认是 false)

    此选项将 core-js 模块直接引用为裸导入。因此,core-js 将相对于文件本身进行解析,并且是可被访问的。如果没有 core-js 依赖项或者有多个版本,您可能需要将 core-js@2 指定为应用程序中的顶级依赖项。

    • useBuiltIns: 'entry'
      • 需要在头部引入 '@babel/polyfill',并且是根据配置环境引入对应的特性。代码中没有用到,但环境中会缺失,也会引入。(只根据 browserslist 配置)

        只需要在你整个 app 中使用 require("@babel/polyfill"); / import '@babel/polyfill' 一次。多次对 @babel/polyfill 的导入会导致全局冲突和其他很难跟踪的错误。我们推荐创建一个单独的文件处理 require 语句。

    • useBuiltIns: 'usage'
      • 无需在头部引入 import '@babel/polyfill',它会自动根据当前的代码引入对应特性,并且只引用代码中用到的特性(browserslist 配置 + 代码用到)

        usage 风险项:由于我们通常会使用很多 npm 的 dependencies 包来进行业务开发,babel 默认是不会检测 依赖包的代码的。也就是说,如果某个 依赖包使用了 Array.from, 但是自己的业务代码没有使用到该API,构建出来的 polyfill 也不会有 Array.from, 如此一来,可能会在某些使用低版本浏览器的用户出现 BUG。所以避免这种情况发生,一般开源的第三方库发布上线的时候都是转换成 ES5 的。

    • useBuiltIns: false
      • 既不会在每个文件中自动添加 polyfill,也不会将 "@babel/polyfill" 导入为单个 polyfill。
  • corejs(决定当前 Babel 使用core-js的版本,有 2 和 3 选项)
    • @babel/polyfill 移除了 polyfill proposals 所以 @babel/polyfill 仅仅是 core-js v2 的别名 因此我们只需要在项目中使用core-js即可

    • 推荐 corejs: 3 + useBuiltIns: 'entry'

      corejs: 2 + useBuiltIns: 'entry'产生警告

      `@babel/polyfill` is deprecated. Please, use required parts of `core-js` and `regenerator-runtime/runtime` separately

@babel/polyfill(截至babel7.4.0,将会被弃用)

文档https://babeljs.io/docs/en/next/babel-polyfill.html

  • 以支持直接导入 core-js/stable(polyfill ECMAScript 特性)和 regenerator-runtime/runtime(需要使用转换后的 generator 函数)

  • babel-polyfill 的存在意义是给浏览器“打补丁”,比如浏览器没有 Object.assign 这个特性,它会针对这个环境创建这个特性。Babel 自身是只转换语法,不添加丢失的特性,polyfill 的存在就是弥补浏览器这部分缺失的特性(比如某些 ie)。

  • 副作用

    • 引入了新的全局对象,比如Promise、WeakMap等。
    • 修改现有的全局对象:比如修改了Array、String的原型链等。

    在应用开发中,上述行为问题不大,基本可控。但如果在库、工具的开发中引入 babel-polyfill,则会带来潜在的问题。 举个例子,在项目中定义了跟规范不一致的Array.from()函数,同时引入了一个库(依赖 babel-polyfill),此时,这个库可能覆盖了自定义的Array.from()函数,导致出错。 这就是 babel-runtime 存在的原因。它将开发者依赖的全局内置对象等,抽取成单独的模块,并通过模块导入的方式引入,避免了对全局作用域的修改(污染)。 因此,如果是开发库、工具,可以考虑使用 babel-runtime。

@babel/runtime

文档https://babeljs.io/docs/en/babel-runtime

  • @babel/runtime 是一个包含 Babel modular runtime helpers 和 一系列 regenerator-runtime 的库。
  • 使用场景
    • 开发库/工具
    • 移除冗余工具函数(helper function)
  • 与 babel-polyfill 的区别在于
    • babel-polyfill 会修改(覆盖)实例方法,这在业务层很有用,但某些场景,比如引用外在的技术库,不希望这里的的 polyfill 覆盖业务代码中的方法
    • babel-runtime 不会修改实例方法,它只是引入一些 helper 函数,创造对应的方法
  • 使用 babel-runtime 一般会搭配 babel-plugin-transform-runtime 使用。babel-plugin-transform-runtime 用于构建过程的代码转换,而 babel-runtime 是实际导入项目代码的功能模块。
  • 与@babel/runtime-corejs2或@babel/runtime-corejs3的区别:
    • 对于任何非实例方法,可以使用它来代替polyfill,它将使用core-js中的库函数替换Promise或Symbol之类的东西

@babel/runtime-corejs2

文档https://babeljs.io/docs/en/babel-runtime-corejs2

@babel/plugin-transform-runtime

文档https://babeljs.io/docs/en/babel-plugin-transform-runtime

  • babel 在每个需要的文件的顶部都会插入一些 helpers 内联代码,这可能会导致多个文件都会有重复的 helpers 代码。@babel/plugin-transform-runtime 的 helpers 选项就可以把这些模块抽离出来。 -@babel/plugin-transform-runtime 主要做了三件事情:core-js aliasing、helper aliasing、regenerator aliasing
    • core-js aliasing:自动导入babel-runtime/core-js,并将全局静态方法、全局内置对象 映射到对应的模块。
    • helper aliasing:将内联的工具函数移除,改成通过babel-runtime/helpers模块进行导入,比如_classCallCheck工具函数。
    • regenerator aliasing:如果你使用了 async/generator 函数,则自动导入 babel-runtime/regenerator模块。
  module.exports = {
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": false, // boolean 或者 number, 默认 false,指定是否需要 runtime 的 corejs aliasing,如果使用 env 的 useBuiltIns + polyfill,使用 false。
                "helpers": true, // boolean, 默认 true,指定是否内联 babel 的 helper 代码 (比如 classCallCheck, extends) 
                "regenerator": false, // 通过 preset-env 已经使用了全局的 regeneratorRuntime, 不再需要 transform-runtime 提供的 不污染全局的 regeneratorRuntime
                "useESModules": true, // boolean, 默认 false,使用 es modules helpers, 减少 commonJS 语法代码
                "absoluteRuntime": false // boolean, 默认 false,是否目录引用 runtime 包(有些项目会引用当前项目之外的代码,编译时会找不到 runtime 包)
            }
        ]
    ]
  }

小总结

  • @babel/core(核心包)
  • @babel/preset-env(预设)
  • @babel/polyfill(v7.4.0似乎被废弃)
  • @babel/runtime(开发业务代码可不用,开发技术库可以使用,提供helpers)
  • @babel/plugin-transform-runtime(合并重复的 helper 函数)
  • @babel/plugin-external-helpers (在使用preset时配置useBuiltIns为usage/entry时使用,不要与plugin-transform-runtime混用)

配置大总结

  • 最新ES 语法:比如,箭头函数
  • 最新ES API:,比如,Promise
  • 最新ES 实例方法:比如,String.protorype.includes

@babel/preset-env + @babel/runtime + @babel/plugin-transform-runtime

  • 开发库/工具
  • 只转译最新ES 语法,比如,箭头函数
  • 比如最新ES API(Promise, Symbol)/最新ES 实例方法(String.protorype.includes)不做转译
  {
    "presets": [
      ["@babel/preset-env", {
        "modules": false,
      }]
    ],
    "plugins": [
      "@babel/plugin-transform-runtime",
    ]
  }

@babel/preset-env + @babel/runtime-corejs2 + @babel/plugin-transform-runtime

  • ES语法、API转换
  • 不支持实例的方法
  • 不污染全局变量

@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime

  • ES语法、API、实例方法都进行转换
  • 适合具体业务场景
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": {
          "version": 3,
          "proposals": true
        },
        "useESModules": true
      }
    ]
  ]
}

@babel/preset-env + corejs3 + @babel/plugin-external-helpers

  • 适合具体的业务场景
  • ES语法、API、实例方法都进行转换
  • 污染全局变量
  {
    "presets": [
      ["@babel/preset-env", {
        "modules": false,
        "useBuiltIns": "entry / usage",
        "corejs": 3,
      }]
    ],
    "plugins": [
      // 如果多个文件都需要helpers,会重复引用这些 helpers,会导致每一个模块都定义一份,代码冗余。所以 babel 提供了这个命令,用于生成一个包含了所有 helpers 的 js 文件,用于直接引用。然后再通过一个 plugin,去检测全局下是否存在这个模块,存在就不需要重新定义了。另外如果使用了 transform-runtime 就不需要了
      "@babel/plugin-external-helpers",
    ]
  }
  • 使用方法
    • 安装 @babel/plugin-external-helpers @babel/cli(babel-external-helpers.js和主babel的cli babel.js)
    • babel-external-helpers 在shell执行手动生成helper文件
      • -t, –output-type [type] Set output format: global (default choice), umd or var
      • -l, –whitelist Whitelist of helpers to ONLY include
        babel-external-helpers -t umd > ./helpers.js
      
        babel-external-helpers -t umd -l createClass,classCallCheck > ./helpers.js
    • 引入helper.js方式
      • 浏览器环境通过script标签引入,且保证在应用代码得上边引入
          <script type="text/javascript" src="path/to/babel-helpers.js"></script>
          <script type="text/javascript" src="app.js"></script>
      • node环境,引入一个使用babelHelpers污染全局范围的中间件,然后启动主应用程序
      • webpack 使用webpack-provide-plugin去注入helper.js
        module.exports = {
          ...
          plugins: [
            new webpack.ProvidePlugin({
              babelHelpers: [path.resolve(__dirname, "dist", "helpers.js")],
            }),
          ],
          ...
        }

About

babel配置学习

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published