00:00:00所以 V+ 的最终公开版本大概会是,
00:00:03它给人的感觉会非常有趣。
00:00:06这位是尤雨溪。
00:00:07尤雨溪。
00:00:09尤雨溪。
00:00:10尤雨溪!
00:00:10我开发了 Vue,也开发了 Vite。
00:00:14现在我经营着一家名叫 VoidZero 的公司。
00:00:16Vite 和 Vite+ 有什么区别?
00:00:19你的开发体验将和现在的 Vite
00:00:21完全一模一样。
00:00:22但如果你想更进一步,
00:00:24它会全程为你提供支持。
00:00:26你和你的团队是如何使用 AI 的?
00:00:28我们开始做一些疯狂的实验,
00:00:30比如把 Angular 编译器移植到 Rust。
00:00:32你对 React Server Components (RSC) 有什么看法?
00:00:34我从第一天起就持怀疑态度。
00:00:36通常我在介绍播客时,
00:00:39会请嘉宾做自我介绍。
00:00:40但我觉得如果有人在看这个节目
00:00:42却不知道你是谁,我会感到非常惊讶。
00:00:44我觉得你的知名度实在太高了。
00:00:46但大家都该知道,
00:00:48或者说大多数人都应该知道你是谁。
00:00:49他们肯定至少听说过 Vite 或 Vue。
00:00:53是的,我开发了 Vue 和 Vite。
00:00:57现在我经营着一家叫 VoidZero 的公司,
00:00:59我们致力于更多的开源项目。
00:01:03包括 Rolldown、Vitest、OXC。
00:01:07那些已经被广泛验证的技术之上,
00:01:11但我们在 VoidZero 开发的一些东西
00:01:14也非常酷。
00:01:15因为 Rolldown 是一个基于 Rust 的打包工具。
00:01:18OXC 是这一套完整的 Rust 工具链,它涵盖了
00:01:22从解析器到解析器 (resolver)、转换器、
00:01:25压缩器 (minifier) 等等。
00:01:28在 OXC 之上,我们还有 OXLint 和 OXFormat,
00:01:32分别是一个兼容 ESLint 的检查器
00:01:35和一个兼容 Prettier 的格式化工具。
00:01:37还有更多东西我们仍在开发中,不过大概就是这些。
00:01:41所以我们现在主要想聊聊开源这一块。
00:01:45当然。
00:01:45既然你同时在做这么多事情,
00:01:47你是如何分配时间的?
00:01:50嗯,我个人并不为
00:01:52所有这些项目编写代码。
00:01:53事实上,自从我创办公司以来,
00:01:56我写的代码比以前少得多了。
00:01:58公司里有很多工程师
00:02:01比我更擅长 Rust,
00:02:03而且他们现在都成了“AI 信徒”。
00:02:05所以大概一半是他们在写,另一半是 Cursor 或 Codex
00:02:10在跑大量的 Rust 代码。
00:02:12而我需要负责决策
00:02:17很多关于开发体验 (DX) 的定位,
00:02:22决定我们接下来的工作重点。
00:02:25当然还有产品方面的思考,
00:02:28比如我们如何将这些东西转化为
00:02:31可以盈利的产品,
00:02:32这也是我们目前仍在努力的方向。
00:02:34是的,这就是现在运行一家公司
00:02:39所需要做的所有事情。
00:02:41那些新的开源项目
00:02:43灵感通常来自哪里?
00:02:45主要是源于你们内部的需求,
00:02:48然后意识到这也能帮助
00:02:49解决其他人的问题吗?
00:02:53其实一切都是从 Vite 开始的,对吧?
00:02:56当我创建 Vite 时,我只是在瞎捣鼓。
00:03:01它起初只是一个原型,
00:03:03然后我觉得,我们需要一个打包工具。
00:03:07我们最初采用的是这种完全不打包的
00:03:10原生 ESM 开发服务器,对吧?
00:03:13那个想法在处理简单代码时效果很好,
00:03:16但当我们开始引入一些庞大的依赖项时,
00:03:18意识到,好吧,如果你把所有依赖项
00:03:21都以不打包的方式加载,扩展性会很差。
00:03:24例如,如果你加载像 lodash-es,
00:03:26它大约有 700 个文件。
00:03:28所以我们就觉得,好吧,
00:03:30我们需要某种工具来预打包依赖项,对吧?
00:03:34那时候有 Rollup、esbuild 和 Webpack。
00:03:41Webpack 不输出 ESM,所以不能用。
00:03:47我看了下 Rollup,Rollup 相当慢。
00:03:50跟 esbuild 比起来非常慢,对吧?
00:03:53它比 Webpack 快,但比 esbuild 慢。
00:03:56于是我们用 esbuild 来预打包依赖项,
00:03:59速度快得惊人。
00:04:00然后我们将所有源代码作为未打包的 ESM 提供服务,
00:04:02这种方式运行得非常出色。
00:04:04但到了生产环境构建时,
00:04:06我们最初的想法是,好吧,
00:04:08我们就用 esbuild 来打包整个项目
00:04:10用于生产环境。
00:04:11后来我们发现 esbuild 对于分块 (chunk splitting)
00:04:14的控制非常有限。
00:04:17这在构建大型应用时是非常普遍的需求,
00:04:19因为你希望能够自主控制,
00:04:21比如我想把这些库依赖
00:04:24放在一个 vendor 分块里,以便更好地利用缓存。
00:04:26我不希望这个分块发生改变,对吧?
00:04:28这样它就有了一致的哈希值。
00:04:32这样即使我修改了源代码,
00:04:33那个分块的哈希也应该保持不变。
00:04:35这样用户在访问网站时,
00:04:38总能直接命中那个分块的缓存。
00:04:39有很多这类优化,
00:04:41esbuild 根本就不支持。
00:04:44它只有一种默认的分块行为,
00:04:47没得商量。
00:04:49它的插件系统也不够灵活。
00:04:53一旦有一个插件决定了
00:04:56由它来处理这个文件,那就结束了。
00:04:59其他插件就没法再碰它了。
00:05:02由于我们一直大量使用 Rollup,
00:05:05我们对 Rollup 的插件系统很熟悉。
00:05:08所以我们最终的做法是,好吧,
00:05:10我们在生产环境打包用 Rollup,
00:05:13但在开发环境的预打包用 esbuild。
00:05:15在这个组合中,每个工具
00:05:20都发挥了各自的长处。
00:05:23事实上,即便是今天的 Vite 6,依然
00:05:26基于这种组合。
00:05:27这对很多人来说已经运行得很不错了,对吧?
00:05:31但显然还是有问题,因为 esbuild
00:05:35是用 Go 编写的,Rollup 是用 JavaScript 编写的,
00:05:40这意味着生产环境的构建速度
00:05:41其实仍然挺慢的,比如相比于
00:05:43完全基于 Rust 的打包工具,如 Rspack。
00:05:47而且对于开发服务器,由于 esbuild
00:05:52和 Rollup 有着不同的插件系统,对吧?
00:05:55我们无法在开发期间对依赖项
00:05:57应用同一套插件,
00:05:59但在生产环境构建时,
00:06:01插件却会应用到依赖项上。
00:06:03这就导致了一些微妙的互操作性问题。
00:06:07比如当你有一个混合了 ESM 和 CJS 的模块图时,
00:06:10esbuild 和 Rollup 的处理方式略有不同。
00:06:13它们在 Tree Shaking 行为上也存在差异。
00:06:15虽然它们都做得不错,对吧?
00:06:18我们也打了很多补丁来弥补这些行为的不一致。
00:06:22我们让它跑通了,但内心深处我们知道,
00:06:22这只是把两个不同的东西
00:06:25强行拼凑在了一起,对吧?
00:06:29因此,为了 A 提高生产环境构建速度,
00:06:31以及 B 让开发和生产环境的构建更加一致,
00:06:35最好的办法就是用一个打包工具
00:06:40包揽两者,对吧?
00:06:42但问题是 esbuild 虽然快,
00:06:44但它的扩展性并不强。
00:06:47它的代码库全都是 Go。
00:06:50esbuild 的作者 Evan Wallace,
00:06:54显然他是个科学怪人般的数学天才,
00:06:57他把 esbuild 做到了极致的快,
00:06:59但它并不怎么适合其他人
00:07:02去扩展、Fork
00:07:05或者在其之上维护一层。
00:07:07这很难做到,对吧?
00:07:10而且也很难说服 Evan Wallace
00:07:12去做他不想做的事情,
00:07:15因为他不差钱,也并不在乎这些。
00:07:17所以我们就想,好吧,那 Rollup 呢?
00:07:21我们能不能让 Rollup 变快?
00:07:27我们也做了一些实验,
00:07:28但从根本上说,Rollup 是用 JavaScript 写的,
00:07:30而 JavaScript 意味着它是单线程的。
00:07:33我们尝试过诸如 Worker 线程池、在 Worker 中运行插件等方法。
00:07:36Rollup 的维护者曾尝试引入一个 Rust 解析器,
00:07:41也就是把 SWC 解析器放入 Rollup 中。
00:07:47但这并没有带来明显的性能提升,
00:07:50因为当你有一个 Rust 和 JS 混合的系统时,
00:07:54总是存在数据传递的成本。
00:07:57你得在两者之间来回传递巨大的字符串块。
00:07:59如果你还需要克隆内存,速度会更慢。
00:08:02所以事实证明,来自 Rust 的原始性能增益,
00:08:05当只有解析器是 Rust 编写,
00:08:09而其他部分都在 JavaScript 中时,
00:08:12性能增益被数据传递的开销抵消了。
00:08:13所以最终性能几乎没有差别,对吧?
00:08:16于是我们意识到,从技术上讲,
00:08:19大幅提升 Rollup 的性能几乎是不可能的。
00:08:23唯一的选择就是重写,
00:08:26重写一个本质上是为 Vite 量身定制的
00:08:30打包工具,而且它必须快得惊人,对吧?
00:08:33这开启了我们一系列的探索,
00:08:37在思考,好吧,我们该怎么做?
00:08:40于是我们决定,
00:08:42最初的想法是用 Rust 来 Fork Rollup。
00:08:44不,不是 Fork,是移植 (Port),对吧?
00:08:48我们想把 Rollup 移植到 Rust。
00:08:49这就是为什么这个项目叫 Rolldown。
00:08:51因为它对应的是 Rollup,Rolldown。
00:08:53起初是想做直接移植,
00:08:54但我们很快意识到,用 JavaScript 写的代码
00:08:58并不容易直接移植到 Rust,
00:09:02因为 JavaScript 是一种非常动态的语言。
00:09:06它是动态语言,对吧?
00:09:08即便你使用 TypeScript,
00:09:11你仍然可以随心所欲地修改对象。
00:09:13而 Rust 对内存非常严苛。
00:09:16它对生命周期、所有权等都有严格要求。
00:09:19所以你必须以一种完全不同于 JavaScript 的方式
00:09:23来构造程序。
00:09:25因此,将现有的 JavaScript 代码
00:09:27直接移植到像 Rust 这样的语言从来都不是件简单的事。
00:09:29这几乎就是重写。
00:09:31我们最终其实是想,
00:09:33我们也想要兼顾两者的优点,对吧?
00:09:35Rollup 本身是一个非常精简的核心。
00:09:37如果你想把 Rollup
00:09:42变成一个生产就绪的预设方案,
00:09:45其实非常繁琐,
00:09:47因为你需要像 Node 解析插件这样的东西,
00:09:49解析 node_modules 并不是它的内置功能。
00:09:51你需要把它添加到你的插件中。
00:09:54你得添加 CommonJS 插件来支持 CommonJS 模块,
00:09:56因为 Rollup 核心只支持 ESM。
00:09:58然后你还得添加一大堆插件,
00:10:03比如 define、inject、replace。
00:10:06这些功能在 esbuild 中是内置的,
00:10:10但在 Rollup 中却需要插件。
00:10:14更糟糕的是,JavaScript 界的这些插件中,
00:10:17大多数都是通过额外的一次完整 AST 解析、转换和代码生成来实现的。
00:10:20所以每一个插件实际上都在重复:
00:10:25获取上一个插件的代码,
00:10:30重新解析,转换,
00:10:33生成新代码,生成新的 Source Map。
00:10:36然后你还得把所有的 Source Map 合并在一起。
00:10:38这就是为什么 JavaScript 构建系统变得越来越慢,
00:10:41因为每个插件都在不停地重复这一过程。
00:10:43所以我们觉得,好吧,我们需要把这些也内置进去。
00:10:46因此,我们最终让它拥有了 esbuild 的功能范围,
00:10:49但保持了 Rollup 的 API 形状,这就是 Rolldown,对吧?
00:10:53但在构建 Rolldown 的过程中,我们意识到,
00:10:56我们需要一个解析器,我们需要所有的转换逻辑,对吧?
00:11:01我们需要压缩器,我们需要解析器 (resolver)。
00:11:03那我们怎么得到这些呢?
00:11:07这就是 OXC 派上用场的地方。
00:11:10OXC 是一套底层的语言工具链,
00:11:12它能提供上述所有功能。
00:11:14OXC 的作者当时还在字节跳动工作,
00:11:17我已经关注这个项目很久了。
00:11:20Borshin,他是 OXC 的作者,
00:11:25现在是我们 VoidZero 的工程副总裁。
00:11:28我刚创办公司时他并没有立刻加入。
00:11:30我当时试图拉他入伙,但他当时还在观望,
00:11:33不太确定,
00:11:36但无论如何,我们已经开始基于 OXC 构建 Rolldown 了。
00:11:38我们觉得,嗯,这是好东西。
00:11:39我相信这就是我们要的,
00:11:44因为我看过了所有的可用选项,对吧?
00:11:45我想要具有组合性的东西。
00:11:47我希望工具链的每个部分
00:11:51都能作为独立的 Crates 使用。
00:11:54我还希望它非常快,对吧?
00:11:57所以我们对比了 OXC 和 SWC。
00:12:00OXC 的解析器比 SWC 快三倍,
00:12:03即便两者都是用 Rust 写的,
00:12:06因为在设计决策和底层技术细节上,
00:12:09OXC 做了很多优化,从而导致了这种性能差异。
00:12:12最主要的一点是,Borshin 在加入公司之前,
00:12:15一直痴迷于解析器性能和链接 (linking) 性能。
00:12:18比如,
00:12:20OXC 使用了一种叫做“Arena 分配器”的技术,
00:12:24它将 AST 的所有内存分配
00:12:27放在一整块连续的内存中。
00:12:30它直接分配一大块内存,
00:12:32然后把 AST 直接塞进去。
00:12:34这样释放内存的速度会更快。
00:12:39它还开启了一些有趣的玩法,
00:12:41让我们能在 OXLint 中实现快速的 JS 插件,
00:12:43因为一致的内存结构允许我们
00:12:45将整个内存块直接传递给 JavaScript,
00:12:50无需克隆,然后在 JS 侧进行反序列化。
00:12:53所以这里面有很多好处,
00:12:57当时我关注这个项目时,
00:12:59印象非常深刻,
00:13:01于是决定基于它构建 Rolldown,
00:13:05并最终说服了 Borshin 加入。
00:13:06现在公司的业务范围基本上变成了
00:13:10我们拥有一整套垂直的 Rust 技术栈,
00:13:10从最底层的解析器开始,
00:13:13向上涵盖了打包工具以及 Vite,
00:13:16除此之外还有 Linter、Formatter、测试运行器,对吧?
00:13:21我们拥有了一套完整的工具链。
00:13:24我们接下来的计划是,
00:13:26实际上我们已经做了一阵子了,
00:13:29就是把所有这些东西整合进一个连贯的包里,
00:13:33这样你就不用为了跑通一个基础应用
00:13:34而去安装五个不同的东西,对吧?
00:13:37你也不需要准备
00:13:40六七个不同的配置文件。
00:13:43我们将它们整合进一个配置文件,
00:13:47而且由于它们基于同一个解析器、
00:13:50同一个转换流水线、同一个解析器,
00:13:51它们之间保证能完美协作。
00:13:55所以不会有任何意外惊喜。
00:13:57比如,如果你同时使用 Webpack 和 Jest,
00:13:59你必须分别配置它们的模块解析逻辑,
00:14:02因为它们用的根本不是同一套东西。
00:14:05所以,我们的愿景真的是,
00:14:07好吧,让我们构建一个垂直的技术栈,
00:14:10让它在各处都能保持一致的工作方式。
00:14:14让开发体验变得尽可能直观、
00:14:16高效,对吧?
00:14:19性能是非常关键的一环。
00:14:22我原本觉得这是理所当然的,
00:14:25但你可能见过一些推文提到,Rolldown
00:14:29比 Rollup 快 20 倍。
00:14:30OXLint 比 ESLint 快 50 到 100 倍。
00:14:32OXFormat 比 Prettier 快 30 到 40 倍。
00:14:34所以我们的目标是实现兼容,
00:14:39让你无需进行大规模重构就能迁移过来,
00:14:43却能获得巨大的性能提升,
00:14:47从此你的测试循环、Lint 检查
00:14:51和一切流程都会变得更快、更顺滑。
00:14:57没错,这将让人们
00:15:00能以更快的速度开发更多的应用。
00:15:04我喜欢这种一步步扩展的过程,
00:15:08从“我们需要为 Vue 做个构建工具”开始,到
00:15:12“哦,我想改进那个环节”,再到
00:15:15“我也想把这部分优化一下”。
00:15:17正如你所说,你确实掌控了
00:15:20整个垂直技术栈。
00:15:22这非常令人钦佩,而且速度确实极快。
00:15:24在开场前我还在跟同事们说,
00:15:25我以前的一份工作,
00:15:27我们接手了一个遗留项目,
00:15:29它用的是 Webpack,构建一次要 50 分钟。
00:15:32我完全搞不懂怎么回事,
00:15:33但我当时对他们说的第一句话就是,
00:15:35我们必须立刻切换到 Vite。
00:15:37因为即便只是改一下 CSS,
00:15:40你都得等上两分钟
00:15:42等它重新构建。
00:15:43我说这绝对不行。
00:15:46我们需要热更新 (HMR)。
00:15:47当我保存文件时,它就应该生效。
00:15:49所以,Vite 确实在这方面帮了大忙。
00:15:49我认为 Vite 的进步速度以及它的普及率
00:15:52都非常惊人。
00:15:54我看到它在 NPM 上的月下载量
00:15:57已经达到了 2 亿次,非常疯狂。
00:15:59简直是——
00:16:02是的,不久前我们的周下载量刚突破了 5000 万。
00:16:05那太令人震撼了。
00:16:07我刚才就在想这 5000 万。
00:16:09这里面可能有一部分水分,
00:16:10来自那些“氛围驱动开发 (Vibe Coding)”的应用。
00:16:13全是些脚手架生成的即抛型应用。
00:16:15但即便如此,它也说明了很多人,
00:16:19或者说很多 AI 智能体都在使用它。
00:16:21我正想说呢,Betaslack 的
00:16:23工程团队全都是 Vue 的死忠粉。
00:16:26他们后端用的是 Rails,前端配 Vue。
00:16:29他们准备了一些问题,我会在播客中
00:16:33根据话题的进展适时提问。
00:16:34刚才你提到了打包,
00:16:36他们其中一个问题是,
00:16:40因为他们在 Rails 中使用 Import Maps,
00:16:42你如何看待打包工具的未来?
00:16:46因为如果你使用 Import Maps,
00:16:48其实并不怎么需要打包。
00:16:49所以,你觉得未来的走向如何?
00:16:52其实我在 Rolldown 的文档里
00:16:54专门写了这么一个章节,
00:16:56标题就叫:
00:16:57“为什么我们仍然需要打包工具?”
00:17:00你是不是经常被问到这个问题?
00:17:02是的,而且 DHH 对“不打包、不构建”
00:17:04的态度非常明确。
00:17:07所以我也不得不关注这一点。
00:17:10Import Maps 在一定程度上确实可行,
00:17:13但“不打包”这个概念
00:17:16只在特定规模下才有效。
00:17:18如果你的应用模块少于 1000 个,
00:17:20整个模块图可能在几百毫秒内
00:17:24就能加载完毕,
00:17:29这完全是可以接受的。
00:17:35如果你知道自己处于这个限制之内,
00:17:39那真的很棒。
00:17:41它默认就是懒加载的,
00:17:43这意味着如果你有一个庞大的应用,
00:17:45每个页面又是相对独立的,
00:17:48你就只加载这个子模块图,
00:17:50效果非常理想。
00:17:53这就是为什么 Vite 在开发环境下表现优异。
00:17:56但这并不是灵丹妙药,
00:17:58因为我们在 Vite 本身上观察到,
00:18:00这也是为什么我们在 Rolldown 中开发
00:18:01一种叫“全打包模式 (Full Bundle Mode)”的原因,
00:18:05因为不打包模式有其局限性,
00:18:07它的瓶颈在于模块的数量。
00:18:09有非常多的应用,它们在开发期间
00:18:12需要加载成千上万个模块,对吧?
00:18:15你可能需要加载 3000 个模块,
00:18:18这会让浏览器不堪重负。
00:18:21瓶颈出现在网络层级,
00:18:25因为使用原生 ESM,
00:18:29每一个模块都要发起一个 HTTP 请求去获取。
00:18:32如果你有一个很深的引用图,
00:18:33浏览器必须先拿回第一个模块,
00:18:36发现它还需要这些额外的模块,
00:18:38再去获取它们。
00:18:40接着再获取下一层,
00:18:44在你真正执行第一个导入模块之前,
00:18:46你必须先贪婪地遍历整个图。
00:18:49如果你处于一个较差的网络环境中,
00:18:52在渲染第一样东西之前,
00:18:53可能需要多次网络往返。
00:18:54如果模块数量达到数千个,
00:18:57网络带来的问题就会被无限放大。
00:19:00即便是本地开发,在 Vite 开发服务器上,
00:19:04如果模块超过 3000 个,
00:19:06本地加载也需要一两秒钟。
00:19:09想象一下这在生产环境的网络下
00:19:13会是什么样?
00:19:17你绝对不希望那样。如果你把它打包了,
00:19:20大概只需要 100 毫秒,对吧?
00:19:23所以这就像是一项摆在桌面上的免费优化,
00:19:27一旦应用规模越过某个阈值,
00:19:29你就应该采用它。
00:19:31我认为那些极力避免打包
00:19:35和构建工具的人,主要是因为厌烦了
00:19:38去配置那些工具,对吧?
00:19:40他们很可能遇到过 Bug,
00:19:41或者遇到了搞不定的配置问题。
00:19:45因为 Webpack 把一切搞得太复杂了,
00:19:47以至于大家现在一想到,
00:19:52哦,又要配置打包工具了,
00:19:55就会觉得这不是我该干的活,我一点都不想碰它,对吧?
00:19:56所以我认为人们对“构建步骤”
00:20:01已经产生了一种抵触心理,
00:20:04觉得它很糟糕,想避开它。
00:20:06某种程度上,我们这一系列工具
00:20:08想做的就是,
00:20:11让这些概念变得非常直观。
00:20:14对于复杂庞大的应用,它永远不可能完全简单,对吧?
00:20:16但我们希望能让一个新项目的起步足够简单,
00:20:19只要你的应用没复杂到离谱,
00:20:22你就完全不需要在这上面费心思,对吧?
00:20:24你应该能够直接说,好的,启动这个应用,
00:20:28它是用 Vite 写的,我知道一切都会很顺利。
00:20:32事实上,我了解到 Rails 社区里也有
00:20:34像 ruby-vite、vite-rails 之类的东西,
00:20:37能让 Vite 在 Rails 中运行得很好。
00:20:41我觉得“无构建”方案确实有其优点,对吧?
00:20:45它让你感到踏实,因为你知道
00:20:48可以避开很多依赖
00:20:50以及那些可能导致崩溃的不确定因素。
00:20:55我觉得有些人对构建系统失去信心是因为,
00:20:59总会有东西出岔子。
00:21:05升级个依赖,构建就崩了,
00:21:12既然能避开这些,那确实很诱人。
00:21:14但我觉得归根结底,
00:21:17如果技术足够好、足够稳定,
00:21:20你总是希望能为最终用户提供最佳的用户体验。
00:21:23而坚持完全不打包意味着你必须把自己锁在
00:21:26一个应用规模极其有限的框框里。
00:21:29你还得操心优化问题,
00:21:33因为你不得不思考,
00:21:36我在访问某个页面时,是不是不小心加载了太多东西?
00:21:37我该如何巧妙地缓存我的模块?
00:21:41我相信即便是在不打包的 Rails 里,
00:21:45仍然需要某种类似于预处理的步骤
00:21:48来给模块打上指纹,以便正确缓存。
00:21:52所以不可避免地,你仍然需要关注
00:21:54优化问题,才能让一切运转良好。
00:21:57我会说它确实适用于
00:22:01相当一部分场景,但它并不是
00:22:03万能的,无法覆盖所有用例。
00:22:06有些人的应用确实做得非常大,对吧?
00:22:08功能非常多。
00:22:11你不能强迫他们也去走“不打包”的路,
00:22:15那样会把他们锁死在
00:22:18一种无法优化的性能困境中。
00:22:21对于那些还不太熟悉它的人,
00:22:24Vite 和 Vite+ 有什么区别?
00:22:29用户能从中得到什么?
00:22:31关于 Vite+,我们正在进行一些小小的转型,
00:22:35重新定义它目前应该扮演的角色。
00:22:37我们的想法是,如果你是一个
00:22:39刚接触 JavaScript 开发的新手,
00:22:42完全是一张白纸,
00:22:45你面前是一台什么都没装的新机器。
00:22:49你如何能从零开始,直接获得一个能运行的应用,
00:22:54并且拥有热更新、各种最佳实践、
00:22:57代码检查与格式化、测试,所有这一切都为你配置好?
00:23:02在目前看来,这需要学习很多东西。
00:23:06你首先得学,
00:23:11什么是 Node.js?
00:23:14该怎么安装它?
00:23:17什么是 Node 版本管理器?
00:23:21我该用哪个包管理器?
00:23:25该用哪个构建工具?
00:23:28该用哪个 Linter?
00:23:33你必须回答所有这些问题。
00:23:36而我们想要消灭这些问题。
00:23:38我们会给你一个带有观点的起点,
00:23:39甚至,
00:23:40你都不需要安装 Node.js,对吧?
00:23:42所以我们正在尝试这种使用 Vite+ 的新方式:
00:23:44就像 `curl -s https://vplus.dev/install | bash`。
00:23:45然后运行 `vp new`,你就得到了一个新项目,
00:23:47接着 `vp dev`,
00:23:49你就拥有了一整套已经为你配置好的工具链。
00:23:50Linter、Formatter、
00:23:52测试运行器、打包工具全都有了,你甚至可以用它
00:23:54来搭建一个 Monorepo 项目。
00:23:57它支持库的打包。
00:23:59我们还计划加入像 lint-staged、
00:24:03管理变更日志 (Changelog) 这样的内置功能。
00:24:08如果你在做一个大型 Monorepo 库,
00:24:15还有一个叫 `vp run` 的命令,
00:24:17它是一个任务运行器,类似于 `pnpm run`,
00:24:21但它更高级,
00:24:25有点像 Nx,它能自动算出
00:24:28运行任务的正确顺序
00:24:31并且能智能地进行缓存。
00:24:32当然,这些都是可选的。
00:24:39所以它是一整套东西,
00:24:41如果你不需要这些额外的功能,
00:24:44你依然可以把它当作基础版的 Vite,对吧?
00:24:49你的开发体验将和
00:24:52现在的 Vite 完全一样。
00:24:57但如果你想更进一步,
00:24:59把它扩展成一个企业级、
00:25:03生产就绪的 Monorepo,它能全程为你保驾护航。
00:25:04而且,由于它是建立在
00:25:07So it's like this whole set of thing that, you know,
00:25:11这些技术本身就已经在类似的场景中被人们使用了。
00:25:13这就是我们希望带来的价值,对吧?
00:25:17我们正在把很多现有的用户
00:25:18转化到我们的开源产品中,
00:25:20比如人们正在从 Webpack 迁移到 Vite,
00:25:24从 ESLint 迁移到 OXLint。
00:25:27而我们希望 Vite+ 解决的是:
00:25:31“如果我刚开始学 JavaScript,我该怎么办?”
00:25:33“最快、最简单的入门方式是什么?”
00:25:35我想回答这个问题,
00:25:39同时让它与 AI 完美配合。
00:25:44那公司的目标是什么呢?
00:25:47我觉得很多人一听说开源项目背后有公司,
00:25:48就会感到害怕,
00:25:52担心你们会把某些功能收进付费墙。
00:25:54但你们的目标是不是一如既往,
00:25:57其实用户可以自己手动实现 Vite+ 的功能,
00:26:00只是需要大量的配置,
00:26:02而 Vite+ 只是提供了一种便利,
00:26:05就像你说的,把它们打包在了一起。
00:26:07所以你们永远不会对某个功能收费吗?
00:26:11是的,我们之前也初步探讨过
00:26:14关于 Vite+ 的授权许可模式,对吧?
00:26:15我们当时说,好的,如果你的公司规模
00:26:17超过了某个阈值,你就需要付费。
00:26:20这个想法一直在演变,
00:26:23因为我们一直在和很多感兴趣的公司交流,
00:26:25试图找到一个平衡点,
00:26:26既能让更多的人使用并创造价值,
00:26:29又能让我们捕获价值并保持可持续发展,对吧?
00:26:31我认为我们可能会把那个付费阈值大幅上调。
00:26:34这样一来,只有极少数特定类别的公司
00:26:37才需要付费。
00:26:39绝大多数用户应该都能免费
00:26:41享受它。而且,
00:26:44我们还在构思一些更偏向于“服务”的理念,
00:26:46而不是单纯为功能买单,对吧?
00:26:50比如提供一种与 Vite+ 配合的服务,
00:26:53用于提升代码质量、
00:26:56监控代码质量
00:27:00并为你提供建议或技巧,
00:27:02帮助你改进某些环节。
00:27:07因为现在有很多行业知识
00:27:11我们可以通过 AI 智能体实现规模化应用。
00:27:14这是我们目前正在探索的方向。
00:27:17明白。我刚才也在想,
00:27:20既然 Vite+ 让一切变得如此便捷,
00:27:25你觉得 AI 能通过现有的解决方案做到这一点吗?
00:27:27或者你有没有试过
00:27:31直接让 AI 去拼凑那些配置,
00:27:35包括格式化、构建等等。
00:27:37你是否觉得它由于训练数据的原因,
00:27:39会倾向于使用旧技术,从而搞出一团糟?
00:27:41是的,我们看到很多由 AI 生成的应用
00:27:44仍然在使用 Vite 5 之类的旧版本,对吧?
00:27:48因为一个大问题是,当我们发布新版本、
00:27:51推出新功能时,模型需要时间
00:27:53去学习这些数据,对吧?
00:27:56模型总是会落后于最新的资讯
00:28:00和技术,所以我们想做的其中一件事就是,
00:28:02比如当我们发布 Vite+ 的新版本时,
00:28:05首先,
00:28:07它会自带相应的 agent.md 和技能描述。
00:28:09所以当你升级 Vite+ 时,它就直接升级了,
00:28:13它会修补你 agent.md 中相关的部分,
00:28:17并链接到你 NPM 包中
00:28:20更新后的技能。
00:28:26然后,
00:28:29我们还可以给你提供一个提示词 (Prompt),告诉 AI:
00:28:31“如果你想从这个版本升级到那个版本,
00:28:34这个提示词能帮你的智能体更顺滑地完成任务。”
00:28:37这些东西很多都必须
00:28:41由工具作者来提供,对吧?
00:28:44因为你没法指望模型自己变出来。我们注意到的一点是,
00:28:47我们的 OXLint、OXFormat 和 Vitest
00:28:50被用在了 OpenManus 这样的项目中,对吧?
00:28:54OpenManus 的代码库非常疯狂。
00:28:58大概有 54,000 行 JavaScript,
00:29:00而且更新速度惊人。
00:29:05它的作者简直是不看代码直接合并。
00:29:08里面有很多东西
00:29:10简直莫名其妙。
00:29:13我们看到一些升级 OXLint
00:29:17或者引入 OXLint 的 PR。
00:29:19里面全是些凭空捏造的配置选项。
00:29:22我们看了之后心想:等等,我们没这选项啊,
00:29:26我们得加上去。
00:29:29还有当它做类型检查时,
00:29:31它会直接“修好”类型检查:
00:29:34“好吧,我直接把这条规则关了。”
00:29:36这样类型就通过了。
00:29:40所以,如果你不给它设好护栏,AI 就会走捷径,对吧?
00:29:43更重要的一点是 Peter,
00:29:45也就是 OpenManus 的作者,
00:29:46他并不是一个 TypeScript 开发者。
00:29:51他只是恰好选了 TypeScript 来做这件事。
00:29:54所以他不是工具领域的专家。
00:29:57他在这个领域没有经验。
00:29:59是 AI 帮他完成的。
00:30:00但作为 AI 所使用的这些工具的作者,
00:30:04我们能清楚地看到 AI 在哪方面表现不足。
00:30:06这就意味着,如果你继续这样搞下去,
00:30:07而我们不指出来的话,
00:30:09你的代码在三个月后就会彻底崩溃。
00:30:12所以,这就是我们认为
00:30:15在 AI 时代能提供的价值,即:
00:30:18如何确保在飞速迭代的同时
00:30:20不把东西搞砸?
00:30:22如何利用 AI 持续交付新功能?
00:30:25因为有了智能体,代码交付的
00:30:26速度正在大幅提升,对吧?
00:30:29人们开发功能的效率比以前高得多。
00:30:30但这些功能都经过仔细的代码审查了吗?
00:30:35当你一天合并 20 个 PR 时,
00:30:38代码库是否依然
00:30:41像它应该有的那样得到了妥善维护?
00:30:44代码的健康状况是非常脆弱的。
00:30:46所以你必须像人类开发一样,时不时地
00:30:50停下来思考,
00:30:54你突击开发了一阵子功能后,
00:30:58必须停下来清理一下。
00:30:59必须偿还累积下来的技术债。
00:31:03由于 AI 智能体让我们的开发速度变快了,
00:31:06我们积累技术债的速度也变快了,对吧?
00:31:11所以你同样需要利用 AI 来偿还这些债务。
00:31:14我觉得这是目前人们
00:31:19容易忽略且急需解决方案的地方。
00:31:22没错,我刚才也看了一下 OpenManus 的代码库,
00:31:25正如你所说,确实有点混乱。
00:31:26它确实是一个绝佳的例子,展示了
00:31:30当你彻底放开 AI,
00:31:33让它随心所欲,
00:31:36却没有任何监督时会发生什么。
00:31:37过去几周在网上看着它冲上热搜,
00:31:38看它做的各种操作确实很有意思。
00:31:40不过我也想问,在 AI 的角色中,
00:31:42你会为了让 AI 智能体更好用
00:31:45而改变开发 Formatter 和 Linter 的方式吗?
00:31:49这会塑造它们的未来吗,
00:31:53还是说,你们单纯把 Formatter
00:31:56和 Linter 做得飞快,本身就已经帮到了 AI 时代?
00:31:57显然它们越快,AI 智能体用起来越爽。
00:32:00我觉得这是一个很好的思路,
00:32:03因为我们确实开始思考这个问题了。
00:32:05最初这些 Linter
00:32:07和 Formatter 的目标非常宏大,
00:32:09因为我们试图去兼容
00:32:11像 ESLint 和 Prettier 这样的东西,
00:32:13它们已经在生产环境里运行了十年之久,
00:32:16用户有各种自定义规则
00:32:19和历史遗留用例,
00:32:22而我们要做到 100% 兼容。
00:32:26这是一项极其艰巨的工作,
00:32:29但我们最终还是做到了。因为我们最近刚刚实现了
00:32:31100% 的 ESLint 插件兼容性。
00:32:34我们通过了所有 ESLint 的插件测试,
00:32:38同时我们的格式化工具也实现了
00:32:40对 Prettier 的 100% 兼容,对吧?
00:32:45这两个里程碑意味着,现在
00:32:48我们可以非常有底气地推荐大家
00:32:50迁移到我们的工具上。那么下一步呢?
00:32:53那确实是个好问题。
00:32:54当智能体在使用 Lint 和格式化工具时,
00:32:56它们应该如何演变?
00:33:00这绝对是我们目前正在积极研究的课题。
00:33:03是的。
00:33:06所以这个问题目前还没有定论。
00:33:09还在不断演变中。
00:33:13AI 确实改变了编程世界的很多东西,
00:33:17这真的很值得关注。
00:33:21回到 Vite+ 的话题。
00:33:23你在 ViteConf 2024 上展示过它,
00:33:25当时演示了一个叫 `vite install` 的功能。
00:33:28我想问的是,那个功能现在还在吗?
00:33:31Vite+ 与像 Bun 这样的工具
00:33:34会有多少重合?
00:33:38好问题。
00:33:40自 ViteConf 以来,确实发生了一些变化。
00:33:44我会说,最终版的
00:33:49Vite+ 公开版本,
00:33:53在某种意义上用起来会感觉像 Bun,对吧?
00:33:54正如我刚才提到的上手体验,
00:33:57如果你有一台新电脑,
00:33:59你想以最快的速度
00:34:01开始构建 Web 应用。
00:34:04你只需要用 curl 跑一下脚本,
00:34:06就会得到一个全局二进制文件叫 `vp`。
00:34:10当你在一个项目里时,对吧?
00:34:14如果你有一个 `.node-version` 文件,
00:34:17或者在 `package.json` 里定义了包管理器字段,
00:34:19这些通常是用来指定你的
00:34:21JavaScript 运行环境的,对吧?
00:34:23当你运行 `vp run build` 时,
00:34:27它会自动使用——
00:34:30其实即便那个项目没启用 Vite+,
00:34:33只要你使用了
00:34:38这些通用的环境配置文件,
00:34:41你就可以用 Vite+ 来代替 nvm。
00:34:43你可以用它来代替 corepack。
00:34:45你再也不用操心版本问题了。
00:34:46核心思路是,当你运行工作流时,
00:34:51你不再使用 `npm run`。
00:34:56而是使用 `vp run`。
00:35:02它的逻辑是,当你执行 `vp run` 时,
00:35:04它会自动调用正确的 Node 版本,
00:35:06调用正确的包管理器版本,
00:35:11然后完成任务。
00:35:15所以那个 install 功能意味着它会——
00:35:20首先,我们目前并没有做自己的包管理器,对吧?
00:35:22所以它更像是一个 corepack 的等价物。
00:35:26我不知道你有没有用过 Anthony Fu 开发的
00:35:28那个叫 `ni` 的包。
00:35:31`ni` 的本质就是当你运行它时,
00:35:36它会自动推断出该使用哪个包管理器,
00:35:40无论你是要运行、安装还是卸载,
00:35:44对吧?
00:35:45所以 `vite install` 基本上就是那个功能,
00:35:48再加上包管理器的版本管理。
00:35:52这就是 corepack 的功能,对吧?
00:35:55哪怕你什么都没装,
00:35:59你进入一个项目,它的 `package.json` 里
00:36:02写着要用特定版本的 pnpm。
00:36:05你运行 `vp install`,它会自动检查
00:36:06那个版本的 pnpm 是否已安装。
00:36:10如果没有,它会直接帮你装好,
00:36:14然后运行 `pnpm install`。
00:36:16所以,我们的目标不仅是
00:36:19解决 Lint 和格式化问题。
00:36:24而是涵盖你日常 JavaScript 工作流中
00:36:27遇到的所有常见问题,对吧?
00:36:30我们想消除这些痛点,
00:36:34让初学者甚至都不需要去考虑这些,对吧?
00:36:36当你第一次初始化项目时,
00:36:41我们会默认使用最新的 Node LTS 版本,并推荐使用 pnpm。
00:36:45同时把这些信息写入你的项目里。
00:36:48这样当你下次回到这个项目时,
00:36:49它永远都在使用那套正确的组合。
00:36:51好奇问一下,为什么推荐 pnpm?
00:36:56因为它在功能集、
00:36:58正确性、磁盘效率、速度
00:37:01以及优秀的工作空间 (workspace) 支持(如 catalog 功能)之间,
00:37:03找到了最好的平衡点。
00:37:07当我们对比了所有的工作空间特性后,
00:37:08发现 pnpm 依然提供了最均衡的体验。
00:37:12虽然我们知道 Bun 异常之快,
00:37:14但 pnpm 对我们很多人来说已经足够快了。
00:37:16而且,我们也不排除未来
00:37:20在我们的运行时和包管理器管理中
00:37:25支持 Bun 的可能性,对吧?
00:37:31你可以选择使用 Bun,
00:37:34我们就用 Bun 来运行一切。
00:37:36关于 Vite 6,我记得你提过打算
00:37:40农历新年后发布?
00:37:43是的。
00:37:45那么在 Beta 版中,你们目前在
00:37:50正式发布前主要关注哪几点?
00:37:53全都是关于稳定性。
00:37:55比如生态系统 CI,
00:37:59我们有一套庞大的生态系统 CI 系统,
00:38:02会在依赖 Vite 的下游项目中运行 Vite 6。
00:38:06我们最近刚实现的一点是,
00:38:10SvelteKit 的所有测试现在都能在 Vite 6 上通过了。
00:38:15这对我们来说意义重大,
00:38:19因为稳定性确实是最重要的。
00:38:21试想一下,
00:38:25我们正在用一个从零开始构建的新工具
00:38:29去替换原有的两个打包工具。
00:38:33这就像是给一架正在飞行的飞机换引擎,
00:38:35还得祈祷它换完之后能飞得更稳。
00:38:37所以必须慎之又慎。
00:38:40我刚才其实想问,选择 Rust,
00:38:42是因为你们团队原本就
00:38:44掌握 Rust 吗?
00:38:49因为我看到很多 TypeScript 圈的人
00:38:52更倾向于 Go,因为我觉得移植起来更接近,
00:38:54这也是为什么 TypeScript 官方都在考虑用 Go
00:38:58来重写编译器。
00:39:00是的,我觉得 TypeScript 团队选择
00:39:04重定向到 Go,正如我所说,
00:39:06Go 是一个更容易把 TypeScript 移植过去的语言,对吧?
00:39:10因为两者的心理模型非常相似。
00:39:15而对我们来说,一个很大的阻碍是,
00:39:17Go 对 WebAssembly 的支持并不理想。
00:39:21它生成的 WebAssembly 二进制文件非常臃肿,
00:39:24而且其 WebAssembly 的性能
00:39:27和 Rust 相比也差了一大截。
00:39:28至于选择 Rust,
00:39:30很大程度上确实取决于人才的可用性,
00:39:33即那些已经充满激情、
00:39:36并在该生态中深耕的人。
00:39:40例如,当我们环顾四周,
00:39:43寻找可供构建的基础时,
00:39:46并没有哪套解析器或工具链
00:39:48能做到像 OXC 那样实现优良且具有组合性。
00:39:49OXC 的本质就是为了被二次开发而生的,对吧?
00:39:51它提供的是这些底层工具。
00:39:55我们在 Go 的世界里没看到类似的等价物。
00:39:57esbuild 固然有它自己的解析器等等,
00:39:58但它是一个庞大的单体系统。
00:40:02你没法把它的解析器拆出来单独使用。
00:40:04而且 esbuild 中的所有特性,
00:40:09比如 define、inject、转换、修饰等,
00:40:13为了追求极致性能,
00:40:17它是通过三次 AST 遍历实现的,
00:40:21这意味着在同一次 AST 遍历中,
00:40:26混合了多种逻辑:
00:40:29可能在这儿做转换,
00:40:32在那儿做 inject,
00:40:35另一边又在做修饰。
00:40:39这对于一个追求扩展性的系统来说并不理想,
00:40:41因为,
00:40:44我们希望能够支持更多的转换逻辑,
00:40:46并允许人们自由开启或关闭这些转换。
00:40:48我们希望允许人们编写自己的转换逻辑。
00:40:54我们需要一个分层清晰的 Linter 系统,
00:40:59这样我们就能让更多人同时协作。
00:41:04所以,这很大程度上取决于我们的现有资源。
00:41:08Rust 的性能确实非常出色。
00:41:11虽然用 Rust 编写优秀的转换逻辑确实有些棘手。
00:41:14我们花了相当多的时间
00:41:18去构思一个良好的架构,
00:41:23包括 Visitor 和转换流水线,
00:41:25因为内存所有权的问题,
00:41:30比如当你深入树的底层遍历时,
00:41:33如果你需要修改父节点,
00:41:36处理起来会非常麻烦,对吧?
00:41:37但我们已经解决了。
00:41:39用 Go 会容易得多,但考虑到
00:41:41我们希望我们的工具能够编译成
00:41:42WebAssembly 并在浏览器中运行。
00:41:45所以,Rolldown 能够在浏览器中运行,
00:41:51而且运行速度相当不错。
00:41:54我是说,esbuild 也能在浏览器里跑,
00:41:57但 Rust 的 WebAssembly 表现就是更好。
00:42:01基于你们团队正在用 Rust 开发这些东西,
00:42:03你和你的团队目前是如何使用 AI 的?
00:42:07你刚才提到团队里很多人
00:42:09都在用 AI。
00:42:13你觉得 AI 在你们的工作中表现如何?
00:42:16我觉得一般的 Web 开发、建个网站什么的,
00:42:22GitHub 上有太多这类案例了,
00:42:26所以 AI 训练得非常好。
00:42:28但我感觉你们在做的东西属于底层技术,
00:42:31或者至少技术含量非常高。
00:42:34在那方面 AI 能帮上忙吗?还是说你们仍然在
00:42:37进行大量的手动编程?
00:42:39它绝对能帮上忙。
00:42:42关键在于这个领域变化太快了。
00:42:44就在去年这个时候,我还持怀疑态度。
00:42:45我说,嗯,我试过了,它对我没用,
00:42:49因为我做的活儿太底层了,对吧。
00:42:51但我猜,OXC 的负责人 Borshin,
00:42:53他应该是目前公司里
00:42:57被 AI 彻底洗脑的人。
00:42:59他开始做一些非常疯狂的实验。
00:43:01我想上个月有那么一周,
00:43:05他靠 AI 提交了 60 个 PR,
00:43:07全靠并行跑智能体。
00:43:09接着我们开始做一些疯狂的实验,
00:43:12比如把 Angular 编译器移植到 Rust,
00:43:14我们直接把任务丢给它,看看行不行。
00:43:16结果居然跑通了。
00:43:19所以也许将来我们会在那个领域有所动作。
00:43:21无论如何,我们对 AI 能力上限的认知
00:43:23每隔几个月就会被刷新一次。
00:43:25随着新模型的推出,
00:43:28随着更好的开发框架 (harnesses) 的应用,
00:43:30以及新的实践方法,比如使用“计划模式 (plan mode)”,
00:43:32或是编写 agent.md。
00:43:34利用这些小技巧,
00:43:38当你实践后会发现,好吧,
00:43:41它确实变得越来越强了。
00:43:45当然,每个人的接纳度和用法各不相同,对吧?
00:43:49我们鼓励公司的每一个人
00:43:52在他们觉得合适的范围内去使用它。
00:43:59我们给他们提供每月的信用额度,
00:44:03如果他们想,甚至可以用 Claude 3.5 Sonnet。
00:44:04我觉得有些人对此非常满意,
00:44:07甚至非常推崇。
00:44:11而且他们提交的 PR 质量确实非常高,对吧?
00:44:13我觉得这很大程度上取决于你如何运用它。
00:44:16一部分归功于模型的原始能力,
00:44:19另一部分归功于你所使用的框架,
00:44:24但我认为框架层
00:44:27有点像早期的 JavaScript 框架。
00:44:29每个人都在搞自己的版本。
00:44:33做的事其实大同小异。
00:44:39也许这个版本有一些独特的技巧,
00:44:43但几个月后,大家都会了,对吧?
00:44:46这就像一个极其内卷的赛场,模型也是一样。
00:44:48每隔几个月,
00:44:51比如 Sonnet 3.7 快发布了,
00:44:55我想 DeepSeek 也要发布新模型了。
00:45:00它只会变得越来越好。
00:45:03我觉得很明显,只要引导得当,
00:45:06AI 的能力极其强大,
00:45:08但这种“引导”依然非常关键。
00:45:13你不能指望一个对 Rust 一窍不通的人,
00:45:18能在 OXC 的代码库里工作,即便有 AI 也不行。
00:45:22你甚至可能都不知道该怎么写 Prompt,对吧?
00:45:24但如果一个本身就是资深 OXC 开发者的
00:45:27 Rust 工程师有了 AI 的加持,
00:45:33他的生产力会大幅飙升,
00:45:36能更快地交付更多功能,明白吗?
00:45:40这就是我的基本看法。
00:45:45所以我可能会是公司里,
00:45:49用 AI 写的代码量最少的一个,
00:45:52跟其他工程师相比微乎其微。
00:45:54我更多地是把它当作研究工具和讨论伙伴。
00:45:57现在的编程世界确实变得很奇妙,
00:46:00我也觉得很难跟上步伐,去学什么
00:46:03该用多少个子智能体、
00:46:08并行智能体,或者现在仓库里该放
00:46:11什么样的 Markdown 文件。
00:46:13是的,它一直在变。
00:46:17很好奇我们未来最终会走向何方。
00:46:18让我们再回到 Vite 的话题。
00:46:21在 Vite 6 中,你们发布了对 React Server Components (RSC) 的支持。
00:46:23但在我看来,RSC
00:46:26并没有像官方团队预想的那样大获全胜。
00:46:32我是说,有些元框架并没有采用它,
00:46:34比如 TanStack。
00:46:37我觉得 Remix 甚至走向了一个完全不同的方向。
00:46:41所以你对 RSC 有什么看法,
00:46:45为什么你觉得它并没有达到预期的效果?
00:46:50是的,我一直对此持非常保守的态度,
00:46:54或者说,我从第一天起就是个怀疑论者。
00:46:58这也是为什么我们从未考虑过
00:47:00在 Vue 中实现类似的东西。
00:47:03我觉得核心问题在于,它到底
00:47:08想解决什么问题?
00:47:13而且我觉得在推广方式上,对吧,
00:47:16为了调动大家的积极性,
00:47:20它被包装成了某种灵丹妙药。
00:47:25似乎它是史上最伟大的东西,
00:47:27能让你所有的网站都变得更快。
00:47:29结果等它落地时,人们发现,好吧,
00:47:32也许我不应该在所有情况下都用它。
00:47:34它只适用于特定类型的场景,
00:47:37在那些场景下它能带来收益。
00:47:38而在其他情况下,它只是一堆权衡取舍。
00:47:40因为那些运行在服务器上的部分,
00:47:43你现在所有的交互其实都必须经过
00:47:43一次网络往返。
00:47:47在我看来,这对
00:47:52离线优先的体验非常不友好。
00:47:54而且我觉得你也没法完全避开水合 (hydration) 成本。
00:47:57虽然你抵消了很多客户端的水合成本,
00:48:00但你只是把它转移到了服务器上,对吧?
00:48:01现在你是在为每一次请求买单,
00:48:04你在服务器上做了更多工作。
00:48:07所以人们有一些阴谋论,
00:48:10觉得 Vercel 在推行这个是为了卖他们的云算力。
00:48:14我倒不觉得这就是真相,对吧?
00:48:17但事实确实是,使用 RSC
00:48:20意味着你有更高的服务器负载。
00:48:23你在服务器上运行了更多东西,
00:48:28消耗了更多的计算时长。
00:48:30当然它还有其他好处,比如,
00:48:35如果你把部分逻辑放在服务器上,
00:48:38你节省了包体积 (bundle size)。
00:48:40但解决那个问题有很多种方法,
00:48:42不一定非得
00:48:44让你去跑一个 Node.js 服务器,对吧?
00:48:48这很大程度上是我个人的看法,对吧?
00:48:51在前端领域,我们常说,好的,
00:48:54架构真的很重要。
00:48:56你是想做单页应用 (SPA)?
00:48:59你是否需要服务端渲染 (SSR)?
00:49:04而 RSC 更加具体。
00:49:06“你是否需要 RSC”是一个非常关键
00:49:08且难以回答的问题。
00:49:10当你决定使用它时,
00:49:14你也必须意识到你所付出的代价。
00:49:20我觉得它之所以没能被广泛采用,首先是因为
00:49:21它极其复杂。
00:49:26这个东西本身就很难解释清楚。
00:49:29它的运作原理也很难理解。
00:49:31我们不得不进行深度挖掘,
00:49:33因为它实际上需要构建工具层面的编排
00:49:38才能让整个系统运转起来,对吧?
00:49:44因此,很少有人真正理解
00:49:47原始的 RSC 是如何运作的。
00:49:51大多数人是通过 Next.js 里的实现
00:49:52来了解它的,因为普通的开发者
00:49:54根本没法靠自己手动搭建起一套 RSC 环境,对吧?
00:49:56你必须透彻理解所有环节是如何咬合在一起的,
00:49:59才能用原生 React 配合 Vite 或 Webpack 把它跑起来,对吧?
00:50:01这根本不是为了日常开发准备的,对吧?
00:50:02所以你得用框架。
00:50:06这就是框架存在的意义。
00:50:07但在框架中引入 RSC 时,
00:50:10框架必须做出设计上的权衡,
00:50:14考虑该如何呈现 RSC,
00:50:17才能给你提供过得去的开发体验 (DX)?
00:50:19我认为 Next.js 并没有处理好这一点,我会这么说,对吧?
00:50:21比如“use server”和“use client”带来的困惑,
00:50:24还有那种混合引用的图,当你把某个东西标为“use server”时,
00:50:27另一边可能就挂了。
00:50:31你被限制只能在特定条件下使用这些东西,
00:50:33然后你引入了一个依赖项,
00:50:35结果发现这个依赖项在“use server”下跑不通。
00:50:37现在你又得把它切回“use client”,对吧?
00:50:39这种反反复复,
00:50:43我觉得这些开发体验上的种种琐碎问题,
00:50:46会让人们觉得,好吧,
00:50:48为了得到那些所谓的收益,
00:50:50我现在必须忍受这种烦人的开发体验,
00:50:52而且是永远忍受下去。
00:50:56这真的值得吗?对吧?
00:50:58所以,我觉得人们产生“我真的想用它吗”这种质疑
00:51:02是很正常的。
00:51:04而且即便对于框架作者来说,对吧?
00:51:07Vercel 与 React 团队有着极其紧密的合作关系,
00:51:11所以他们可以快速协作、迭代。
00:51:14但对于第三方——我也不能说他们是第三方,
00:51:17因为技术上讲 Vercel 也是第三方,对吧?
00:51:20但对于像 Remix 和 TanStack 这样的其他框架,
00:51:23要解决这个问题并不那么直接,
00:51:27因为 React 团队的很多 API 迭代
00:51:29都是优先考虑 Next.js 的。
00:51:30我并不是在因此指责他们,
00:51:33因为,好的,Vercel 是他们的设计合作伙伴。
00:51:36他们想与 Vercel 合作
00:51:39去打磨这个功能并发布它,
00:51:42这很合理,对吧?
00:51:47但我认为,正因如此,
00:51:51Next.js 基本上成了人们使用 RSC
00:51:55的唯一现实途径。
00:51:58而那部分的体验并不怎么好。
00:52:01所以我觉得这就是它没能按预期发展的原因。
00:52:03而且,我认为
00:52:06即便是在一个 RSC 拥有完美开发体验的理想世界里,
00:52:08我依然不觉得它会是
00:52:10万能的灵丹妙药,对吧?
00:52:12你需要接受充分的教育,
00:52:15去辨别哪里该用,哪里不该用。
00:52:20权衡实在是太多了。
00:52:24我猜 Vue 应该没有打算实现类似功能的
00:52:27压力,因为很明显,这里和 Vercel 有关。
00:52:28他们收购了 Nuxt Labs,
00:52:35那是 Vue 之上的元框架,
00:52:37把一切整合在了一起。
00:52:40自从 Vercel 收购了他们,Nuxt 和 Vue 的
00:52:42关系有什么变化吗?
00:52:45说实话,没太大变化。
00:52:49我认为 Vercel 自收购以来一直保持着不插手的态度,
00:52:52所以 Nuxt 团队很高兴能
00:52:57继续做他们正在做的事情。
00:53:02当然,他们可能会做一些努力,比如
00:53:06让 Nuxt 在 Vercel 上运行得更好,
00:53:08让它成为一等公民。
00:53:13但我认为 Vercel 也很清楚
00:53:15它在社区中的某些形象,
00:53:17他们会非常小心地不去进一步破坏它。
00:53:19所以在收购了 Nuxt 之后,对吧,
00:53:21他们最不想做的
00:53:25就是强迫 Nuxt 去做人们不喜欢的事情。
00:53:29非常遗憾,尤雨溪不得不提前离开
00:53:31去接一个重要的电话,
00:53:33但我们非常感谢他能抽出时间,
00:53:38并对我们提出的所有问题给出了如此有见地的观点。
00:53:41如果您有任何希望出现在播客中的未来嘉宾,
00:53:46请在评论区告诉我们。
00:53:49如果您有任何反馈意见,
00:53:50也请一并告知。
00:53:52我们很乐意倾听。您可以在任何
00:53:54收听播客的地方找到我们,
00:53:57比如 Spotify 或 Apple Podcasts。
00:53:59下期节目再见,我是 [主持人名字],先走一步。
00:54:01拜拜。
00:54:03再见。
00:54:05倍感荣幸,谢谢大家。
00:54:08非常感谢您的参与。
00:54:09How's that sort of relationship been between Nuxt and Vue
00:54:13now that Vercel own them?
00:54:14- Honestly, it didn't change much.
00:54:18I think Vercel has been pretty hands-off since the acquisition
00:54:21so the Nuxt team is just happy to be able
00:54:24to keep doing what they do.
00:54:25There are probably some efforts to say,
00:54:30make Nuxt work better on Vercel,
00:54:32make a first-class citizen.
00:54:34But I think the thing is Vercel is aware
00:54:38that some of the images it has in the community
00:54:43and they would be really careful not to damage it further.
00:54:47And so after acquiring Nuxt, right,
00:54:50the last thing they'd want to do
00:54:52is to force Nuxt to do things people don't like.
00:54:54- Unfortunately, Evan had to leave early
00:54:56to take an important call,
00:54:58but we really appreciate his time
00:55:00and all his insightful opinions on all the questions we asked.
00:55:04If you have any future guests you'd love on the podcast,
00:55:06please let us know in the comments.
00:55:08And if you have any feedback in general,
00:55:10also let us know too.
00:55:11We'd love to hear it.
00:55:12Find us on anywhere you listen to podcasts
00:55:15like Spotify or Apple Podcasts.
00:55:17And until next time, it's a bye from me.
00:55:20- Bye from me.
00:55:21- Bye from me.
00:55:21- It's a pleasure, thank you all.
00:55:23- Thank you very much for joining us.