Vite使用Esbuild提升性能详解

目录
  • 前言
  • 初探 Esbuild
    • 关键 API - transfrom & build
    • plugin
  • Esbuild 在 Vite 中的巧妙使用
    • 预构建
    • middlewares 中内容转换
  • 结束语

前言

在上一篇 为什么有人说 vite 快,有人却说 vite 慢? 中,我们提到过开发模式下使用 Vite 会有首屏性能下降的负面效果。之所以会造成首屏性能下降,一方面是 dev server 需要完成预构建才可以响应首屏请求;另一方面是需要对请求文件做实时转换。

也许有的同学会问,是不是针对这两个方面做优化,就可以提升首屏性能呢?原则上这样是没有问题的,而且 Vite 也是这么做的。为了能提升性能,Vite 另辟蹊径的借助了 Esbuild 能快速完成项目打包、文件转换的能力来进行预构建、内容转换,效果非常好。

今天小编就通过本文和大家一起聊一聊 Vite 是怎样利用 Esbuild 来提升性能的。

初探 Esbuild

首先,小编先带大家简单了解一下 Esbuild,其官方地址是: Esbuild

什么是 Esbuild

Esbuild 是一款基于 Go 语言开发的 javascript 打包工具,最大的一个特征就是快。

通过官网提供的一张图,我们可以清晰的看到 Esbuild 的表现是多么优秀:

同样规模的项目,使用 Esbuild 可以将打包速度提升 10 - 100 倍,这对广大一直饱受 Webpack 缓慢打包速度折磨的开发人员来说,简直就是福音。

Esbuild 之所以能这么快,主要原因有两个:

  • Go 语言开发,可以多线程打包,代码直接编译成机器码;
  • Webpack 一直被人诟病构建速度慢,主要原因是在打包构建过程中,存在大量的 resolveloadtransformparse 操作(详见 为什么有人说 vite 快,有人却说 vite 慢?- 快速的冷启动 ),而这些操作通常是通过 javascript 代码来执行的。要知道,javascript 并不是什么高效的语言,在执行过程中要先编译后执行,还是单线程并且不能利用多核 cpu 优势,和 Go 语言相比,效率很低。
  • 可充分利用多核 cpu 优势;

关键 API - transfrom & build

Esbuild 并不复杂。它对外提供了两个 API - transformbuild,使用起来非常简单。

transfrom,转换的意思。通过这个 api,我们可以将 tsjsxtsx 等格式的内容转化为 jstransfrom 只负责文件内容转换,并不会生成一个新的文件。

build,构建的意思,根据指定的单个或者多个入口,分析依赖,并使用 loader 将不同格式的内容转化为 js 内容,生成一个或多个 bundle 文件。

这两个 API 的使用方式:

const res = await esbuild.transform(code, options) // 将 code 转换为指定格式的内容
esbuild.build(options) // 打包构建

关于使用 transformbuild 需要传入的具体配置项,本文就不详细说明了,官网对这一块儿有很详细的说明,感兴趣的同学可以去官网 - simple-optionsAdvanced options 看看,也可以自己动手试试。

plugin

WebpackRollup 等构建工具一样,Esbuild 也提供了供外部使用的 plugin,使得我们可以介入构建打包过程。

在这里要说明一点,只有 build 这个 API 的入参中可以配置 plugintransform 不可以。

一个标准的 plugin 的标准格式如下:

let customerPlugin = {
    name: 'xxx',
    setup: (build) => {
        build.onResolve({ filter: '', namespace: '' }, args => { ...});
        build.onLoad({ filter: '', namespace: ''}, args => { ... });
        build.onStart(() => { ... });
        build.onEnd((result) => { ... });
    }
}

其中,setup 可以帮助我们在 build 的各个过程中注册 hook

Esbuild 对外提供的 hook 比较简单,总共 4 个:

  • onResolve, 解析 url 时触发,可自定义 url 如何解析。如果 callback 有返回 path,后面的同类型 callback 将不会执行。所有的 onResolve callback 将按照对应的 plugin 注册的顺序执行。
  • onLoad, 加载模块时触发,可自定义模块如何加载。 如果 callback 有返回 contents,后面的同类型 callback 将不会执行。所有的 onLoad callback 将按照对应的 plugin 注册的顺序执行。
  • onStart, 每次 build 开始时都会触发,没有入参,因此不具有改变 build 的能力。多个 pluginonStart 并行执行。
  • onEnd, 每次 build 结束时会触发,入参为 build 的结果,可对 result 做修改。所有的的 onEnd 将按照对应的 plugin 注册的顺序执行。

正是有了 onResolveonLoadonStartonEnd,我们可以在 build 过程中的解析 url、加载模块内容、构建开始、构建结束阶段介入,做自定义操作。

Esbuild 在 Vite 中的巧妙使用

了解了 Esbuild 的基本用法以后,小编就带大家一起来看看 Vite 是怎么利用 Esbuild 来做预构建和内容转换的。

预构建

先来回顾一下为什么要做预构建。

原因有两点:

  • 将非 ESM 规范的代码转换为符合 ESM 规范的代码;
  • 将第三方依赖内部的多个文件合并为一个,减少 http 请求数量;

要完成预构建,最关键的两点是找到项目中所有的第三份依赖和对第三方依赖做合并、转换。借助 EsbuildVite 很轻松的实现了这两个诉求。

寻找第三方依赖

寻找第三方依赖的过程非常简单,分为两步:

定义一个带 onResolve hookonLoad hookesbuild plugin

执行 esbuildbuild 方法做打包构建;

WebpackRollupParcel 等构建工具一样,Esbuild 在做打包构建时也要构建模块依赖图 - module graph(具体过程可参考 为什么有人说 vite 快,有人却说 vite 慢?- 快速的冷启动 中 Webpack 构建 module graph)。

在构建 module graph 时,第一步就是解析模块的绝对路径,这个时候就会触发 onResolve hook。在 onResolve hook 触发时,会传入模块的路径。根据模块的路径,我们就可以判断出这个模块是第三方依赖还是业务代码。

举个 ,

// main.tsx
import react from 'react';
import CustomeComponent from './components/CustomeComponent';
...

在对 main.tsx 的内容做 parser 操作时,能知道 main.tsx 依赖 reactCustomeComponent,然后开始解析 reactCustomeComponent

解析 reactCustomeComponent 时,会触发 onResolve hook,入参分别为 'react' 和 './components/CustomeComponent'。

根据入参,我们可以很清楚的区分 'react' 是第三方依赖,'./components/CustomeComponet' 是业务代码。

这样,esbuild 完成构建,项目中的第三方依赖也就收集完毕了。所有的第三方依赖会收集到一个 deps 列表中。

  • 合并、转换第三方依赖
  • 知道了项目中的第三方依赖以后,再做合并、转换操作就非常简单了。
  • 这一步, Vite 直接通过 esbuild 提供的 build 方法,指定 entryPoints 为收集到的第三方依赖,formatesm,再做一次打包构建。
  • 这一次,会对第三方依赖做合并、转换操作。打包构建完成以后,再把构建内容输出到 /node_modules/.vite/deps 下。

这样,通过两次 esbuild.build,预构建就完成了。

middlewares 中内容转换

Vite 中源文件的转换是在 dev server 启动以后通过 middlewares 实现的。

当浏览器发起请求以后,dev sever 会通过相应的 middlewares 对请求做处理,然后将处理以后的内容返回给浏览器。

middlewares 对源文件的处理,分为 resolveloadtransformparser 四个过程:

  • resolve - 解析 url,找到源文件的绝对路径;
  • load - 加载源文件。如果是第三方依赖,直接将预构建内容返回给浏览器;如果是业务代码,继续 transformparser
  • transfrom - 对源文件内容做转换,即 ts -> js, less -> css 等。转换完成的内容可以直接返回给浏览器了。
  • parser - 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4
  • pre transformVite 做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。

Vite 在处理步骤 3 时,是通过 esbuild.transform 实现的,对比 Webpack 使用各个 loader 处理源文件,那是非常简单、快捷的。

结束语

有一说一,Vite 通过 Esbuild 来优化预构建和内容转换的思路非常棒,这给我们以后处理同类问题提供了解决方案,真心给尤大点

(0)

相关推荐

  • Vite vue3多页面入口打包以及部署踩坑实战

    目录 为什么需要多入口? 一.改造项目 二.vite.config.ts配置 三.部署 总结 为什么需要多入口? 公司原生的移动端上需要用webview引入一些性能要求不高的H5页面,初步考虑后选择用vue试个水,前期页面跳转选择使用vue-router,测试过程中在安卓高版本下右滑返回效果尚可,ios端初步尝试使用的最左侧touch事件移动距离检测以及router判断index添加过场动画,但是整体的效果依然达不到下图的效果. 原先项目中是使用多个html页面以及原生自带的协议去打开html,

  • vue使用vite配置跨域以及环境配置详解

    目录 如何配置跨域,代理域名 区分开发环境和生产环境,以及预发布环境 可以做什么事 补充:解决跨域常用方法 一.VUE中常用proxy来解决跨域问题 二.JSONP解决跨域 三.CORS是跨域资源共享(Cross-Origin Resource Sharing),以 ajax 跨域请求资源,支持现代浏览器,IE支持10以上 四.iframe实现跨域 总结 如何配置跨域,代理域名 不管使用什么脚手架,配置代理都是绕不开的话题,下面是vite的代理 server: { proxy: { '/api'

  • vite的搭建与使用的详细步骤

    目录 1.安装: 2.在vite项目中使用TypeScript 3.vite项目使用less sass scss 4.vite打包 5.下面就来创建一个标准的项目 实际开发中编写的代码往往是不能被浏览器直接识别的,比如ES6,TypeScript,Vue文件等.所以此时我们必须通过构建工具来对代码进行转换,编译,类似的工具有webpack,rollup,parcel.但是随着项目越来越大,需要处理的javascript呈指数级增长,模块越来越多.构建工具需要很长时间才能开启服务器,HMR也需要几

  • 使用Vite处理css less及postcss示例详解

    目录 1. css 2. less 3. postcss 4. 小结 1. css 当前,我们的 vite的基本使用 项目中是没有 css 代码的,但在真实的项目中,肯定会有 css 代码,那 Vite 能否帮助我们对 css 做支持呢?我们可以测试一下,在 src 目录下新建 css 文件夹,在 css 文件夹中新建 style.css 文件,内容如下: body { background-color: #f66; } 有了这个 css 文件后,先来思考一下,这个 css 文件现在有被打包吗?

  • 如何用Vite构建工具快速创建Vue项目

    目录 和Webpack相比,Vite具有以下特点 Vite构建Vue项目 构建过程可能会发生的一些问题 总结 和Webpack相比,Vite具有以下特点 1.快速的冷启动,不需要等待打包 2.即时的热模块更新,真正的按需编译,不用等待整个项目编译完成 Vite构建Vue项目 前提:安装Node.js和Vite 第一步通过npm创建Vite项目 npm init vite-app 项目名称 # 例如 npm init vite-app HelloVue 第二步当项目创建成功后,cd到项目目录 cd

  • vue3+vite使用jsx和tsx详情

    目录 安装@vitejs/plugin-vue-jsx 配置vite.config.js 使用实战 第一种写法使用this 第二种写法 第三种写法 安装@vitejs/plugin-vue-jsx yarn add -D @vitejs/plugin-vue-jsx npm i -D @vitejs/plugin-vue-jsx 配置vite.config.js ... import vueJsx from '@vitejs/plugin-vue-jsx'; export default def

  • Vite使用Esbuild提升性能详解

    目录 前言 初探 Esbuild 关键 API - transfrom & build plugin Esbuild 在 Vite 中的巧妙使用 预构建 middlewares 中内容转换 结束语 前言 在上一篇 为什么有人说 vite 快,有人却说 vite 慢? 中,我们提到过开发模式下使用 Vite 会有首屏性能下降的负面效果.之所以会造成首屏性能下降,一方面是 dev server 需要完成预构建才可以响应首屏请求:另一方面是需要对请求文件做实时转换. 也许有的同学会问,是不是针对这两个

  • php文件包含目录配置open_basedir的使用与性能详解

    1.open_basedir介绍 open_basedir 将php所能打开的文件限制在指定的目录树中,包括文件本身.当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查.当文件在指定的目录树之外,程序将拒绝打开. 本指令不受安全模式打开或关闭的影响. 2.open_basedir设置方法 1.在php.ini 加入 open_basedir="指定目录" 2.在程序中使用 ini_set('open_basedir', '指定

  • JavaScript中变量提升和函数提升的详解

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函数提升 3. 为什么要进行提升 4. 最佳实践 那么,我们就开始进入主题吧. 1. 变量提升 通常JS引擎会在正式执行之前先进行一次预编译,在这个过程中,首先将变量声明及函数声明提升至当前作用域的顶端,然后进行接下来的处理.(注:当前流行的JS引擎大都对源码进行了编译,由于引擎的不同,编译形式也会有

  • vite.config.js配置入门详解

    目录 1 如何创建vite项目? 2 如何让vite项目启动时自动打开浏览器? 3vite启动默认端口为3000?如何更改默认端口? 4 vite如何设置热更新? 5vite中如何配置别名路径? 6 vite中如何设置便捷图片路径引用? 7如何把vite打包以后的js,css和img资源分别分门别类在js/css/img文件夹中? 8 如何通过vite给项目配置多个环境? 9 vite中如何配置多入口,进行多页面开发? 10 如何设置开启生产打包分析文件大小功能?类似webpack-bundle

  • webpack项目中使用vite加速的兼容模式详解

    目录 前言 目的 要处理的问题 动手 共用 index.html 共用配置 兼容环境变量 自动导入 资源引入 svg-sprite-loader 替代方案 其他 效果 前言 随着公司前端工程越来越大,启动是无尽的等待,修改是焦急的等待. vite 到现在生态也起来了,就有了把项目改造成 vite 的想法,但是项目后面可能要依赖 qiankun 改造成微前端项目,现在 qiankun 对 vite 还没有好的解决方法,我就想采取一个折中的办法,保留 webpack,再兼容 vite,两条路都留着.

  • Vue3从0搭建Vite打包组件库使用详解

    目录 打包配置 声明文件 打包配置 本篇文章将介绍如何使用 vite 打包我们的组件库,同时告诉大家如何使用插件让打包后的文件自动生成声明文件(*.d.ts) vite 专门提供了库模式的打包方式,配置其实非常简单,首先全局安装 vite 以及@vitejs/plugin-vue pnpm add vite @vitejs/plugin-vue -D -w 在 components 文件下新建vite.config.ts配置文件 import { defineConfig } from "vit

  • React中immutable的UI组件渲染性能详解

    目录 引言 UI组件渲染性能 方案一:shallow compare 方案二:直接对前后的对象进行deepCompare 总结: 引言 react 一直遵循UI = fn(state) 的原则,有时候我们的state却和UI不同步 有时候组件本身在业务上不需要渲染,却又会再一次re-render.之前在项目中遇到的一些问题,这里做一个简单的分析,大家可以一起交流一下 UI组件渲染性能 react每次触发页面的更新可大致分成两步: render(): 主要是计算v-dom的diff commit阶

  • PHP7如何开启Opcode打造强悍性能详解

    前言 鸟哥在博客中说,提高PHP 7性能的几个tips,第一条就是开启opcache: 记得启用Zend Opcache, 因为PHP7即使不启用Opcache速度也比PHP-5.6启用了Opcache快, 所以之前测试时期就发生了有人一直没有启用Opcache的事情 那么什么是Opcache呢? Opcache 的前生是 Optimizer+ ,它是PHP的官方公司 Zend 开发的一款闭源但可以免费使用的 PHP 优化加速组件. Optimizer+ 将PHP代码预编译生成的脚本文件 Opc

  • .NET Core/Framework如何创建委托大幅度提高反射调用的性能详解

    前言 大家都知道反射伤性能,但不得不反射的时候又怎么办呢?当真的被问题逼迫的时候还是能找到解决办法的. 反射是一种很重要的技术,然而它与直接调用相比性能要慢很多,因此如何优化反射性能也就成为一个不得不面对的问题. 目前最常见的优化反射性能的方法就是采用委托:用委托的方式调用需要反射调用的方法(或者属性.字段). 为反射得到的方法创建一个委托,此后调用此委托将能够提高近乎直接调用方法本身的性能.(当然 Emit 也能够帮助我们显著提升性能,不过直接得到可以调用的委托不是更加方便吗?) 性能对比数据

  • 使用v-memo缓存模板子树提高应用性能详解

    目录 引言 v-memo 是做什么的? 事例 错误的使用方式 管理更新 与 v-for 结合使用 无意中停止了子组件触发的更新 总结 引言 Vue3 为我们提供了几项开箱即用的重大性能改进,但也引入了一些额外的手动功能,可以帮助提高我们的应用性能. 在这节课中,我们介绍一下,在 Vue 3.2 中引入新指令 v-memo.引入这个指令的目的是帮助我们提高中型/大型 Vue 应用程序的性能,小项目大家根据需要自行决定. v-memo 是做什么的? 官网对 v-memo 定义是这样的: 缓存一个模板

随机推荐