Vite2.0 依赖关系预捆绑

2021-03-16 15:21:31 浏览数 (2)

当你第一次运行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;

重新加载页面。

0 人点赞