您的位置:首页 > 游戏 > 游戏 > 漳州开发区人才网_温州今日头条新闻_百度服务中心_百度 营销推广怎么收费

漳州开发区人才网_温州今日头条新闻_百度服务中心_百度 营销推广怎么收费

2024/12/23 12:34:26 来源:https://blog.csdn.net/qq_37550440/article/details/143306444  浏览:    关键词:漳州开发区人才网_温州今日头条新闻_百度服务中心_百度 营销推广怎么收费
漳州开发区人才网_温州今日头条新闻_百度服务中心_百度 营销推广怎么收费

什么是Babel?

Babel 是一个 JavaScript 编译器,提供了JavaScript的编译过程,能够将源代码转换为目标代码。AST -> Transform -> Generate

官网 Babel · Babel

查看AST https://astexplorer.net/

Babel所有的包 @babel/traverse · Babel

Babel 是一个广泛使用的 JavaScript 编译器,它主要用于将现代的 JavaScript 代码转换成向后兼容的版本,以便可以在旧版浏览器中运行。Babel 的编译过程可以分为三个主要阶段:解析(Parse)、转换(Transform)和生成(Generate)。这三个阶段分别对应于上文提到的 AST -> Transform -> Generate。

  1. 解析 (Parse) - 生成抽象语法树 (AST) 在这个阶段,Babel 将源代码作为输入,并通过解析器将其转换为抽象语法树 (Abstract Syntax Tree, AST)。AST 是一种表示代码结构的树形数据结构,其中每个节点代表源代码中的一个构造,比如变量声明、函数调用等。这个阶段的主要工作是读取源代码并创建相应的 AST 结构,这样就可以以编程方式来理解和操作代码了。

  2. 转换 (Transform) 一旦有了 AST,Babel 就可以通过遍历这棵树来应用各种转换插件。这些插件能够修改 AST,从而实现从一种 JavaScript 版本到另一种版本的转换。例如,一个插件可能将 ES6 的箭头函数转换为 ES5 中的普通函数。转换阶段是 Babel 功能的核心部分,因为它允许开发者根据需要添加或移除特定的功能,或者执行其他形式的代码转换。Babel 使用访问者模式来遍历 AST,并在适当的地方插入或删除节点,或者改变节点属性。

  3. 生成 (Generate) 最后,在所有必要的转换完成后,Babel 需要将更新后的 AST 转换回实际的 JavaScript 代码。这个阶段被称为代码生成。在这个过程中,Babel 会遍历修改过的 AST 并输出新的源代码。生成的代码应该与原始代码具有相同的行为,但可能使用了不同的语言特性或语法结构。最终的结果就是转换后的代码,它可以被更广泛的环境所支持。

 AST抽象语法树

核心功能​

  1. 语法转换:将新版本的 JavaScript 语法转换为旧版本的语法
  2. Polyfill:通过引入额外的代码,使新功能在旧浏览器中可用如filter这些新特性在旧浏览器中无法使用需要处理
  3. JSX: 将JSX语法转换成普通的JavaScript语法
  4. 插件: 为Babel提供自定义功能

案例

案例1 es6转es5 

语法转换:将新版本的 JavaScript 语法转换为旧版本的语法

npm install --save-dev @babel/core @babel/cli @babel/preset-env

//如何支持新特性例如 Object.assign Array.prototype.find 等

npm i core-js -D

目录结构:

test.js 测试用例  

//语法
const a = (params = 2) => 1 + params;
const b = [1, 2, 3]
const c = [...b, 4, 5]
class Babel {}
new Babel()
//API
const x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].filter((x) => x % 2 === 0)
const y = Object.assign({}, { name: 1 })

index.js 核心转换代码

///记得设置package.json的type为module
import Babel from '@babel/core'
import presetEnv from '@babel/preset-env'
import fs from 'node:fs'
const file = fs.readFileSync('./test.js', 'utf8')
const result = Babel.transform(file, {//usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加//corejs 3 是corejs的版本presets: [// useBuiltIns参数有很多entry,usage等,corejs是版本// entry手动引入 usage按需引入[presetEnv, { useBuiltIns: "usage", corejs: 3 }]]
})
console.log(result.code)

转换之后的代码

"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 _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _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 (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } 
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
//语法
var a = function a() {var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;return 1 + params;
};
var b = [1, 2, 3];
var c = [].concat(b, [4, 5]);
var Babel = /*#__PURE__*/_createClass(function Babel() {_classCallCheck(this, Babel);
});
new Babel();
//API
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].filter(function (x) {return x % 2 === 0;
});
var y = Object.assign({}, {name: 1
});

案例2jsx代码转换react

npm i  react react-dom -D

npm install @babel/preset-react -D  //之前的babel预设也需要

测试用例 test.jsx

import react from 'react'
import { createRoot } from 'react-dom/client'const App = () => {return <div>是谁?????</div>
}createRoot(document.getElementById('root')).render(<App />)

index.js

//记得设置package.json的type为module
import Babel from '@babel/core'
import presetEnv from '@babel/preset-env'
import fs from 'node:fs'
import react from '@babel/preset-react' //支持jsx语法
// const file = fs.readFileSync('./test.js', 'utf8')
const file = fs.readFileSync('./test.jsx', 'utf8')
const result = Babel.transform(file, {//usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加//corejs 3 是corejs的版本presets: [// useBuiltIns参数有很多entry,usage等,corejs是版本// entry手动引入 usage按需引入[presetEnv, { useBuiltIns: "usage", corejs: 3 }],react]
})
console.log(result.code)

转换的结果

其实也就是调用了React.createElement去创建元素

"use strict";var _react = _interopRequireDefault(require("react"));
var _client = require("react-dom/client");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
var App = function App() {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));

手写babel插件

import Babel from '@babel/core'
import fs from 'node:fs'
const file = fs.readFileSync('./test.js', 'utf8')
//babel会注入一个types对象里面包含了各种ast节点的方法
const transformFunction = ({ types: t }) => {return {name: 'babel-transform-function',//visitor 是一个对象,它包含了一组方法,这些方法对应于 AST 中的不同节点类型。每当 Babel 遇到某种类型的节点时,都会调用 visitor 中对应的方法。visitor: {//匹配 箭头函数 当然也可以匹配别的东西 这儿只是案例ArrowFunctionExpression(path) {const node = path.nodeconst arrowFunction = t.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) //替换当前节点}}}
}
const result = Babel.transform(file, {plugins: [transformFunction]
})
console.log(result.code)

很多插件的写法都是一样的,如vite rollup esbuild都是差不多的 除了webpack插件不同,

const test =(params) =>{

  //都是返回一个对象,含各种配置信息

  return {

    //插件包名

    //插件的生命周期

    name: '',

    visitor: {

     

    }

  }

}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com