深入了解Vite:依赖预构建原理

news/2024/9/24 2:22:50

前言

前面我们有提到Vite在开发阶段,提倡的是一个no-bundle的理念,不必与webpack那样需要先将整个项目进行打包构建。但是no-bundle的理念只适合源代码部分(我们自己写的代码),vite会将项目中的所有模块分为依赖源码两部分。

依赖: 指的是一些不会变动的一些模块,如:node_modules中的第三方依赖,这部分代码vite会在启动本地服务之前使用esbuild进行预构建。esbuild 使用 Go 编写,比使用 JavaScript 编写的打包器预构建依赖快 10-100 倍。

源码: 指的是我们自己开发时写的那部分代码,这部分代码可能会经常变动,并且一般不会同时加载所有源代码。

所以总结来说:no-bundle是针对源码的,而预构建是针对第三方依赖的

使用预构建的原因

主要有以下两点:

  • commonJS 与 UMD兼容:因为Vite在开发阶段主要是依赖浏览器原生ES模块化规范,所以无论是我们的源代码还是第三方依赖都得符合ESM的规范,但是目前并不是所有第三方依赖都有ESM的版本,所以需要对第三方依赖进行预编译,将它们转换成EMS规范的产物。

比如React,它就没有ESM的版本,所以在使用Vite时需要预构建

  • 性能: 为了提高后续页面的加载性能,Vite将那些具有许多内部模块的 ESM 依赖项转换为单个模块。

比如常用的loads-es

我们引入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请求!可以很大程度地提高加载性能

由于Vite的预构建是基于性能优异的Esbuild来完成的,所以并不会造成明显的打包性能问题

开启预构建

默认配置

一般来说,Vite帮我们默认开启了预构建

预构建产物会存放在:node_modules/.vite/deps

里面会有一个_metadata.json的文件,这里保存着已经预构建过的依赖信息

对于预构建产物的请求,Vite会设置为强缓存,有效时间为1年,对于有效期内的请求,会直接使用缓存内容

如果只有HTTP强缓存肯定也不行,如果用户更新了依赖版本,在缓存过期之前,浏览器拿到的一直是旧版本的内容。

所以Vite对本地文件也设置了缓存判断,如果下面几个地方任意一个地方有变动,Vite将会对依赖进行重新预构建:

  • 项目依赖dependencies变更

  • 各种包管理器的lock文件变更

  • optimizeDeps配置内容变更

自定义配置

entries

默认情况下,Vite会抓取项目中的index.html来检测需要预构建的依赖

optimizeDeps: {entries: ['index.html']
}

如果指定了 build.rollupOptions.input,Vite 将转而去抓取这些入口点。

exclude

排除需要预构建的依赖项

optimizeDeps: {exclude: ['lodash-es']
}

include

默认情况下,不在 node_modules 中的依赖不会被预构建。使用此选项可强制选择预构建的依赖项。

optimizeDeps: {include: ['lodash-es']
}

预构建流程

还是从源码入手,在启动服务的过程中会执行一个initDepsOptimizer表示初始化依赖优化

接着找到定义initDepsOptimizer方法的地方

在这里会执行createDepsOptimizer方法,再接着找到定义createDepsOptimizer的地方

这里首先会去执行loadCachedDepOptimizationMetadata用于获取本地缓存中的metadata数据

该函数会在获取到_metadata.json文件内容之后去对比lock文件hash以及配置文件optimizeDeps内容,如果一样说明预构建缓存没有任何改变,无需重新预构建,直接使用上次预构建缓存即可

如果没有缓存时则需要进行依赖扫描

这里主要是会调用scanImport方法,从名字也能看出该方法应该是通过扫描项目中的import语句来得到需要预编译的依赖

最终会返回一个prepareEsbuildScanner方法

最后该方法中会使用esbuild对扫描出来的依赖项进行预编译。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

在keil中使用git

目录搜集官方相关帮助1.application note2.软件附带帮助文件基础准备git命令行MDK版本操作步骤1.Abstract(摘要)2.Introduction3.Workflows3.1.Centralized Workflow4.Using Git with Vision4.1.Project Files under Version Control4.2.Files that do not need to be monitore…

1000多天我开发了一个免费的跨浏览器的书签同步、阅读排版、任意网页标注插件

自我介绍 大家好,我是阿浩,一位后端开发工程师,同时也略懂前端技术。业余时间,我开发了这款小工具——《藏趣云》。 我为什么要写这么个工具 需求来源于我自己,因为我是做开发的。我日常都会使用多款浏览器来测试项目,一次需要登录多个账号,寻找各种测试地址链接。之前因…

02-逻辑概述负判断

https://blog.csdn.net/vviccc/article/details/106694210 来源

信息学奥赛初赛天天练-83-NOIP2014普及组-基础题2-输入设备、输出设备、操作系统、二进制、整数除法、while、do while循环

1 NOIP 2014 普及组 基础题2 4 以下哪一种设备属于输出设备( ) A 扫描仪 B 键盘 C 鼠标 D 打印机 5 下列对操作系统功能的描述最为完整的是( ) A 负责外设与主机之间的信息交换 B 负责诊断机器的故障 C 控制和管理计算机系统的各种硬件和软件资源的使用 D 将没有…

webstorm使用缩写生成自定义注释

/** =========================$END$========================= **/$END$代表生成的时候光标在哪里 date怎么写? date("Y-MM-d HH:mm:ss")