Babel是一个Javascript 编译器。将ECMA2015及以上版本的代码通过babel转为向下兼容的javascript。这也是你可以使用更先进语法的原因。
浏览器并不兼容ts,jsx,或者es6语法,但是通过babel插件类如typescript @babel/preset-env,可将代码编译为兼容的javascript。以便浏览器识别。
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]
}
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});'
插件是@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/parse、@babel/generator都是提供了代码转换的基本功能,
@babel/types、@babel/traverser起作用是提供操作ast节点的功能
@babel/helper-module-transforms
@babel/template 用于从字符串形式的代码来构建 AST 树节点
…
另外加入了其他功能,比如读取、分析配置文件
var babel = require("@babel/core");
var code = "jyy"; // 代码
babel.transform(code,{plugins: ["@babel/plugin-transform-react-jsx"],},function(err, result){
console.log(result.code);
// React.createElement("div", {
// class: "c"
// }, "jyy");
});
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);
});
*/
});
为兼容越来越多的新语法,开发者可能要导入很多的插件。
这里增加了预设,预设就是插件集合。再也不用一个一个导入
1:@babel/preset-env 将最新javascript转为es6
2:@babel/preset-flow
3:@babel/preset-react 支持react
4:@babel/preset-typescript
@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);
});
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":[]}}
// ======================> 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));
方式一 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);
}
});
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',
};