当前位置: 欣欣网 > 码农

Vite 5.1 正式发布,性能大幅提升!

2024-02-08码农

去年 11 月,Vite 5 的发布标志着 Vite 及其生态系统再次取得了巨大的进步。而就在几周前,我们喜迎了 npm 每周下载量突破 1000 万次以及 Vite 仓库贡献者达到 900 名的里程碑。今天,Vite 5.1 版本正式发布了,本文就来看看该版本带来了哪些更新!

Vite 运行时 API

Vite 5.1 引入了实验性的 Vite 运行时 API 支持,允许通过 Vite 插件处理并运行任意代码。与 server.ssrLoadModule 不同,新 API 的运行时实现与服务器完全解耦,为库和框架开发者提供了在服务器与运行时之间实现自定义通信层的机会。一旦稳定,该 API 有望替代 Vite 当前的 SSR 基础组件。

这一新 API 带来了显著优势:

  • 支持在 SSR 期间进行 HMR(热更新),提升开发效率。

  • 由于与服务器解耦,单个服务器可支持无限量客户端,且每个客户端拥有独立的模块缓存,通信方式灵活多样(如消息通道、fetch 调用、直接函数调用或 WebSocket)。

  • 不依赖 node/bun/deno 等任何内置 API,因此具备跨环境运行的能力。

  • 轻松集成具有自定义运行代码机制的工具,例如通过提供运行器选择使用 eval 而非 new AsyncFunction。

  • 该创意最初由 Pooya Parsa 提出,并由 Anthony Fu 以 vite-node 包的形式实现,以支持 Nuxt 3 的开发环境 SSR,并随后成为 Vitest 的基础。经过一段时间的实战检验,Vladimir Sheremet 在 Vitest 中对 vite-node 进行了重新实现,并汲取经验,将 API 打造得更加强大和灵活,最终集成到 Vite Core 中。这个 PR 历时一年精心打磨,期间与生态系统维护者进行了深入的讨论和协作。

    新特性

    .css?url 的支持改进

    CSS 文件现在能够以更高的可靠性和准确性作为 URL 被导入,这一改进标志着 Remix 迁移到 Vite 过程中的最后一道障碍的克服。

    build.assetsInlineLimit 支持回调函数

    用户现在能够通过提供一个回调函数来进一步自定义资源内联的逻辑。该回调函数应返回一个布尔值,用以决定特定资源是否应被内联。若函数返回 undefined ,则默认逻辑将生效。

    循环导入的 HMR 优化

    在 Vite 5.0 中,循环导入中的已接受模块在发生更改时总是会触发整个页面的重新加载,即使这些模块在客户端能够无缝处理。现在,这一限制已被放宽,允许在不需重新加载整个页面的情况下应用 HMR。然而,如果在 HMR 过程中遇到任何错误,页面将重新加载以确保一致性。

    支持 ssr.external: true 实现全面外部化 SSR 包

    过去,Vite 会在服务器端渲染(SSR)时将除已链接包外的所有包外部化。现在,通过新引入的 ssr.external: true 选项,用户可以强制将所有包(包括已链接的包)都进行外部化处理。这一特性在单仓库(monorepo)环境中进行测试时显得尤为实用,因为它能模拟出所有包均被外部化的标准情况。此外,在通过 ssrLoadModule 加载任意文件时,始终将包外部化可以确保我们无需关注热更新(HMR)的实现细节。

    预览服务器新增 close 方法实现优雅关闭

    为了提升预览服务器的管理能力,现在服务器对象暴露了一个 close 方法。通过调用这个方法,用户可以优雅地关闭服务器,并确保所有已打开的套接字连接都被正确关闭。这一改进有助于提升服务器的稳定性和可维护性。

    性能提升

    随着每次版本的迭代,Vite 都在不断追求极致的速度。Vite 5.1 更是如此,带来了显著的性能改进。我们采用了 vite-dev-server-perf 工具来精准测量从 Vite 4.0 开始的所有次要版本在加载大量模块时的性能表现。测试环境包括了 10000 个模块和 25 级深度的模块树,每个模块都是一个包含计数器和导入其他文件的 TypeScript 文件。这样的设置确保了测试主要聚焦于请求各个模块所需的时间。

    在 Vite 4.0 中,加载 10000 个模块在 M1 MAX 设备上需要 8 秒。而在 Vite 4.3 中, Vite 团队专注于性能优化,成功地将加载时间缩短至 6.35 秒。如今,在 Vite 5.1 中,再次实现了性能的提升。Vite 仅需 5.35 秒就能加载这 10000 个模块,比 Vite 4.0 快了近 3 秒,比 Vite 4.3 也快了近 1 秒。这些成绩不仅验证了 Vite 无捆绑方法的优势,也彰显了 Vite 团队对性能持续优化的承诺。

    这个基准测试是在无头 Puppeteer 上运行的,是一个比较各个版本的好方法。但它并不代表用户实际体验到的时间。当在 Chrome 的隐身窗口中运行相同的 10000 个模块时,得到以下结果:


    10000 模块 Vite 5.0 Vite 5.1
    加载时间 2892ms 2765ms
    加载时间 (已缓存) 2778ms 2477ms
    完全重新加载 2003ms 1878ms
    完全重新加载(已缓存) 1682ms 1604ms

    在线程中运行 CSS 预处理器

    Vite 现在支持通过多线程运行 CSS 预处理器,从而极大提高了处理速度。通过简单地设置 css.preprocessorMaxWorkers: true 就可以启用这一功能。以 Vuetify 2 项目为例,启用此功能后,开发启动时间缩短了 40%。

    改进服务器冷启动的新策略

    对于大型项目,引入了一个新的依赖项优化策略。通过设置 optimizeDeps.holdUntilCrawlEnd: false ,可以切换到这一新策略,从而可能进一步提升依赖项的处理速度。Vite 团队正在考虑将此策略作为未来的默认设置。

    使用缓存加速解析

    为了提高解析速度,默认启用了 fs.cachedChecks 优化。在 Windows 环境下,这一优化使 tryFsResolve 的速度提升了约 14 倍,同时在三角形基准测试中,解析 ids 的总体速度也提高了约 5 倍。

    内部性能优化

    Vite 的开发服务器也在不断地进行内部性能优化。引入了新的中间件以在 304 响应时进行短路处理,避免了在热路径中进行不必要的请求解析,并确保了 Rollup 的正确惰性加载。这些改进共同提升了 Vite 的整体性能。

    弃用功能

    import.meta.glob 中的 'as' 选项已被弃用

    随着标准迁移到 Import Attributes, 'as' 选项在 import.meta.glob 中不再受支持。虽然目前不打算用新选项来替代它,但建议用户转而使用 query 功能。

    移除 Vite 3 中的实验性构建时预打包功能

    在 Vite 3 中引入的实验性构建时预打包功能现已被移除。随着 Rollup 4 切换到原生解析器,并且 Rolldown 项目正在积极推进中,该功能的性能以及开发和构建之间的一致性问题已不再有效。Vite 团队致力于改进开发/构建一致性,并认为在未来使用 Rolldown 进行「开发期间的预打包」和「生产构建」是更合适的策略。Rolldown 还可能以比依赖项预打包更高效的方式实现缓存。


    往期推荐