Vite 双引擎架构 —— Esbuild 概念篇
Vite 底层采用 双引擎架构,核心构建引擎是 Esbuild 和 Rollup,二者在开发和生产环境中分工协作,共同实现高性能构建。不可否认,作为 Vite 的双引擎之一,Esbuild 在很多关键的构建阶段(如依赖预编译
、TS 语法转译
、代码压缩
)让 Vite 获得了相当优异的性能,是 Vite 高性能的得力助手。无论是在 Vite 的配置项还是源码实现中,都包含了不少 Esbuild 本身的基本概念和高阶用法。因此,要深入掌握 Vite,学习 Esbuild 必不可少。
本篇文章我将由 Esbuild 开始,讲解 Vite 强大的双引擎结构。强烈建议上手操作,读两三遍,不如上手写一遍 。《esbuild 中文文档》
🔍 一、为什么 Esbuild 的性能极高?
极速构建:
- 性能碾压传统工具:基于 Go 语言编写,多进程并行处理,比 Webpack/Rollup 快 10-100 倍(10个 three.js 副本打包仅需 0.39秒 vs Webpack 的 41秒) 。
- 无缓存仍高效:内置优化算法,无需依赖缓存即可实现秒级编译 。
开箱即用的支持:
- 语言支持:原生处理 JS、TS、JSX、CSS(含 CSS Modules),无需额外配置 。
- 模块化:无缝捆绑 ESM 和 CommonJS 模块,自动树摇(Tree Shaking) 。
多场景适配:
- 浏览器环境:默认输出浏览器兼容代码,支持
--minify
压缩、--sourcemap
源码映射 。 - Node 环境:通过
--platform=node
打包,剥离 TS 类型、转换 ESM→CommonJS 。
🛠️ 二、 Esbuild 安装与使用
npm install esbuild # 或 yarn add esbuild
1. 命令行调用
命令行方式调用也是最简单的使用方式。我们先来写一些示例代码,新建src/index.jsx
文件,内容如下:
import Server from "react-dom/server";let Greet = () => <h1>祝所有高三的同学,金榜题名!</h1>;
console.log(Server.renderToString(<Greet />));
注意安装一下所需的依赖,在终端执行如下的命令:
npm install react react-dom
接着到package.json
中添加build
脚本:
"scripts": {"build": "esbuild src/index.jsx --bundle --outfile=dist/out.js",},
现在,你可以在终端执行npm run build
,可以发现如下的日志信息:
接着我们就可以看到dish目录中的打包产物
说明我们已经成功通过命令行完成了 Esbuild 打包!但命令行的使用方式不够灵活,只能传入一些简单的命令行参数,稍微复杂的场景就不适用了,所以一般情况下我们还是会用代码调用的方式。
2. 代码调用
Esbuild 对外暴露了一系列的 API,主要包括两类: Build API
和Transform API
,我们可以在 Nodejs 代码中通过调用这些 API 来使用 Esbuild 的各种功能。想要更全面的了解的,可以去访问文章开头的文档地址。
项目打包——Build API
Build API
主要用来进行项目打包,包括build
、buildSync
和 serve
三个方法。
A、build
方法:异步打包
功能:执行异步构建任务,返回 Promise 对象,支持插件和并行操作。
适用场景:生产环境打包、复杂构建流程(如代码分割、压缩)。
首先我们来试着在 Node.js 中使用build
方法。你可以在项目根目录新建build.js
文件,内容如下:
import { build } from 'esbuild';async function runBuild() {// 异步方法,返回一个 Promiseconst result = await build({// ---- 如下是一些常见的配置 --- // 当前项目根目录absWorkingDir: process.cwd(),// 入口文件列表,为一个数组entryPoints: ["./src/index.jsx"],// 打包产物目录outdir: "dist",// 是否需要打包,一般设为 truebundle: true,// 模块格式,包括`esm`、`commonjs`和`iife`format: "esm",// 需要排除打包的依赖列表external: [],// 是否开启自动拆包splitting: true,// 是否生成 SourceMap 文件sourcemap: true,// 是否生成打包的元信息文件metafile: true,// 是否进行代码压缩minify: false,// 是否开启 watch 模式,在 watch 模式下代码变动则会触发重新打包watch: false,// 是否将产物写入磁盘write: true,// Esbuild 内置了一系列的 loader,包括 base64、binary、css、dataurl、file、js(x)、ts(x)、text、json// 针对一些特殊的文件,调用不同的 loader 进行加载loader: {'.png': 'base64',}});console.log(result);
}runBuild();
随后,你在命令行执行node build.js
,就能在控制台发现如下日志信息:
接着我们就可以看到dish目录中的打包产物和相应的 SourceMap 文件
B、buildSync
方法:同步打包 (不推荐)
功能:同步执行构建任务,立即返回结果,但阻塞主线程。
适用场景:小型项目、简单脚本或 CLI 工具。
一个简单的例子:
const result = esbuild.buildSync({entryPoints: ['app.js'],bundle: true,outfile: 'out.js',platform: 'node' // 指定 Node 环境
});if (result.errors.length > 0) {throw new Error('Build failed');
}
局限性:
- 性能影响:阻塞主线程,可能导致界面卡顿
- 插件限制:Rollup 等工具的
buildSync
不支持插件 - 适用性:仅推荐在轻量任务中使用
难道就不能使用同步打包了吗?? 如果说有,其实也是有的
使用 build
+ await
实现伪同步:
async function runBuild() {await esbuild.build({ /* 配置 */ });
}
C、serve
方法:开发服务器
这个 API 有 3 个特点。
-
开启 serve 模式后,将在指定的端口和目录上搭建一个
静态文件服务
,这个服务器用原生 Go 语言实现,性能比 Nodejs 更高。 -
类似 webpack-dev-server,所有的产物文件都默认不会写到磁盘,而是放在内存中,通过请求服务来访问。
-
每次请求到来时,都会进行重新构建(
rebuild
),永远返回新的产物。
下面,我们通过一个具体例子来感受一下。
// build.js
import { serve } from 'esbuild';function runBuild() {serve({port: 8000,servedir: './dist',onRequest: (args) => {if (args.path === '/') {args.path = '/index.html'}}},{absWorkingDir: process.cwd(),entryPoints: ["./src/index.jsx"],bundle: true,format: "esm",splitting: true,sourcemap: true,outdir: "dist",loader: {'.js': 'jsx','.png': 'file','.jpg': 'file'}}).then((server) => {console.log("HTTP Server starts at port", server.port);});
}runBuild();
1.运行构建命令
npm run build
2.启动服务器
node build.js
我们在浏览器访问http://localhost:8000/dist/index.js可以看到 Esbuild 服务器返回的编译产物如下所示:
后续每次在浏览器请求都会触发 Esbuild 重新构建,而每次重新构建都是一个增量构建的过程,耗时也会比首次构建少很多(一般能减少 70% 左右)。
Serve API 只适合在开发阶段使用,不适用于生产环境。
单文件转译——Transform API
功能:对单个字符串内容进行转换(如转译 TS/JSX),不访问文件系统,适用于非文件环境(如浏览器内联处理)或作为工具链一环。
与 Build API
类似,它也包含了同步和异步的两个方法,分别是transformSync
和transform
。
举例栗子:在项目根目录新建transform.js
,
// transform.js
import { transform, transformSync } from 'esbuild';async function runTransform() {// 第一个参数是代码字符串,第二个参数为编译配置const content = await transform("const isNull = (str: string): boolean => str.length > 0;",{sourcemap: true,loader: "tsx",});console.log(content);
}runTransform();
终端输入:
node transform.js
接着你就会看见:
同样的步骤,传参:
// transform.js
import { transform, transformSync } from 'esbuild';async function runTransform(code = "const isNull = (str: string): boolean => str.length > 0;") {// 第一个参数是代码字符串,第二个参数为编译配置const content = await transform(code,{sourcemap: true,loader: "tsx",});console.log(content);
}const inputCode = process.argv[2];
runTransform(inputCode).catch(console.error);
终端输入:
node transform.js "const add = (a: number, b: number): number => a + b;"
打印出:
由于同步的 API 会使 Esbuild 丧失并发任务处理
的优势(Build API
的部分已经分析过),我同样也不推荐大家使用transformSync
。出于性能考虑,Vite 的底层实现也是采用 transform
这个异步的 API 进行 TS 及 JSX 的单文件转译的。
📊 三、总结
Esbuild的优势在于编译速度非常快,且拥有Go语言的优势,Go语言编写的程序比JavaScript少了一个动态解释的过程;在代码实现上,Esbuild使用比较克制,很多在Webpack上使用插件实现的功能如loader、minify等均使用Go实现。;劣势在于支持不完善,提供的功能很基础,对代码分割和css处理等支持较弱。
✅ 优势
- 速度为王:Go 语言 + 并行处理 + 内置功能(减少 AST 转换链) 。
- 轻量 API:提供 CLI、JS、Go 三种接口,配置简洁 。
- 生产优化:默认支持 Tree Shaking、代码压缩、Source Map 。
❌ 局限性
1.生态插件较弱
- 不支持 Vue/Sass/Less 等语法,需 JS 插件(性能下降) 。
- 无热更新(HMR),依赖
--watch
或手动重启 。
2.高级功能缺失
- 无 AST 操作接口,无法实现类 Babel 按需引入 。
- 代码分割(Code Splitting)对非 ESM 包支持差 。
但是不可否认,它的作用和潜力,我相信 Esbuild 未来在持续迭代中, 生态完善后或颠覆前端构建范式。
相关文章:

Vite 双引擎架构 —— Esbuild 概念篇
Vite 底层采用 双引擎架构,核心构建引擎是 Esbuild 和 Rollup,二者在开发和生产环境中分工协作,共同实现高性能构建。不可否认,作为 Vite 的双引擎之一,Esbuild 在很多关键的构建阶段(如依赖预编译、TS 语法转译、代码…...
Life:Internship finding
1. 前言 fishwheel writes this Blog to 记录自分自身在研二下找实习的经历。When 写这篇 Blog 的时候我的最后一搏也挂掉了,只能启用保底方案了。When I 打开我的邮箱时,发现里面有 nearly 100 多封与之相关的邮件,顿时感到有些心凉&#x…...

阿里云Alibaba Cloud安装Docker与Docker compose【图文教程】
个人记录 进入控制台,找到定时与自动化任务 进入‘安装/卸载扩展程序’ 点击‘安装扩展程序’ 选择docker社区版,点击下一步与确定,等待一会 安装成功 查询版本 查询docker sudo docker version查询docker compose sudo docker compo…...
GitHub 趋势日报 (2025年06月07日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 603 netbird 459 dify 440 cognee 352 omni-tools 337 note-gen 239 ragbits 237 …...
Java编程之组合模式
引言 在软件开发的世界里,我们经常会遇到需要表示"部分-整体"层次结构的场景。比如文件系统中的文件和文件夹、图形界面中的各种组件、企业组织架构中的部门和员工等。这些场景都有一个共同的特点:我们需要以一种统一的方式来处理单个对象和由…...
Oracle 19c RAC集群ADG搭建
1、将主库的pfile和passwdfile发送到备库 #主库一节点操作 scp -P1234 /tmp/pfile2025.ora bak_ip:/home/oracle sco -P1234 /oracle/app/oracle/product/19.0.0/db/dbs/orapw$ORACLE_SID bak_ip:/oracle/app/oracle/product/19.0.0/db/dbs 2、备库修改参数文件成standby相关…...

ADB识别手机系统弹授权框-如何处理多重弹框叠加和重叠问题
ADB识别手机系统弹授权框-如何处理多重弹框叠加和重叠问题 --蓝牙电话SDK自动部署 上一篇:手机App-插入USB时自动授权点击确定按钮-使系统弹出框自动消失 下一篇:编写中。 一、前言 我们在上一篇《手机App-插入USB时自动授权点击确定按钮-使系统弹出框…...
Kaggle-Predicting Optimal Fertilizers-(多分类+xgboost+同一特征值多样性)
Predicting Optimal Fertilizers 题意: 给出土壤的特性,预测出3种最佳的肥料 数据处理: 1.有数字型和类别型,类别不能随意换成数字,独热编码。cat可以直接处理category类型。 2.构造一些相关土壤特性特征 3.由于la…...

uniapp+<script setup lang=“ts“>解决有数据与暂无数据切换显示,有数据加载时暂无数据闪现(先加载空数据)问题
声明showEmpty 为false,在接口返回处判断有数据时设置showEmpty 为false,接口返回数据为空则判断showEmpty 为true (这样就解决有数据的时候会闪现暂无数据的问题啦) <!--* Date: 2024-02-26 03:38:52* LastEditTime: 2025-06…...

详解鸿蒙Next仓颉开发语言中的动画
大家上午好,今天来聊一聊仓颉开发语言中的动画开发。 仓颉中的动画通常有两种方式,分别是属性动画和显示动画,我们今天以下面的加载动画为例,使用显示动画和属性动画分别实现一下,看看他们有什么区别。 显示动画 显示…...

Redis常见使用场景解析
1. 数据库缓存 Redis 作为典型的 Key-Value 型内存数据库,数据缓存是其最广为人知的应用场景。使用 Redis 缓存数据操作简便,通常将序列化后的对象以 string 类型存储。但在实际应用中,需注意以下关键要点: Key 设计:必须确保不同对象的 Key 具有唯一性,且尽量缩短长度,…...
C语言指针与数组sizeof运算深度解析:从笔试题到内存原理
前两天跟着数组指针的教程: // #self 视频里的笔试题 !!!vipint b12[3][4] {0};printf("%ld \n", sizeof(b12[0]));printf("%ld \n", sizeof(*b12));printf("%ld \n", sizeof(*(b12 1)));printf("%ld \n", sizeof(*(&am…...

起重机指挥人员在工作中需要注意哪些安全事项?
起重机指挥人员在作业中承担着协调设备运行、保障作业安全的关键职责,其安全操作直接关系到整个起重作业的安全性。以下从作业前、作业中、作业后的全流程,详细说明指挥人员需注意的安全事项: 一、作业前的安全准备 资质与状态检查ÿ…...
JVM内存区域与溢出异常详解
当然可以。以下是结合了程序计数器和Java内存区域以及内存溢出异常的详细解释: JVM内存区域与内存溢出异常 Java虚拟机(JVM)管理着不同类型的内存区域,每个区域都有其特定的功能和可能导致的内存溢出异常。 程序计数器ÿ…...
ES海量数据更新及导入导出备份
一、根据查询条件更新字段 from elasticsearch import Elasticsearch import redis import json# 替换下面的用户名、密码和Elasticsearch服务器地址 username elastic password password es_host https://127.0.0.2:30674# 使用Elasticsearch实例化时传递用户名和密码 es…...
Java线程池核心原理与最佳实践
Java 线程池详解 线程池是Java并发编程的核心组件,它能高效管理线程生命周期,避免频繁创建销毁线程的开销,提升系统性能和资源利用率。 一、线程池核心优势 降低资源消耗:复用已创建的线程,减少线程创建销毁开销提高…...

JAVA-springboot log日志
SpringBoot从入门到精通-第8章 日志的操作 一、Spring Boot默认的日志框架 SpringBoot支持很多种日志框架,通常情况下,这些日志框架都是由一个日志抽象层和一个日志实现层搭建而成的,日志抽象层是为记录日志提供的一套标准且规范的框架&…...

1.springmvc基础入门(一)
1.Spring MVC概念 Spring MVC 是 Spring Framework 提供的 Web 组件,全称是 Spring Web MVC,是⽬前主流的实现 MVC 设计模式的框架,提供前端路由映射、视图解析等功能。 Java Web 开发者必须要掌握的技术框架。 2.Spring MVC 功能 MVC&am…...
AI 时代下语音与视频伪造的网络安全危机
引言 在人工智能技术的推动下,语音合成、视频生成等技术取得了突破性进展,Deepfake、AI 语音克隆等工具让语音和视频伪造变得愈发简单且逼真。这些技术在娱乐、影视等领域带来便利的同时,也被不法分子利用,引发了一系列网络安全问…...

模块缝合-把A模块换成B模块(没写完)
把MLP Head替换为KAN 1.在model文件下新建一个python文件 2.把 模块文件里的整个KAN代码复制到新的python文件中 3.在开头导入 from model.KAN(新建文件名) import KAN(新建文件中的类名) 4.sys.path.append(r"D: Icode(Kansformer"…...

从零开始学Flink:揭开实时计算的神秘面纱
一、为什么需要Flink? 当你在电商平台秒杀商品时,1毫秒的延迟可能导致交易失败;当自动驾驶汽车遇到障碍物时,10毫秒的计算延迟可能酿成事故。这些场景揭示了一个残酷事实:数据的价值随时间呈指数级衰减。 传统批处理…...
一、ES6-let声明变量【解刨分析最详细】
一、块级作用域 { let Tim"Tim是靓仔!" } console.log("Tim:",Tim) 打印结果:Tim未进行任何定义! 原因:因为Tim定义再块级{}里面,它的声音Tim只服务于该块级里面。而打印结果是再块级外面&#…...

Appium如何支持ios真机测试
ios模拟器上UI自动化测试 以appiumwebdriverio为例,详细介绍如何在模拟器上安装和测试app。在使用ios模拟器前,需要安装xcode,创建和启动一个simulator。simulator创建好后,就可以使用xcrun simctl命令安装被测应用并开始测试了。…...

JDK17 Http Request 异步处理 源码刨析
为什么可以异步? #调用起始源码 // 3. 发送异步请求并处理响应 CompletableFuture future client.sendAsync( request, HttpResponse.BodyHandlers.ofString() // 响应体转为字符串 ).thenApply(response -> { // 状态码检查(非200系列抛出异常&…...

【Zephyr 系列 8】构建完整 BLE 产品架构:状态机 + AT 命令 + 双通道通信实战
🧠关键词:Zephyr、BLE、状态机、双向透传、AT 命令、Buffer、主从共存、系统架构 📌适合人群:希望开发 BLE 产品(模块/标签/终端)具备可控、可测、可维护架构的开发者 🧭 引言:从“点功能”到“系统架构” 前面几篇我们已经逐步构建了 BLE 广播、连接、数据透传系统…...

【Mac 从 0 到 1 保姆级配置教程 16】- Docker 快速安装配置、常用命令以及实际项目演示
文章目录 前言1. Docker 是什么?2. 为什么要使用 Docker? 安装 Docker1. 安装 Docker Desktop2. 安装 OrbStack3. Docker Desktop VS OrbStack5. 验证安装 使用 Docker 运行项目1. 克隆项目到本地2. 进入项目目录3. 启动容器: 查看运行效果1. OrbStack 中…...

2025-05-01-决策树算法及应用
决策树算法及应用 参考资料 GitHub - zhaoyichanghong/machine_learing_algo_python: implement the machine learning algorithms by p(机器学习相关的 github 仓库)决策树实现与应用决策树 概述 机器学习算法分类 决策树算法 决策树是一种以树状结构对数据进行划分的分类…...

Redis知识体系
1. 概述 本文总结了Redis基本的核心知识体系,在学习Redis的过程中,可以将其作为学习框架,以此更好的从整体的角度去理解和学习Redis的内容和设计思想。同时知识框架带来的好处是可以帮助我们更好的进行记忆,在大脑中形成相应的知识…...

mysql-MySQL体系结构和存储引擎
1. MySQL体系结构和存储引擎 MySQL被设计成一个单进程多线程架构的数据库,MySQL数据库实例在系统上的表现就是一个进 程当启动实例时,读取配置文件,根据配置文件的参数来启动数据库实例;若没有,按编译时的默认 参数设…...
Pycharm 函数注释
1 Docstring format File -> Settings -> Tools -> Python Integrated Tools -> Docstrings -> Docstring format,选择google File -> Settings -> Editor -> General -> Smart Keys -> Insert type placeholders in the documenta…...