前言

随着Vue3的逐渐普及以及Vite的逐渐成熟,我们有必要来了解一下关于vite的本地构建原理。

对于webpack打包的核心流程是通过分析JS文件中引用关系,通过递归得到整个项目的依赖关系,并且对于非JS类型的资源,通过调用对应的loader将其打包编译生成JS 代码,最后再启动开发服务器。

了解到webpack的耗时主要花费在打包上,Vite选择跳过打包,直接以 原生 ESM 方式提供源码,这样岂不是可以非常快!

与webpack对比

Vite官网有两张对比图能够非常直观的对比两者的区别。

这张图代表的是基于打包器的构建方式(webpack就是其中之一),它在启动服务之前,需要从入口开始扫描整个项目的依赖关系,然后基于依赖关系构建整个应用生成bundle,最后才会启动开发服务器。 这就是这类构建方式为什么慢的原因,并且整个构建时间会随着项目的变大变的越来越长!

这张图代表的是基于ES Module的构建方式(比如:Vite),这张图是不是能够很直观说明为什么Vite会非常快,因为它上来就直接启动开发服务器,然后在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前页面上实际使用时才会被处理。

也就是它不需要扫描整个项目并且打包,不打包的话那它是如何让浏览器拿到分散在项目中的各个模块呢?

这一切都要得益于浏览器支持ESM的模块化方案,当浏览器识别到模块内的 ESM 方式导入的模块时,会自动去帮我们查找对应的内容

这就是为什么vite项目的模版文件中的script标签需要加上type=module,而webpack项目不需要。

<script type="module" src="/src/main.ts"></script>

vite快的原因

其实上面已经能够说明vite为什么会比webpack快了,但还有另外一个点在上图中并没有表现出来。

Vite会在一开始将项目中的所有模块分为源码依赖两类

  • 源码指的是我们自己写的代码,这类代码可能需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),并且时常会被编辑。Vite 会以 原生 ESM 方式提供源码,同时并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)。
  • 依赖大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)。Vite 将会使用 esbuild预构建依赖。esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

总结来说就是:基于ESM模块化方案 + 预构建

使用预构建的原因

Vite使用依赖预构建的原因主要有以下两点:

  • 兼容CommonJS与UMD:在开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将以 CommonJS 或 UMD 形式提供的依赖项转换为 ES 模块。
  • 性能:为了提高后续页面的加载性能,Vite将那些具有许多内部模块的 ESM 依赖项转换为单个模块。

可以来看个例子:

我们引入lodash-es工具包中的debounce方法,此时它理想状态应该是只发出一个请求

import  { debounce }  from 'lodash-es'

事实也是这样

但这是预构建的功劳,如果我们对lodash-es关闭预构建呢?

vite配置文件加上如下代码,再来试试:

// vite.config.js
optimizeDeps: {
exclude: ['lodash-es']
}

可以看到,此时发起了600多个请求,这是因为lodash-es 有超过 600 个内置模块!

vite通过将 lodash-es 预构建成单个模块,只需要发起一个HTTP请求!可以很大程度地提高加载性能

基本原理

跟着debug来一步一步看vite本地是如何工作的

首先从package.json出发,找到项目启动命令:

可以看到,dev对应的命令直接就是vite,然后我们再找到node_modules下面的vite下面的bin文件夹下面的vite.js文件,这就是vite运行的入口文件。

这里有一个start方法,从这打上断点开始慢慢往下走,就能够知道整个运行的基本原理

从上面我们知道,vite首先是会启动一个本地服务,基于该服务对文件的请求进行处理返回

接着往下走,我们可以看到有一个处理url的方法,此时运行栈里面的address变量也能够看到是127.0.0.1:5173,这就是我们等会要访问的本地服务,当然现在浏览器还什么也看不到,因为还没开始处理/路由,该路由需要返回一个html文件,也就是我们的模版文件(项目基于Vue3)

继续往下走,就可以看到有一个applyHtmlTransforms方法用来处理html文件并返回,可以看到当前请求的原始路径是/,返回的文件是项目根目录下的index.html文件

里面有一个脚本文件<script type="module" src="/src/main.ts"></script>,接下来就该请求并处理入口文件main.ts

main.ts文件如下:

import { createApp } from 'vue'
// import './style.css'
import { debounce } from 'lodash-es' console.log('--lodash--', debounce)
import App from './App.vue' createApp(App).mount('#app')

经过处理之后变成了:

它其实也没做啥处理,只是把依赖的引用路径处理成了预构建下的路径(.vite/deps/),把源码的引用路径处理成了绝对路径。

这里是不是会好奇,浏览器不是不能识别处理vue文件吗,这个不需要处理吗?(接着往下看!)

来看看此时浏览器中的加载顺序是怎样的吧:

整个文件的加载顺序是不是都对上了,注意看这个App.vue文件,虽然是.vue结尾,但文件类型依然是一个JavaScript文件

App.vue经过编译后文件类型已经转成JS了!

App.vue文件内容如下:

<script setup lang="ts">
import { ref } from 'vue'
const userName = ref('前端南玖')
</script> <template>
<div class="user_name">{{ userName }}</div>
</template> <style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

编译后:

再接着往下走,看下style被编译成了什么内容:

最后整个页面就可以渲染出来了!

总结

vite整体思路:启动一个 connect 服务器拦截由浏览器请求 ESM的请求。通过请求的路径找到目录下对应的文件做一下编译最终以 ESM的格式返回给浏览器。

对于node_modules下面的依赖,vite会使用esbuild进行预构建,主要是为了兼容CommonJS与UMD,以及提高性能。

这样完整走一遍,是不是对Vite的理解又更深一步了,它实际上就是“走一步看一步”,不像webpack上来就扫描整个项目进行打包编译,所以vite的构建速度会比较快!

了解完vite工作原理,我们是不是可以来实现一个简易的vite工具!

浅析Vite本地构建原理的更多相关文章

  1. Dockerfile多阶段构建原理和使用场景

    本文转载自Dockerfile多阶段构建原理和使用场景 导语 Docker 17.05版本以后,新增了Dockerfile多阶段构建.所谓多阶段构建,实际上是允许一个Dockerfile 中出现多个 ...

  2. .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理

    .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...

  3. Ubuntu系统下Jenkins的本地构建基本方法

    上一篇文章介绍了,jenkins的安装和系统配置之后,配置登录成功后,就可以新建jenkins构建项目,用于自动化构建. 1.项目名称和项目描述 点击左上角的 新建任务,输入项目名称,选择 构建一个自 ...

  4. Webpack探索【16】--- 懒加载构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack懒加载构建原理. 本文使用的 ...

  5. Webpack探索【15】--- 基础构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack模块构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack的基础构建原理. 本文使用的W ...

  6. NodeJS7-1本地构建_gulp入门学习

    NodeJS在前端最常用的两种方式: 1.做成webserver 2.做成前端开发的相关工具 本地构建:前端发布代码都会经过压缩(谁来处理) ,前端技术的日新月异,利用新特性代码变得易读,清晰,可是老 ...

  7. Linux centos 安装 jenkins & 本地构建jar & 远程构建jar

    一.部署 jenkins 需要的前奏 1.安装 JDK:https://www.cnblogs.com/chuyi-/p/10644440.html 2.安装tomcat:https://www.cn ...

  8. MySQL数据库本地事务原理

    在经典的数据库理论里,本地事务具备四大特征: 原子性 事务中的所有操作都是以原子的方式执行的,要么全部成功,要么全部失败: 一致性 事务执行前后,所有的数据都应该处于一致性状态---即要满足数据库表的 ...

  9. 使用Vite快速构建Vue3+ts+pinia脚手架

    一.前言 vue3的快速更新,很多IT发展快的地区在22开始都已经提上日程,小编所在的青岛好像最近才有点风波.vue3的人才在青岛还是比较稀缺的哈,纯属小编自己的看法,可能小编是个井底之蛙!! vue ...

  10. Docker镜像构建原理解析(不装docker也能构建镜像)

    在devops流程里面 构建镜像是一个非常重要的过程,一般构建镜像是写dockerfile文件然后通过docker client来构建的image. docker client 会先检查本地有没有im ...

随机推荐

  1. 2019-8-31-C#-获取进程退出代码

    title author date CreateTime categories C# 获取进程退出代码 lindexi 2019-08-31 16:55:58 +0800 2019-02-13 09: ...

  2. DE10-Lite加速度计使用教程

    DE10-Lite加速度计使用教程 1. 概述 DE10-Lite实验板上有一片5轴加速度计芯片ADXL345(通常称为G-sensor).它可以用来测量板子的倾斜角度.本文讲述如何以50次/秒的速度 ...

  3. 您可知道如何通过`HTTP2`实现TCP的内网穿透???

    可能有人很疑惑应用层 转发传输层?,为什么会有这样的需求啊???哈哈技术无所不用其极,由于一些场景下,对于一个服务器存在某一个内部网站中,但是对于这个服务器它没有访问外网的权限,虽然也可以申请端口访问 ...

  4. linux-centos7.6 硬盘挂载

    目录 一 .功能 二.VM中设置硬盘 2.1 系统关机状态下 2.2 添加硬盘 三.系统中挂载硬盘 3.1 查看硬盘信息 3.2 硬盘分区 3.3 格式化硬盘 3.4 临时挂载硬盘 3.4 开机自动挂 ...

  5. Threading Programming Guide:One

    苹果支持的产生线程的方式 Operation Object 使用OperationQueue,具体可以参考:Concurrency Programming Guide GCD 使用诸如dispatch ...

  6. ansible系列(32)--ansible实战之部署WEB集群架构(2)

    1. 基础环境role编写 创建基础环境role的相关目录: [root@xuzhichao cluster-roles]# mkdir base-module/{tasks,handlers,fil ...

  7. fastposter v2.9.2 最简海报生成器

    fastposter v2.9.2 程序员必备海报生成器 fastposter海报生成器是一款快速开发海报的工具.只需上传一张背景图,在对应的位置放上组件(文字.图片.二维.头像)即可生成海报. 点击 ...

  8. jeecgboot项目swagger2在线接口转word

    1.先找到接口文档地址 2.根据url获取接口数据 3.利用在线工具进行转换生成word 在线工具地址:在线swagger转word文档  生成的word文档如下:  

  9. 从需求角度介绍PasteSpider(K8S平替部署工具适合于任何开发语言)

    你是否被K8S的强大而吸引,我相信一部分人是被那复杂的配置和各种专业知识而劝退,应该还有一部分人是因为K8S太吃资源而放手! 这里介绍一款平替工具PasteSpider,PasteSpider是一款使 ...

  10. Android 13 - Media框架(12)- MediaCodec(二)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 前面一节我们学习了 MediaCodec 的创建以及配置过程,了解部分设计机制以及功能,这一节我们将继续学习其他方法. 1.start start ...