31.Babel

31.Babel Babel1. 什么是Babel?2. 核心功能3. 案例1. 语法转换将新版本的 JavaScript 语法转换为旧版本的语法1.1. test.js 测试用例1.2. index.js 核心转换代码1.3. 编译之后的代码1.4. 如何支持新特性例如 Object.assign Array.prototype.find 等1.5. index.js 增强编译1.6. 转换之后的代码2.jsx代码转换react2.1. 测试用例 test.jsx2.2. 编写代码 只需要增加一个预设即可 babel/preset-react2.3. 转换的结果:3. 编写Babel插件3.1. 手动编写插件实现将箭头函数转成普通函数3.2. 转换之后的结果1. 什么是Babel?Babel 是一个 JavaScript 编译器,提供了JavaScript的编译过程能够将源代码转换为目标代码。AST - Transform - Generate官网: https://babeljs.io/查看AST: https://astexplorer.net/Babel所有的包: https://babeljs.io/docs/babel-traverse2. 核心功能语法转换将新版本的 JavaScript 语法转换为旧版本的语法Polyfill通过引入额外的代码使新功能在旧浏览器中可用(垫片)JSX: 将JSX语法转换成普通的JavaScript语法插件: 为Babel提供自定义功能3. 案例1. 语法转换将新版本的 JavaScript 语法转换为旧版本的语法npminstall--save-dev babel/core babel/cli babel/preset-env1.1. test.js 测试用例//语法consta(params2)1params;constb[1,2,3]constc[...b,4,5]classBabel{}newBabel()//APIconstx[1,2,3,4,5,6,7,8,9,10].filter((x)x%20)constyObject.assign({},{name:1})1.2. index.js 核心转换代码//记得设置package.json的type为moduleimportBabelfrombabel/coreimportpresetEnvfrombabel/preset-envimportfsfromnode:fsconstfilefs.readFileSync(./test.js,utf8)constresultBabel.transform(file,{presets:[presetEnv]})console.log(result.code)1.3. 编译之后的代码use strict;function_typeof(o){babel/helpers - typeof;return_typeoffunctiontypeofSymbolsymboltypeofSymbol.iterator?function(o){returntypeofo;}:function(o){returnofunctiontypeofSymbolo.constructorSymbolo!Symbol.prototype?symbol:typeofo;},_typeof(o);}function_defineProperties(e,r){for(vart0;tr.length;t){varor[t];o.enumerableo.enumerable||!1,o.configurable!0,valueino(o.writable!0),Object.defineProperty(e,_toPropertyKey(o.key),o);}}function_createClass(e,r,t){returnr_defineProperties(e.prototype,r),t_defineProperties(e,t),Object.defineProperty(e,prototype,{writable:!1}),e;}function_toPropertyKey(t){vari_toPrimitive(t,string);returnsymbol_typeof(i)?i:i;}function_toPrimitive(t,r){if(object!_typeof(t)||!t)returnt;varet[Symbol.toPrimitive];if(void0!e){varie.call(t,r||default);if(object!_typeof(i))returni;thrownewTypeError(toPrimitive must return a primitive value.);}return(stringr?String:Number)(t);}function_classCallCheck(a,n){if(!(ainstanceofn))thrownewTypeError(Cannot call a class as a function);}varafunctiona(){varparamsarguments.length0arguments[0]!undefined?arguments[0]:2;return1params;};varb[1,2,3];varc[].concat(b,[4,5]);varBabel/*#__PURE__*/_createClass(functionBabel(){_classCallCheck(this,Babel);});newBabel();1.4. 如何支持新特性例如 Object.assign Array.prototype.find 等npmi core-js-D1.5. index.js 增强编译importBabelfrombabel/coreimportpresetEnvfrombabel/preset-envimportfsfromnode:fsconstfilefs.readFileSync(./test.js,utf8)constresultBabel.transform(file,{//usage 会根据配置的浏览器兼容以及你代码中用到的 API 来进行 polyfill实现了按需添加//corejs 3 是corejs的版本presets:[[presetEnv,{useBuiltIns:usage,corejs:3}]]})console.log(result.code)1.6. 转换之后的代码use strict;require(core-js/modules/es.symbol.js);require(core-js/modules/es.symbol.description.js);require(core-js/modules/es.symbol.iterator.js);require(core-js/modules/es.symbol.to-primitive.js);require(core-js/modules/es.array.iterator.js);require(core-js/modules/es.date.to-primitive.js);require(core-js/modules/es.number.constructor.js);require(core-js/modules/es.object.define-property.js);require(core-js/modules/es.string.iterator.js);require(core-js/modules/web.dom-collections.iterator.js);function_typeof(o){babel/helpers - typeof;return_typeoffunctiontypeofSymbolsymboltypeofSymbol.iterator?function(o){returntypeofo;}:function(o){returnofunctiontypeofSymbolo.constructorSymbolo!Symbol.prototype?symbol:typeofo;},_typeof(o);}require(core-js/modules/es.array.concat.js);require(core-js/modules/es.array.filter.js);require(core-js/modules/es.object.assign.js);require(core-js/modules/es.object.to-string.js);function_defineProperties(e,r){for(vart0;tr.length;t){varor[t];o.enumerableo.enumerable||!1,o.configurable!0,valueino(o.writable!0),Object.defineProperty(e,_toPropertyKey(o.key),o);}}function_createClass(e,r,t){returnr_defineProperties(e.prototype,r),t_defineProperties(e,t),Object.defineProperty(e,prototype,{writable:!1}),e;}function_toPropertyKey(t){vari_toPrimitive(t,string);returnsymbol_typeof(i)?i:i;}function_toPrimitive(t,r){if(object!_typeof(t)||!t)returnt;varet[Symbol.toPrimitive];if(void0!e){varie.call(t,r||default);if(object!_typeof(i))returni;thrownewTypeError(toPrimitive must return a primitive value.);}return(stringr?String:Number)(t);}function_classCallCheck(a,n){if(!(ainstanceofn))thrownewTypeError(Cannot call a class as a function);}//语法varafunctiona(){varparamsarguments.length0arguments[0]!undefined?arguments[0]:2;return1params;};varb[1,2,3];varc[].concat(b,[4,5]);varBabel/*#__PURE__*/_createClass(functionBabel(){_classCallCheck(this,Babel);});newBabel();//APIvarx[1,2,3,4,5,6,7,8,9,10].filter(function(x){returnx%20;});varyObject.assign({},{name:1});2.jsx代码转换react2.1. 测试用例 test.jsximportreactfromreactimport{createRoot}fromreact-dom/clientconstApp(){returndiv小满是谁/div}createRoot(document.getElementById(root)).render(App/)2.2. 编写代码 只需要增加一个预设即可 babel/preset-reactnpminstallbabel/preset-react-DimportBabelfrombabel/coreimportpresetEnvfrombabel/preset-envimportfsfromnode:fsimportreactfrombabel/preset-reactconstfilefs.readFileSync(./test.jsx,utf8)constresultBabel.transform(file,{presets:[[presetEnv,{useBuiltIns:usage,corejs:3}],react]})console.log(result.code)2.3. 转换的结果:其实也就是调用了React.createElement去创建元素use strict;var_react_interopRequireDefault(require(react));var_clientrequire(react-dom/client);function_interopRequireDefault(e){returnee.__esModule?e:{default:e};}varAppfunctionApp(){return/*#__PURE__*/React.createElement(div,null,\u5C0F\u6EE1\u662F\u8C01\uFF1F\uFF1F\uFF1F\uFF1F\uFF1F);};(0,_client.createRoot)(document.getElementById(root)).render(/*#__PURE__*/React.createElement(App,null));3. 编写Babel插件3.1. 手动编写插件实现将箭头函数转成普通函数importBabelfrombabel/coreimportfsfromnode:fsconstfilefs.readFileSync(./test.js,utf8)//babel会注入一个types对象里面包含了各种ast节点的方法consttransformFunction({types:t}){return{name:babel-transform-function,//visitor 是一个对象它包含了一组方法这些方法对应于 AST 中的不同节点类型。每当 Babel 遇到某种类型的节点时都会调用 visitor 中对应的方法。visitor:{//匹配 箭头函数 当然也可以匹配别的东西 这儿只是案例ArrowFunctionExpression(path){constnodepath.nodeconstarrowFunctiont.functionExpression(null,//node.id 是一个 Identifier 节点表示函数名node.params,//node.params 是一个数组表示函数的参数// BlockStatement 是 JavaScript 抽象语法树AST中的一种节点类型表示一个由大括号 {} 包围的语句块。它是函数体、循环体、条件分支如 if 语句等代码块的基础结构t.blockStatement([t.returnStatement(node.body)]),//node.body 是函数的主体通常是一个 BlockStatement 节点node.async//node.async 是一个布尔值表示函数是否是异步的 (async 函数))path.replaceWith(arrowFunction)//替换当前节点}}}}constresultBabel.transform(file,{plugins:[transformFunction]})console.log(result.code)3.2. 转换之后的结果//语法constafunction(params2){return1params;};constb[1,2,3];constc[...b,4,5];classBabel{}newBabel();//APIconstx[1,2,3,4,5,6,7,8,9,10].filter(function(x){returnx%20;});constyObject.assign({},{name:1});参考链接: https://message163.github.io/react-docs/react/tools/babel.html