大家好我是Fly. 最近一直着手组内基建活动, 目前正在做的事组件库的技术文档搭建, 最终还是弃用dumi, 选用了storybook 作为组件库文档的技术方案, 主要是我们项目架构 本身就是自己去搭建的, 没有采用umi 那一套, umi对我们来说太重了, 本身的打包配置分为node 和 web的, 本身就是webpack 5去构建的, 主要是想复用一些webpack的配置。 想着组件库采用 vite 去打包的时候,看了一些文档, webpack5 的 lazyCompilation 配合 code spliting 本身的开发速度和hmr 启动 整体和vite 的体验是差不多的, 甚至在第一次加载是比vite 更快的。最终的建议是(个人看法,不喜勿喷),有下面三条
- 如果你项目架子本身就是依赖于umi的 可以使用 dumi 去做项目搭建
- 如果你是webpack4 建议升级到 webapck5 ,不然 你体会不到webpack5 带来的快速发展模式
- 如果你是新项目,可以采用 vite 作为构建工具
storybook
Storybook 是行业标准的 UI 组件工作室。全球数以千计的应用程序和设计系统团队大部分时间都在 Storybook 中工作——构建、记录和测试他们的 UI 组件。因此,Storybook 需要尽可能快地运行,这样才不会减慢他们的工作流程。Storybook 在首次启动或重建更改的文件时的性能很大程度上取决于它如何捆绑故事和组件。优化构建过程为 Storybook 中的性能提升提供了很多机会。Webpack 和 Vite 构建器的改进是这一更大的持续优化工作的一部分。本文着眼于帮助您获得当今最快的开发体验的选项。我们将检查升级到 Webpack 5 的影响,启用代码拆分或惰性编译等功能,最后切换到 Vite 构建器。Storybook 致力于为 Vite 项目提供一流的支持,获得我们的性能基准是进一步优化的第一步。
Storybook builders
Storybook 由 Webpack 等构建器提供支持,它们处理和捆绑您的代码——Javascript、TypeScript、CSS、MDX,甚至是特定于框架的模块,如 Vue 或 Svelte SFC
目前,Webpack 是 Storybook 的默认构建器。Storybook 使用 Webpack 编译自己的 UI(侧边栏、面板、按钮等)和预览(您的故事和文档页面)。使用 Storybook 6.4 及更高版本,可以切换到 @storybook/builder-vite 以使用 Vite 而不是 Webpack 构建预览。
Storybook Vite Builder
Vite 是下一代构建工具,旨在提供更快、更精简的开发体验。它不是将整个项目捆绑成一个或多个块,而是在开发过程中为浏览器提供单独的 ES 模块。这使它几乎可以立即启动。然后,当您更新代码时,热模块替换 (HMR) 只需要替换一个小文件,而不是重新捆绑整个应用程序,从而使重建速度快如闪电。使用 Storybook Vite Builder 时,您将能够使用与您的应用相同的 Vite 插件和配置,并继续利用 Storybook 插件生态系统。那么,在 Vite 承诺如此出色的性能的情况下,Webpack 是否已经过时了?好吧,等等,Storybook 团队也一直在努力提高 Webpack 的性能。他们引入了惰性编译等功能以加快开发性能,并引入了按需架构以通过利用代码拆分来减少初始加载时间。让我们看看这些变化是否足以匹配 Vite 在真实 Storybook 项目中的性能。
使用 IBM Carbon Design System 对 Storybook 性能进行基准测试
为了比较这两个构建器的性能,我选择针对 IBM 的 Carbon Design System 运行基准测试。Carbon 有一个相对较大的 Storybook,包含 100 多个 React 组件和 250 个使用 CSF 和 MDX 格式混合的故事。Carbon 使用 Webpack 5,但不使用惰性编译或代码拆分功能。它的配置与 Webpack 没有紧密耦合,允许相当直接地迁移到 Vite Builder。这只是一个示例项目,这些结果可能与您在自己的项目中看到的不同。性能是一个复杂的话题,可能会受到许多因素的影响,但 Carbon 项目中的结果说明了 Storybook 构建器选项之间的一些有趣差异。
在深入研究结果之前,让我解释一下我是如何运行这些基准测试的。我使用@storybook/bench 来全面了解构建者之间的性能差异。它测量开发服务器启动并在浏览器中呈现故事的总时间、创建生产构建所需的时间以及浏览器为已发布的 Storybook 呈现第一个故事所需的时间。我还计算了编辑文件和使用 HMR 在浏览器中重新渲染故事之间的总时间。我在我的 2019 Intel Macbook Pro 上每次都取了五个样本的平均值。我比较了五种不同 Storybook 构建器配置的结果
- Webpack 4
- Webpack 5
- Webpack 5 LC/CS (lazy compilation & code-splitting enabled)
- Vite
- Vite CS (code-splitting enabled)
Storybook 可以通过两种不同的方式构建您的应用程序。当您在开发期间处理它时,您必须等待故事书开发服务器启动并打开带有您的故事的浏览器。完成后,Storybook 会运行生产版本,因此您可以在 CI 中运行测试并发布到 Web。每次保存时,Storybook 还会在您处理故事时重建您的故事,因此我们也会看看这需要多长时间。
冷启动
我们将检查的第一个场景是开发服务器的冷启动。这是您在第一次运行 start-storybook 和故事加载到浏览器中之间等待的时间。使用默认配置的 Carbon 项目(没有代码拆分或延迟编译的 Webpack 5)需要 61 秒来启动开发服务器并在浏览器中呈现故事,这与使用 Webpack 4 的时间大致相同。但是,启用延迟编译会减少那个时间在半到30秒。
Vite 本来就是闪电般的速度,但令人惊讶的是它在首页加载时速度较慢。发生了什么?请记住,Vite 将每个模块未捆绑发送到浏览器,因此即使开发服务器快速启动,浏览器也需要更多时间来下载和处理所有这些请求。相比之下,Webpack 向浏览器发送了 16 到 33 个资产,如果未启用代码拆分,Vite 发送的资产高达 1,060 个。启用代码拆分 (storyStoreV7) 将该数字大大减少到 250,我们看到速度有所提高,尽管启动仍然比启用延迟编译的 Webpack 5 稍慢
使用缓存进行开发(热启动)
第一次运行后,Storybook 会缓存一些构建工件,因此后续启动会更快。我们在这里看到的构建时间确实更快,而且同样的模式也适用。带有惰性编译的 Webpack 5 在第一个故事加载前 11 秒占据了优势,紧随其后的是 Vite,代码拆分需要 15 秒。基线 Webpack 4 和 Webpack 5 配置花了将近半分钟。
生产构建时间
要在线发布您的 Storybook,您需要使用 build-storybook 将其构建为静态 Web 应用程序。与本地开发不同,生产构建不需要 HMR。因此,Vite 不是为单个模块提供服务,而是将所有内容捆绑在一起,类似于 Webpack。在底层,它使用 Rollup 和自以为是的配置来完成这项任务。在这里,我们也发现 Vite 比 Webpack 需要更长的时间来捆绑资产。
Vite 使用 Rollup 来执行比 Webpack 更激进的死代码消除(摇树),这就是为什么创建生产构建需要更长的时间。但是,权衡是它会生成更小的捆绑包,如下图所示。一般来说,这意味着由 Vite 捆绑用于生产的 Storybook 对最终用户的加载速度会稍快一些,并且比使用标准 Webpack 4 或 5 配置生成的 Storybook 需要的带宽更少。
惰性编译是仅开发模式的功能,但 Webpack 5 LC/CS 构建也使用代码拆分,这解释了上面看到的较小请求大小。还要记住,虽然代码拆分可以更快地加载第一页,但导航到其他故事可能需要稍长一些,因为每次请求和下载更多的 javascript。
Webpack 的延迟编译将刷新时间缩短到只有一秒,但这仍然是 Vite 的两倍。这些看似很小的数字,但它们加起来会产生很大的不同。使用 Vite 时,您的更改似乎会立即发生,让您在构建组件时保持思路并快速迭代。
Vite 具有闪电般的快速重建时间,但您必须启用代码拆分功能才能获得全部好处并避免大型项目的首页加载时间缓慢
// .storybook/main.js module.exports = { stories: [], addons: ['@storybook/addon-essentials'], features: { storyStoreV7: true, }, core: { builder: "@storybook/builder-vite" }, };
不要期望通过切换到 Vite Builder 来加快生产构建时间,但您可能会获得更小的生产捆绑包,从而加快已发布故事书的加载时间。如果你的应用严重依赖 Webpack,升级到 Webpack 5 并启用代码拆分和惰性编译可能是一个快速的胜利。在大多数情况下,您可以预期启动和重建时间与 Vite 相当。