Babel 编译器
Babel是一个Javascript 编译器。将ECMA2015及以上版本的代码通过babel转为向下兼容的javascript。这也是你可以使用更先进语法的原因。
浏览器并不兼容ts,jsx,或者es6语法,但是通过babel插件类如typescript @babel/preset-env,可将代码编译为兼容的javascript。以便浏览器识别。
Babel执行过程
-
parse解析代码 生成AST树
var { parse } = require('@babel/parser'); var code = `const name = "jyy";`; // 源代码生成的ast var ast = parse(code); console.log(ast)
去掉部分信息
{ "type":"File", "program":{ "type":"Program", "sourceType":"script", "body":[ { "type":"VariableDeclaration", "declarations":[ { "type":"VariableDeclarator", "id":{ "type":"Identifier", "name":"name" }, "init":{ "type":"StringLiteral", "extra":Object{...}, "value":"jyy" } } ], "kind":"const" } ], "directives":[] }, "comments":Array[0] }
-
transform AST转换
babel 是个工具链,如果直接将AST转为javascript代码进行输出,那么前后没有任何区别。 这一步叫做转换,就是将AST进行增删改。这也就是插件的功能。 @babel/plugin-transform-react-jsx 就是将react中的jsx代码转为react 的节点对象。 @babel/plugin-proposal-optional-chaining 支持代码中书写可选链(target?.pro)
-
@babel/traverse 插件 可以定义回调函数,回调函数的参数提供了丰富的增、删、改、查以及类型断言
-
@babel/types 插件 它的作用是创建、修改、删除、查找ast节点‘
-
@babel/plugin-proposal-optional-chaining 。。。
var { parse } = require('@babel/parser'); var { default: traverse } = require('@babel/traverse'); var { default: generate } = require('@babel/generator'); var t = require('@babel/types'); var code = `const target = stringify({a:1});`; var ast = parse(code); traverse(ast, { Identifier(path) { const { node } = path; if (node && node.name === 'stringify') { const nNode = t.memberExpression(t.identifier('JSON'), t.identifier('stringify')); path.replaceWith(nNode); path.stop(); } } }) const newCode = generate(ast, {}, code).code; //'const target = JSON.stringify({\n a: 1\n});'
-
-
AST 输出。生成新的javascript代码
插件是@babel/generator,其作用就是将转换好的ast重新生成代码。[见上]
-
总结
// js=>AST=>js 1:parser 解析代码到AST 2:transform AST 。插件 2.1:type 它的作用是创建、修改、删除、查找ast节点 2.2:traverse 遍历AST 定义回调函数,回调函数的参数提供了丰富的增、删、改、查以及类型断言的方法 2.3:.... 3:generator AST生成js代码
Babel/Core 整合基础插件
@babel/parse、@babel/generator都是提供了代码转换的基本功能,
@babel/types、@babel/traverser起作用是提供操作ast节点的功能
@babel/helper-module-transforms
@babel/template 用于从字符串形式的代码来构建 AST 树节点
…
另外加入了其他功能,比如读取、分析配置文件
-
dome
var babel = require("@babel/core"); var code = "<div class='c'>jyy</div>"; // 代码 babel.transform(code,{plugins: ["@babel/plugin-transform-react-jsx"],},function(err, result){ console.log(result.code); // React.createElement("div", { // class: "c" // }, "jyy"); });
Babel插件
babel已经开发了基础插件,包含code==>AST=转换=>New_AST==>code。
这里所说的插件针对于AST的转换。用于支持新的javascript 新的语法和语法糖。
-
插件
var babel = require("@babel/core"); var code = `num => {return num ** 2;}`; // 代码 babel.transform(code,{ plugins: [ "@babel/plugin-transform-arrow-functions",// 兼容箭头函数 "@babel/plugin-transform-exponentiation-operator",// 兼容 幂运算符 //。。。。 ] },function(err, result){ /*** (function (num) { return Math.pow(num, 2); }); */ });
-
预设preset
为兼容越来越多的新语法,开发者可能要导入很多的插件。 这里增加了预设,预设就是插件集合。再也不用一个一个导入 1:@babel/preset-env 将最新javascript转为es6 2:@babel/preset-flow 3:@babel/preset-react 支持react 4:@babel/preset-typescript
-
preset-env
查看所有依赖插件
@babel/preset-env 等价于 @babel/env
“@babel/babel-plugin-name” 和 “@babel/name”是等价的
var babel = require("@babel/core"); var code = `num => {return num ** 2;}`; // babel.transform(code,{ plugins:[], presets: ["@babel/preset-env"] },function(err, result){ console.log(result.code); });
Babel配置
1:命令行 babel src --out-dir lib --presets=@babel/preset-env,@babel/react
2:.babelrc 项目根目录创建文件 {"presets":[],"plugins":[]}
3:babel.config.js 项目根目录创建文件 {module.exports={"presets":[],"plugins":[]}}
4:package.json {"babel":{"presets":[],"plugins":[]}}
Babel简单应用
-
简单的esnext规范代码解析为es6
// ======================> src/app.js class MError extends Error { statusCode = null; code = 0; constructor(message, code, statusCode) { super(message); this.code = code; this.statusCode = statusCode; } get [Symbol.toStringTag]() { return 'MError'; } } // ===============================> js 转换AST var babel = require("@babel/core"); var fs = require("fs"); const path = require("path"); const source = path.join(__dirname, 'src', 'app.js'); const target = path.join(__dirname, 'dist', 'app.js'); babel.transformFile(source, { plugins: [], presets: ["@babel/preset-env"] }, function (err, result) { if (!!err === false) { fs.writeFileSync(target, result.code); } }); //===============================> dist/app.js "use strict"; ...省略声明代码 var MError = /*#__PURE__*/function (_Error) { _inherits(MError, _Error); var _super = _createSuper(MError); function MError(message, code, statusCode) { var _this; _classCallCheck(this, MError); _this = _super.call(this, message); _defineProperty(_assertThisInitialized(_this), "statusCode", null); _defineProperty(_assertThisInitialized(_this), "code", 0); _this.code = code; _this.statusCode = statusCode; return _this; } _createClass(MError, [{ key: _Symbol$toStringTag, get: function get() { return 'MError'; } }]); return MError; }( /*#__PURE__*/_wrapNativeSuper(Error));
-
支持typescript
-
方式一 1:使用tsc命令 将ts语法转为js语法 2:使用preser/env将js 转为es6 。 TS > TS Compiler > JS > Babel > NEW_JS
-
方式二 2: @babel/preset-typescript 整合typescript
var babel = require("@babel/core"); var fs = require("fs"); const path = require("path"); const source = path.join(__dirname, 'src', 'app.ts'); const target = path.join(__dirname, 'dist', 'app.ts.js'); babel.transformFile(source, { plugins: [ '@babel/plugin-proposal-object-rest-spread',// 解构的支持 '@babel/plugin-proposal-class-properties', // static 支持 ], presets: [ "@babel/preset-typescript", // 将ts=>JS 配置tsconfig.json 是无效的 '@babel/preset-env',// JS=>JS ] }, function (err, result) { if (!!err === false) { fs.writeFileSync(target, result.code); } });
-
-
webpack + ts
webpack+ts配置
1:tsc 命令基本不和webpack结合。 webpack 有watch 参数 2:webpack (ts-loader+ tsconfig.json)用于处理ts文件 + (babel-loader+@babel/preset-env) 再将js编译为es6 3:webpack (无ts-loader ,使用 (@babel/preset-typescript + @babel/preset-env)
// 方式2 // webpack.config.js const path = require('path'); module.exports = { mode: 'production', entry: { 'index': path.join(__dirname, "src", 'index.ts'), }, watch: false, output: { filename: "[name].js", path: path.join(__dirname, "cjs"), }, module: { rules: [ { test: /\.ts$/,// 处理ts exclude: /node_modules/, use: ['ts-loader'] }, { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components|build)/, use: { loader: "babel-loader", options: { "plugins": [ ["@babel/plugin-proposal-optional-chaining"], ], presets: ["@babel/preset-env"] } }, },] }, externals: {}, plugins: [], resolve: { extensions: [ '.js', '.jsx','.ts','.tsx'], }, };
// 方式3 // webpack.dev.js module.exports = { // 其他配置见上 module: { rules: [{ test: /\.(js|jsx|ts)$/, // 新增 对ts文件处理 exclude: /(node_modules|bower_components|build)/, use: { loader: "babel-loader", options: { "plugins": [ ["@babel/plugin-proposal-optional-chaining",{}], '@babel/plugin-proposal-object-rest-spread',// 解构的支持 '@babel/plugin-proposal-class-properties', // static 支持 ], presets: [ "@babel/preset-typescript", // 对ts文件的预设 "@babel/preset-env" ] } }, },] }, devtool: 'cheap-module-source-map', };