译文:Babel.js Guide -Part 1- The Absolute Must-Know Basics: Plugins, Presets, And Config

本文将讲述:
  • Babel 是什么以及怎么在日常开发中应用它?
  • presets and plugins 是什么及区别,在babel执行中,他们的执行程序是什么?

尽管原文题目看似是一个系列,但作者仿佛没有持续,但我曾经想好了下一部分要写的内容;非专业翻译,夹带本人了解,有小改变。

Babel 是什么

babel 是一个收费开源的JavaScript 编译库. 它依据你的配置将代码转化成各式各样的JS代码。

最常见的应用形式就是将古代语法JavaScript es6+编写的代码 转化成 es5,从而兼容更多的浏览器(特地是IE),上面以Babel 转换es6 箭头函数 为 es5 函数的为例。

// The original codeconst foo = () => console.log('hello world!');

转移后

// The code after babel transpilationvar foo = function foo() {  return console.log('hello world!');};

你能够在这里在线尝试

应用Babel

在线Repl

这是应用Babel的最简略办法。这兴许不是一个十分实用的工具,然而是最快的测试或者试验Babel如何工作的工具, 在线Repl地址。

构建库

应用Babel的最风行办法是应用WebpackGulpRollup等构建库进行打包构建。每个形式都应用Babel作为构建的一部分来实现本人的构建过程。

比方,咱们最罕用的webpack:

{  ...  module: {    rules: [      {        test: /\.js$/,        exclude: /(node_modules|bower_components)/,        use: {          loader: 'babel-loader',          options: {            plugins: ['@babel/plugin-transform-arrow-functions']          }        }      }    ]  },  ...}

库罕用的构建工具:Rollup

rollup.rollup({  ...,  plugins: [    ...,    babel({      plugins: ['@babel/plugin-transform-arrow-functions']    }),    ...  ],  ...}).then(...)

脚手架cli

除了依赖构建库,也能够间接用命令行依赖官网提供的@babel/cli 包来编译NIIT的代码:

# install the core of babel and it's cli interfacenpm install @babel/core @babel/cli# use the babel command linebabel script.js --out-file script-compiled.js

Babel Plugins

Babel是通过插件配置的。开箱即用,Babel不会更改您的代码。没有插件,它基本上是这样的:

// parse -> generate, 大白话就是英翻中,中翻英const babel = code => code;

通过Babel插件运行代码,您的代码将转换为新代码,如下所示:

// parse -> do something -> generate, 大白话就是英翻中,添枝加叶,中翻英const babel = code => babelPlugin2(babelPlugin1(code));

Babel Presets

您能够独自增加Babel插件列表,然而通常更不便的办法是应用Babel presets。

Babel presets联合一系列插件的汇合。传递给presets的选项会影响其聚合的插件, 这些选项将管制应用哪些插件以及这些插件的配置。

比方,咱们后面看到的@babelplugin-transform-arrow-functions插件是@babel/preset-env presets的一部分。

@babel/preset-env可能是最受欢迎的presets。 它依据用户传递给预设的配置(比方browsers:指标浏览器/环境), 将古代JavaScript(即ES Next)转换为较旧的JavaScript版本。

比方:它能够将()=> arrowFunctions,{…detructuring} 和class {}转换为旧版浏览器反对的JavaScript语法,举个????, 指标浏览器为IE11:

// 新版语法class SomeClass {  constructor(config){    this.someFunction = params => {      console.log('hello world!', {...config, ...params});    }  }  someMethod(methodParams){    this.someFunction(methodParams);  }  someOtherMethod(){    console.log('hello some other world');  }}

编译后:

// explained here: https://www.w3schools.com/js/js_strict.asp"use strict";// this is a babel helper function injected by babel to mimic a {...destructuring} syntaxfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }// this is a babel helper function injected by babel for a faster-than-native property defining on an object// very advanced info can be found here:// https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L348function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }// this is a babel helper function that makes sure a class is called with the "new" keyword like "new SomeClass({})" and not like "SomeClass({})"function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }// like "_defineProperty" above, but for multiple propsfunction _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); } }// used by babel to create a class with class functions function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }var SomeClass =/*#__PURE__*/ // this marks the function as pure. check https://webpack.js.org/guides/tree-shaking/ for more info.function () {  // the class got converted to a function  function SomeClass(config) {    // make sure a class is called with the "new" keyword    _classCallCheck(this, SomeClass);    // someFunction is set on SomeClass     this.someFunction = function (params) {         // notice how the {...config, ...params} became _objectSpread({}, config, params) here      console.log('hello world!', _objectSpread({}, config, params));    };  }  // this function adds the class methods to the transpiled class created above  _createClass(SomeClass, [    {      key: "someMethod",      value: function someMethod(methodParams) {        this.someFunction(methodParams);      }    },    {      key: "someOtherMethod",      value: function someOtherMethod() {        console.log('hello some other world');      }    }  ]);  return SomeClass;}();

对于更简单的构建要求,配置将应用我的项目根目录中的babel.config.js文件。因为是JavaScript文件,因而比.babelrc更加灵便。例如:

module.exports = function (api) {    // Only execute this file once and cache the resulted config object below for the next babel uses.  // more info about the babel config caching can be found here: https://babeljs.io/docs/en/config-files#apicache  api.cache.using(() => process.env.NODE_ENV === "development")  return {    presets: [      // Use the preset-env babel plugins      '@babel/preset-env'    ],    plugins: [      // Besides the presets, use this plugin      '@babel/plugin-proposal-class-properties'    ]  }}

@babel/preset-env不同配置,编译出的代码可能大不一样,比方当配置为:latest 10 Chrome versions是,下面一段代码编译后果与编译前统一,因为下面的个性,chrrome都反对;但如果将10调整为30,40时,你会发现,编译的代码将会越来越多;能够点击这里尝试一下:

配置

Babel Plugins and Presets 是十分重要的概念,Babel的配置由Plugins and Presets组合而成(也能够应用其余几个高级属性);

简略的配置,能够间接应用.babelrc,babelrc是一种JSON5文件(和JSON一样,但其容许正文),被搁置在我的项目根目录下,比方上面这样:

// Comments are allowed as opposed to regular JSON files{  presets: [    // Use the preset-env babel plugins    '@babel/preset-env'  ],  plugins: [    // Besides the presets, use this plugin    '@babel/plugin-proposal-class-properties'  ]}

对于更简单的配置,个别应用babel.config.js文件来代替.babelrc文件,因为他是js文件,所以比.babelrc配置更灵便,举个例子:

module.exports = function (api) {  // Only execute this file once and cache the resulted config object below for the next babel uses.  // more info about the babel config caching can be found here: https://babeljs.io/docs/en/config-files#apicache  api.cache.using(() => process.env.NODE_ENV === "development")  return {    presets: [      // Use the preset-env babel plugins      '@babel/preset-env'    ],    plugins: [      // Besides the presets, use this plugin      '@babel/plugin-proposal-class-properties'    ]  }  }

一些配置文件可能非常复杂, 例如: Babel我的项目自身的babel.config.js。莫慌!浏览本指南系列后,您将晓得此简单配置的每一行的意义(看,有头牛在天上飞)。

Babel Plugins and Presets 执行程序

如果您在配置中混合应用了Plugins和Presets,Babel将按以下程序利用它们:

  • 首先从上到下利用插件;
  • 而后,将预设利用在插件之后,从下到上;

举个????:

{  presets: [    '@babel/preset-5', //   ↑    ** End Here ** Last preset to apply it's plugins *after* all the plugins below finished to run     '@babel/preset-4', //   ↑    '@babel/preset-3', //   ↑    2    '@babel/preset-2', //   ↑    '@babel/preset-1', //   ↑    First preset to apply it's plugins *after* all the plugins below finished to run   ],  plugins: [    '@babel/plugin-1', //   ↓    >>> Start Here <<< First plugin to transpile the code.    '@babel/plugin-2', //   ↓      '@babel/plugin-3', //   ↓    1    '@babel/plugin-4', //   ↓      '@babel/plugin-5', //   ↓    Last plugin to transpile the code before the preset plugins are applied  ]}

另外,值得一提的是,每个Presets中的插件也自上而下利用。

以正确的程序配置Plugins和Presets十分重要! 正确的程序可能会放慢翻译速度,谬误的程序可能会产生不须要的后果或者导致谬误。

可能下面的????不够实在,那就来个实在的吧:

{  "presets": [    "@babel/preset-env",    "@babel/preset-react",  ],  "plugins": [    ["@babel/plugin-proposal-decorators", { "legacy": true }],  ]}

decorators 是装璜器语法,当初还处于stage-3阶段难产,而JSX则是React的专有语法;如果没有@babel/plugin-proposal-decorators@babel/preset-react 先编译,间接运行@babel/preset-env编译,就会报@<div> 有效的语法标识,所有正确的配置插件和插件程序是如许重要。

Babel Plugins and Presets 选项

下面提到过给@babel/preset-env设置不同的browsers选项,会失去不同的编译后果;通过将选项包装在数组中并向其中增加选项,能够将选项配置传递给Babel Plugins and Presets,比方位于@babel/preset-env前面的对象就是一个选项配置,通知编译的指标是兼容到chrome 58版本和IE11:

{  presets: [    // Notice how @babel/preset-env is wrapped in an array with an options object    ['@babel/preset-env', {      "targets": {        "chrome": "58",        "ie": "11"      }    }],    '@babel/some-other-preset'  ]}

@babel/preset-env根本是我的项目编译必选的Presets,除了targets,还有useBuiltIns,esmodules,modules等常见选项,还有更多对于配置可参考官网

最初

对于指引,就这么多,将在不久后推出进阶篇, 对于babel-runtime与babel-polyfill。