浅析Svelte介绍了解、如何看待 svelte 这个前端框架、svelte评测结论(存在一个阈值大小优势消失、适用简单应用场景又想要数据驱动方式)
一、Svelte 介绍
Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。
与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。
Svelte 中文文档:https://www.sveltejs.cn/tutorial/basics
1、什么是 Svelte?
Svelte 是一个构建 web 应用程序的工具。
Svelte 与诸如 React 和 Vue 等 JavaScript 框架类似,都怀揣着一颗让构建交互式用户界面变得更容易的心。
但是有一个关键的区别:Svelte 在 构建/编译阶段 将你的应用程序转换为理想的 JavaScript 应用,而不是在 运行阶段 解释应用程序的代码。这意味着你不需要为框架所消耗的性能付出成本,并且在应用程序首次加载时没有额外损失。
你可以使用 Svelte 构建整个应用程序,也可以逐步将其融合到现有的代码中。你还可以将组件作为独立的包(package)交付到任何地方,并且不会有传统框架所带来的额外开销。
二、如何看待 svelte 这个前端框架
1、尤雨溪大神的观点
作者是 Rich Harris,也就是 Ractive, Rollup 和 Buble 的作者,堪称前端界的轮子哥,现在又带来新轮子了!
这个框架的 API 设计是从 Ractive 那边传承过来的(自然跟 Vue 也非常像),但这不是重点。Svelte 的核心思想在于『通过静态编译减少框架运行时的代码量』。举例来说,当前的框架无论是 React Angular 还是 Vue,不管你怎么编译,使用的时候必然需要『引入』框架本身,也就是所谓的运行时 (runtime)。但是用 Svelte 就不一样,一个 Svelte 组件编译了以后,所有需要的运行时代码都包含在里面了,除了引入这个组件本身,你不需要再额外引入一个所谓的框架运行时!
当然,这不是说 Svelte 没有运行时,但是出于两个原因这个代价可以变得很小:
(1)Svelte 的编译风格是将模板编译为命令式 (imperative) 的原生 DOM 操作。比如这段模板:
<a>{{ msg }}</a>
// 会被编译成如下代码:
function renderMainFragment ( root, component, target ) {
var a = document.createElement( 'a' );
var text = document.createTextNode( root.msg );
a.appendChild( text );
target.appendChild( a )
return {
update: function ( changed, root ) {
text.data = root.msg;
},
teardown: function ( detach ) {
if ( detach ) a.parentNode.removeChild( a );
}
};
}
可以看到,跟基于 Virtual DOM 的框架相比,这样的输出不需要 Virtual DOM 的 diff/patch 操作,自然可以省去大量代码,同时,性能上也和 vanilla JS 相差无几(仅就这个简单示例而言),内存占用更是极佳。这个思路其实并不是它首创,之前有一个性能爆表的模板引擎 Monkberry.js 也是这样实现的,ng2 的模板编译其实也跟这个很类似(但是中间加了一层渲染抽象层)。
(2)对于特定功能,Svelte 依然有对应的运行时代码,比如组件逻辑,if/else 切换逻辑,循环逻辑等等... 但它在编译时,如果一个功能没用到,对应的代码就根本不会被编译到结果里去。这就好像用 Babel 的时候没有用到的功能的 helper 是不会被引入的,又好像用 lodash 或者 RxJS 的时候只选择性地引入对应的函数。
基于这两个特点,Svelte 应用的最终代码量可以非常小。比如它的 TodoMVC min+gzip 之后只有 3kb。
但是,Svelte 也不是没有它的潜在问题:
(1)虽然在简单的 demo 里面代码量确实非常小,但同样的组件模板,这样的 imperative 操作生成的代码量会比 vdom 渲染函数要大,多个组件中会有很多重复的代码(虽然 gzip 时候可以缓解,但 parse 和 evaluate 是免不了的)。
项目里的组件越多,代码量的差异就会逐渐缩小。
同时,并不是真正的如宣传的那样 “没有 runtime“,而是根据你的代码按需 import 而已。
使用的功能越多,Svelte 要包含的运行时代码也越多,最终在实际生产项目中能有多少尺寸优势,其实很难说。
(2)Svelte 在大型应用中的性能还有待观察,尤其是在大量动态内容和嵌套组件的情况下。它的更新策略决定了它也需要类似 React 的 shouldComponentUpdate 的机制来防止过度更新。
另一方面,其性能优势比起现在的主流框架并不是质的区别,现在大部分主流框架的性能都可以做到 vanilla js 的 1.2~1.5 倍慢,基于 Virtual DOM 的 Inferno 更是接近原生,证明了 Virtual DOM 这个方向理论上的可能性,所以可以预见以后 web 的性能瓶颈更多是 DOM 本身而不是框架。
(3)Svelte 的编译策略决定了它跟 Virtual DOM 绝缘(渲染函数由于其动态性,无法像模板那样可以被可靠地静态分析),也就享受不到 Virtual DOM 带来的诸多好处,比如基于 render function 的组件的强大抽象能力,基于 vdom 做测试,服务端/原生渲染亲和性等等。
这一点在我看来比较关键。让我在一点点性能和 Virtual DOM 之间做抉择的话,我还是会选择 Virtual DOM。Vue 3 在保留 Virtual DOM 灵活性的前提下基于模版对渲染函数做 AOT 优化,性能已经做到跟 Svelte 很接近。
最后,我个人觉得 Svelte 比较有优势的地方,就是用来编译可独立分发的 Web Components。传统框架和 Web Components 结合最大的问题就在于运行时:单独分发的 WC 里面直接打包框架运行时,等于每个组件都要复制一份框架;不打包的话,又做不到开箱即用。但 Svelte 受这个问题的限制最小(依然存在重复代码问题,但取决于你用了多少功能),可以说是最适合这个用例的框架。
作者:尤雨溪 - https://www.zhihu.com/question/53150351/answer/133912199其他观点也可以直接看这篇文章上的观点
三、尤大亲自评测 Vue3 和 Svelte(19个组件后Vue更好!)
本研究旨在展示框架如何在 compile-time 编译时和 runtime spectrum 运行时找到一个平衡点:
(1)Vue 在源码上使用了一定的 compile-time 编译时 优化,但选择较重的 compile-time 返回较小的生成代码。
(2)Svelte选择最小的运行时,但具有较重生成的代码的成本。
(3)Svelte 可以进一步改进其代码生成来降低代码输出吗?Vue可以进一步改善tree-shaking,使基线(运行时框架)变小吗?另外一点框架可以找到更好的平衡点吗?对以上所有的问题的答案回答可能是肯定的。
从这篇文章学到的总体观点:
1、Svelte 确实有一个阈值会使得它在一定程度后让体积大小没有了优势;
2、但是在一般情况下,特别是在一些 H5 游戏中,如果你想要获得 React/Vue 数据驱动的方式编写应用,但是你又不想要引入他们这么大的运行时,确实来说是一个非常不错的方案。