02 什么是Babel

什么是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: {

    }

  }

}

创建基本的 Vite 插件

1.定义插件: 你需要定义一个对象或函数作为你的插件。这个对象可以包含多个钩子(hooks),这些钩子会在构建过程中被调用

// my-plugin.js
export default function myPlugin(options) {return {name: 'vite-plugin-my-plugin', // 插件名称,用于调试和日志记录// 在这里定义各种钩子config(config, env) {// 修改 Vite 配置console.log('config hook');return {...config,define: {__APP_VERSION__: JSON.stringify(process.env.npm_package_version)}};},configureServer(server) {// 自定义 dev serverconsole.log('configureServer hook');// 可以在这里添加中间件、监听事件等},transform(code, id) {// 转换代码if (id.endsWith('.js')) {console.log(`transforming ${id}`);code = code.replace(/console\.log/g, 'console.info');}return code;},buildStart() {// 构建开始时执行console.log('buildStart hook');},closeBundle() {// 打包结束时执行console.log('closeBundle hook');}};
}

2.在 Vite 配置中使用插件: 一旦你有了插件,你可以在 vite.config.js 中引入并使用它。

import { defineConfig } from 'vite';
import myPlugin from './my-plugin';export default defineConfig({plugins: [myPlugin({ /* 传递给插件的选项 */ })]
});

使用现有的 Vite 插件接口

Vite 提供了许多标准的插件钩子,比如 config, configureServer, transform, buildStart, closeBundle 等等。你可以根据需要实现相应的钩子来扩展 Vite 的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/460703.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读笔记】VLP: A Survey on Vision-language Pre-training

目录 前言2 特征提取&#xff08;Feature extraction&#xff09;2.1.1 图象特征提取OD-based Region feature / RoIFreeze the pre-trained object detectorsGrid features&#xff08;网格特征&#xff09;CNN-GFsEnd-to-End Training&#xff08;端到端训练&#xff09;ViT-…

TortoiseSVN小乌龟下载安装(Windows11)

目录 TortoiseSVN 1.14.7工具下载安装 TortoiseSVN 1.14.7 工具 系统&#xff1a;Windows 11 下载 官网&#xff1a;https://tortoisesvn.subversion.org.cn/downloads.html如图选 TortoiseSVN 1.14.7 - 64 位 下载完成 安装 打开 next&#xff0c;next Browse&#xf…

Mac OS 搭建MySQL开发环境

Mac OS 搭建MySQL开发环境 文章目录 Mac OS 搭建MySQL开发环境一、安装Mysql&#xff1a;二、配置环境变量三、安装Navicat 本地环境&#xff1a; Mac OS Sequoia15.0.1&#xff08;M3 Max) 目标状态&#xff1a; 下载安装Mysql&#xff0c;配置相关环境。 一、安装Mysql&…

docker Desktop开启远程访问端口

文章目录 问题解决方法1.首先开启docker Desktop的访问端口2.将本地端口绑定远程访问ip 验证 问题 Windows上部署的docker&#xff0c;没办法通过远程的ip进行访问&#xff0c;实现远程代码的部署。 解决方法 1.首先开启docker Desktop的访问端口 通过开启docker访问端口&am…

Linux文件系统学习(未完)

1. Linux文件系统的特点与类别 1.1 特点 Linux系统中&#xff0c;文件组织在一个统一的树形目录结构中&#xff0c;整个文件系统有一个根“/”&#xff08;文件夹&#xff09;&#xff0c;然后以每个目录&#xff08;文件夹&#xff09;作为分叉&#xff0c;叶子节点作为文件…

Three.js 快速入门构建你的第一个 3D 应用

![ 开发领域&#xff1a;前端开发 | AI 应用 | Web3D | 元宇宙 技术栈&#xff1a;JavaScript、React、Three.js、WebGL、Go 经验经验&#xff1a;6年 前端开发经验&#xff0c;专注于图形渲染和AI技术 开源项目&#xff1a;github 晓智元宇宙、数字孪生引擎、前端面试题 大家好…

排序算法汇总

一、二分查找 public static int binarySearch(int[] nums,int target){int l 0, r nums.length-1;while(l < r){int mid l (r-l)/2;if(nums[mid] target){return mid;}else if(nums[mid] < target){r mid - 1;}else{l mid 1;}}return -1;} 对于防止溢出的 mid …

类和对象(2)

1.类的默认成员函数 默认成员函数就是⽤⼾没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类&#xff0c;我们不写的情况下编译器会默认⽣成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前4个&#xff0c;最后两个取地址重载不…

AcWing 1303:斐波那契前 n 项和 ← 矩阵快速幂加速递推

【题目来源】https://www.acwing.com/problem/content/1305/http://poj.org/problem?id3070【题目描述】 大家都知道 数列吧&#xff0c;。现在问题很简单&#xff0c;输入 和 &#xff0c;求 的前 项和 。【输入格式】 共一行&#xff0c;包含两个整数 和 。【输出格式】…

ElasticSearch备考 -- Index rollover

一、题目 给索引my-index-000001&#xff0c;创建别名my-index&#xff0c;并设置rollover&#xff0c;满足以下三个条件的 The index was created 7 or more days ago.The index contains 5 or more documents.The index’s largest primary shard is 1GB or larger. 二、思考…

zabbix 6.0 监控clickhouse(单机)

zabbix 6.0 LTS已经包含了clickhouse的监控模板&#xff0c;所以我们可以直接使用自带的模板来监控clickhouse了。 0.前置条件 clickhouse 已经安装&#xff0c;我安装的是24.3.5.47zabbix-agent 已经安装并配置。系统是ubuntu 2204 server 1. 新建监控用户 使用xml的方式为…

Jmeter自动化实战

一、前言 由于系统业务流程很复杂,在不同的阶段需要不同的数据,且数据无法重复使用,每次造新的数据特别繁琐,故想着能不能使用jmeter一键造数据 二、创建录制模板 可参考:jmeter录制接口 首先创建一个录制模板 因为会有各种请求头,cookies,签名,认证信息等原因,导致手动复制…

提升网站速度与性能优化的有效策略与实践

内容概要 在数字化快速发展的今天&#xff0c;网站速度与性能优化显得尤为重要&#xff0c;它直接影响用户的浏览体验。用户在访问网站时&#xff0c;往往希望能够迅速获取信息&#xff0c;若加载时间过长&#xff0c;轻易可能导致他们转向其他更为流畅的网站。因此&#xff0…

OpenCV视觉分析之目标跟踪(6)轻量级目标跟踪器类TrackerNano的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 Nano 跟踪器是一个超轻量级的基于深度神经网络&#xff08;DNN&#xff09;的通用目标跟踪器。 由于特殊的模型结构&#xff0c;Nano 跟踪器速度…

C数组手动输入问题

问题界面 解析 输入数组数据也需要加取地址符吗&#xff1f;数组不就是地址了吗&#xff1f; 理解array[i]和array[i][j]的区别&#xff1a; array[i]是一个指向第i行第一个元素的指针&#xff08;int*类型&#xff0c;指向array[i][0]&#xff09;。 array[i][j]是一个int类…

Hadoop-002-部署并配置HDFS集群

集群规划 Hadoop HDFS的角色包含 NameNode(主节点管理者)、DataNode(从节点工作者)、SeconddaryNameNode(从节点辅助) 节点CPU内存hadoop-11C4Ghadoop-21C2Ghadoop-31C2G 一、下载上传Hadoop包 注意: 登录hadoop-1节点root用户执行 1、官网下载安装包后上传 到hadoop-1服务…

Android 在github网站下载项目:各种很慢怎么办?比如gradle下载慢;访问github慢;依赖下载慢

目录 访问github慢gradle下载慢依赖下载慢 前言 大家好&#xff0c;我是前期后期&#xff0c;在网上冲浪的一名程序员。 为什么要看这篇文章呢&#xff1f;问题是什么&#xff1f; 我们在Github上面看到一些好的项目的时候&#xff0c;想下载下来研究学习一下。但经常遇到各…

信息安全数学基础(35)同态和同构

一、同态 定义&#xff1a; 设(M,)和(S,)是两个群&#xff08;或更一般的代数系统&#xff09;&#xff0c;如果存在一个映射σ:M→S&#xff0c;使得对于M中的任意两个元素a、b&#xff0c;都有σ(ab)σ(a)σ(b)&#xff0c;则称σ为M到S的同态或群映射。 性质&#xff1a; 同…

微信小程序中点击搜素按钮没有反应,可能是样式问题(按钮被其他元素覆盖或遮挡)

文章目录 1. 确认 bindtap 绑定在正确的元素上2. 检查是否有遮挡或重叠元素3. 检查 this 上下文绑定问题4. 清除微信小程序开发者工具的缓存5. 用微信开发者工具查看事件绑定6. 确保 handleSearch 没有拼写错误进一步调试 1、searchResults.wxml2、searchResults.wxss3、search…

实验干货|电流型霍尔传感器采样设计03-信号调理

在前两篇博客中&#xff0c;将霍尔输出的电流信号转换成了有正有负的电压信号&#xff0c;但是DSP需要采集0~3V的电压信号&#xff0c;因此需要对信号缩放并抬升至全部为正的信号。 常见的方法是&#xff0c;通过比例放大(缩小)电路对信号进行放缩&#xff0c;通过加法电路抬升…