译文:Babel.js Guide -Part 1- The Absolute Must-Know Basics: Plugins, Presets, And Config前端
本文将讲述:
虽然原文标题看似是一个系列,但做者彷佛没有继续,但我已经想好了下一部分要写的内容;非专业翻译,夹带本身理解,有小改动。node
babel 是一个免费开源的JavaScript 编译库. 它根据你的配置将代码转化成各式各样的JS代码。react
最多见的使用方式就是将现代语法JavaScript es6+编写的代码 转化成 es5,从而兼容更多的浏览器(特别是IE),下面以Babel 转换es6 箭头函数 为 es5 函数的为例。webpack
// The original code const foo = () => console.log('hello world!');
转移后git
// The code after babel transpilation var foo = function foo() { return console.log('hello world!'); };
你能够在这里在线尝试es6
这是使用Babel的最简单方法。这也许不是一个很是实用的工具,可是是最快的测试或者实验Babel如何工做的工具, 在线Repl地址。github
使用Babel的最流行方法是使用Webpack
,Gulp
或Rollup
等构建库进行打包构建。每一个方式都使用Babel做为构建的一部分来实现本身的构建过程。web
好比,咱们最经常使用的webpack:chrome
{ ... module: { rules: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { plugins: ['@babel/plugin-transform-arrow-functions'] } } } ] }, ... }
库经常使用的构建工具:Rollupnpm
rollup.rollup({ ..., plugins: [ ..., babel({ plugins: ['@babel/plugin-transform-arrow-functions'] }), ... ], ... }).then(...)
除了依赖构建库,也能够直接用命令行依赖官方提供的@babel/cli 包来编译NIIT的代码:
# install the core of babel and it's cli interface npm install @babel/core @babel/cli # use the babel command line babel script.js --out-file script-compiled.js
Babel是经过插件
配置的。开箱即用,Babel不会更改您的代码。没有插件,它基本上是这样的:
// parse -> generate, 大白话就是英翻中,中翻英 const babel = code => code;
经过Babel插件运行代码,您的代码将转换为新代码,以下所示:
// parse -> do something -> generate, 大白话就是英翻中,添油加醋,中翻英 const babel = code => babelPlugin2(babelPlugin1(code));
您能够单独添加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} syntax function _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#L348 function _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 props 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); } } // 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。莫慌!阅读本指南系列后,您将知道此复杂配置的每一行的意义(看,有头牛在天上飞)。
若是您在配置中混合使用了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/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。