Web Components Are Not the Future
1 views
本文是对
几年前,我写了一篇文章,认为 Web 组件可能并不是 Web 开发最有利可图的发展方向。

这些组件在有意义和无效时都很温和。它并非旨在成为”我们反对它们”的论据,我希望人们可以自行得出合理的结论。
但在过去的几年中,我只看到情况越来越糟。有些人可能从未认真对待 Web 组件,但我一直认真对待。我在生产中使用了它 7 年。在我职业生涯的早期,我还撰写了一些 polyfill ,比如 Shadow DOM ,以便在它们进入黄金时间之前就能使用它们。
但我当时的经历和此后的经历只让我得出一个结论。据我所知,Web 组件可能对 Web 的未来构成最大的风险。
乌托邦的愿景
我承认这种说法有点严厉。但我之所以相信这一点,背后隐藏着许多原因。首先要了解 Web 组件的拟议优势。
从某种意义上说,这是一个可移植的可互操作的网络。一种可以减轻未来迁移需求的方法。一个让你为任何可能的未来做好准备的人。让您的网站和应用程序面向未来的完美方式。
微件是一个引人注目的前景,不是吗?这正是Web组件如此诱人和危险的原因所在。
竞争的标准

如果庞大的 JavaScript 框架数量有任何衡量标准,我们远远没有达成关于如何在网络上创作组件的共识,即使我们现在接近这个目标,我们也不会在十年前如此接近。
引入更高级的基元可能产生积极的影响。事情突然变得更简单。这最初导致更多的探索。Web Components 导致 2010 年代中期 JavaScript 框架数量的增加。它是我创建 SolidJS 的一个重要灵感。一个类似的例子是,由于 Vite ,构建的元框架数量有所增加。
但是它也会产生负面影响。如果做了过多的假设,探索备选空间就会变得更加困难,因为一切都是围绕着标准来进行的。还有比永不改变的网络标准更根深蒂固的东西吗?
这是一个例子,而这只是众多例子中的一个。对我们有帮助的事情可能会有效地束缚我们的手脚。在对任何更高级别的机制进行标准化时,我们都必须谨慎行事,因为它做出了很多假设。仅仅表示并非每个人都必须使用它是不够的,当它的存在影响了我们如何看待该平台时,它是如此。
机会成本是真实的
作为一个框架作者,我也非常理解这一点。我经常说,在这个领域中,事物被发现的程度与被发明是一样的。我的意思是,在设计决策中,有一些真理/物理,如果你愿意的话,遵循这些真理/物理,我们都会走向相似的方向。并不是这些工具公然地互相复制。它们落入了凹槽中。
而且由于同样的原因,一旦我们做出改变我们看法的发现,在写下一行代码之前,损害已经造成。如果您从事系统设计的工作,您不希望有冗余的部分。您希望清晰明确的边界。与其对相同的事情进行数百万种变化,不如尝试重复使用一件事。更重要的是,认识到要完成共同的任务需要多种东西,这些部分开始变得相互关联。
例如, React 开发人员肯定感受到了 2017 年宣布 Suspense 和 2022 年我们终于为 RSC 带来数据提取故事之间的漫长等待。为何花费了 5 年时间?因为这不是一条直线。理解所有部分如何契合需要一段时间。这本身是合理的。但除此之外, React 不想零散地发布它们,直到他们知道整个故事都有答案。随着他们逐渐深入了解,所有这些部分都变得相互关联,虽然可以将它们分解,但需要彼此协同才能描绘出全貌。
RSC 并不符合每个人关于如何在 React 中使用 Suspense 获取数据的想法。也许人们可以从客户端数据获取原语中受益。 React 选择在这里雄心勃勃,这是他们作为工具的权利,并决定什么是最好的,但这可以通过多种方式发挥作用。
但是这里有一个很大的区别。React是一个库,而它不是一个标准。当涉及到标准的时候,这些选项并不一样。如果我想要的作用域样式,而我必须使用 Shadow DOM ,因为这是最适合于通过Web组件采用单一方法的事物的抽象,好吧,这就是我所困惑的。
当基本类型超出其预期用法时,当它们过度抽象时,你就无法再返回。你已经付出了代价。正如任何做过项目重大架构重构的人都可以证明的那样,最困难的部分是调整边界。如果事物属于相同的逻辑分组,则更容易更新。真正具有挑战性的是当你需要分开事物时。你总是可以添加另一层抽象来解决问题,但是删除一层可能很困难。
抽象的代价

因此,Web 组件的基本问题在于它们建立于自定义元素之上。元素不等于组件。更具体地说,元素是组件的一个子集。有人可能会争辩说每个元素都可以是一个组件,但并非所有组件都是元素。
所以是什么意思?由此可知,每个界面都需要经过 DOM。一些以完善的方式融入且不十分贴切,另一些则以新定义的方式扩充或改变人们为适应扩展功能而处理元素的方式。
对于一开始,DOM元素有属性和特征。这是为了能够以HTML形式展示这些元素。属性只接受字符串,而特征是一种JS界面,可以处理任何值。原生DOM元素在特定属性/特征周围有许多
作为一个标准,您可能认为我们需要更好的模板。但就像上面的 JSX 一样,您需要考虑该决定的含义。几年前,大多数人可能都会同意类似 LitHTML 进行模板渲染的方法是个不错的方法。其他解决方案也可以输出它。然而在此期间,我们意识到像 Solid 所做的反应式渲染效果更好。它是通过改变模板化语义来实现的。如果我们继续前进,我们将有一个标准,那将不是完成模板化的最佳方式。
但这还不是结束。DOM 元素可以克隆。但自定义元素有不同的行为,这意味着它们应该被导入。它们有基于 DOM 的生命周期,这些生命周期可以在升级时同步或异步地触发。这会对诸
与 Shadow DOM 中的事件目标工作方式类似,还有其他一些特殊之处。某些事件不具备”组合”功能,即不会超 Shadow DOM 边界冒泡。某些事件没有一致地冒泡,因为它们不识别不同的目标,例如 “focusin”,因为 Shadow 主机始终被设为目标,无论哪个子元素获取焦点。我们可以花好几天来讨论这些问题,但我不想在这儿过多地分散注意力。有些事情是如今的不足之处,有些则是出于设计。但其中的共性是它们都需要特定的考虑,否则它们不是必须的。
当然,这会带来性能开销:

但即使你认为这种性能成本最小,当我们为了进行服务器端渲染 (SSR) 等操作而联系服务器时,又会怎样?是的,你完全可以用 Web 组件进行服务器端渲染。完全实现 hydration 是可以的。但它们是一个没有 DOM 的地方的 DOM 接口。你可以制作一个最小的包装器来处理大多数事情,但这都是额外的开销。所有这些都归因于我们尝试让组件成为它们所不是的东西。

有人告诉我,从现在开始的 10 年内,可能没有人会使用 Solid ,但 Web 组件仍然会存在,并且具有与今天相同的界面。但我想了一会儿,回答说我仍然会用 Solid 构建它,因为这将是今天的最佳选择。 10 年后,即使我不得不使用 10 年前的 Solid 版本,它也会比 Web Component 版本更好。 10年并不能抹去这一点。希望十年后我会使用更好的东西。
该决策是完全正交的。因此,从某种意义上说,Web 组件没有任何问题,因为它们只能成为它们本来的样子。这是非常危险的,因为他们承诺自己不是这样的人。它们的存在扭曲了周围的一切,使整个网络面临风险。这是每个人都必须付出的代价。