当你第一次运行vite,你可能会注意到这个消息:
代码语言:javascript复制Optimizable dependencies detected:
react, react-dom
Pre-bundling them to speed up dev server page load...
(this will be run only when your dependencies have changed)
为什么
这就是Vite执行的所谓的“依赖预绑定”。这个过程有两个目的:
CommonJS和UMD兼容性:在开发过程中,Vite的dev将所有代码作为本地ESM服务。因此,Vite必须首先将作为CommonJS或UMD发布的依赖项转换为ESM。
在转换CommonJS依赖时,Vite会执行智能导入分析,这样即使导出被动态分配(例如React),命名的导入也会像预期的那样工作:
代码语言:javascript复制// works as expected
import React, { useState } from 'react'
性能:Vite将ESM与许多内部模块的依赖关系转换为单个模块,以提高后续页面加载性能。
一些包将它们的ES模块构建作为许多单独的文件相互导入。例如,lodash-es有超过600个内部模块!当我们从'lodash-es'导入{debounce}时,浏览器会同时发出600多个HTTP请求!尽管服务器在处理这些请求时没有问题,但大量的请求会在浏览器端造成网络拥塞,导致页面加载明显变慢。
通过将lodash-es预绑定到单个模块中,我们现在只需要一个HTTP请求!
自动依赖发现
如果没有找到现有的缓存,Vite会抓取你的源代码,并自动发现依赖项导入(即:希望从node_modules解析的“裸导入”),并使用这些发现的导入作为预绑定包的入口点。预绑定是用esbuild执行的,所以它通常非常快。
在服务器已经启动之后,如果在缓存中没有遇到新的依赖项导入,Vite将重新运行dep绑定进程并重新加载页面。
Monorepos and Linked Dependencies
在monorepo设置中,一个依赖项可能是来自同一回购协议的链接包。Vite自动检测没有从node_modules解析的依赖项,并将链接的dep视为源代码。它不会尝试捆绑被链接的dep,而是会分析被链接的dep的依赖列表。
Customizing the Behavior
默认的依赖项发现启发式可能并不总是可取的。如果你想显式地从列表中包含/排除依赖项,使用optimizeDeps配置选项。
optimizeDeps的典型用例。包括或optimizeDeps。当您有一个不能直接在源代码中发现的导入时,就可以排除。例如,导入可能是插件转换的结果。这意味着Vite无法在初始扫描时发现导入-它只能在浏览器请求文件并进行转换后发现它。这将导致服务器在启动后立即重新绑定。
include和exclude都可以用来处理这个问题。如果依赖项很大(包含很多内部模块)或者是CommonJS,那么你应该包含它;如果依赖项很小,并且已经是有效的ESM,则可以排除它,让浏览器直接加载它。
Caching
文件系统缓存
在node_modules/.Vite中缓存预绑定的依赖项。它根据几个源来决定是否需要重新运行预绑定步骤:
您的package.json中的依赖项列表
包管理器锁定文件,例如package-lock.json,yarn.lock,或pnpm-lock.yaml。
只有当上面的一个步骤发生变化时,才需要重新运行预捆绑步骤。
如果出于某些原因,您想要强制Vite重新绑定deps,您可以使用--force命令行选项启动dev服务器,或者手动删除node_modules/.vite缓存目录。
浏览器缓存
解析后的依赖请求通过HTTP头max-age=31536000强缓存,不可变,以提高在开发期间的页面重载性能。一旦缓存,这些请求将永远不会再到达开发服务器。如果安装了不同的版本(反映在包管理器的lockfile中),则附加的版本查询会自动使它们失效。如果你想通过本地编辑来调试依赖项,你可以:
通过浏览器devtools的Network选项卡暂时禁用缓存;
重启Vite dev server,使用--force标志重新捆绑deps;
重新加载页面。