在过去的六年里,Vue、Angular 和 React 统治着前端组件框架的世界。谷歌和 Facebook 有自己的赞助框架,但对于任何倡导开放和公正网络的人来说,它们可能会留下苦涩的滋味。Vue 是另一个受欢迎的框架,它有多个赞助商,但不受单一公司的控制,这可能会吸引一些人。
在框架领域,还有另一个正在引起关注的参与者,其运作方式与 Vue 非常相似,都采用了开放的 MIT 许可证:Svelte。
Svelte 之前曾在 CSS-Tricks 上被介绍过,例如 Ollie Williams 关于 如何使用它编写更方便的基于组件的 CSS 的精彩概述。本文将更进一步,提供更多关于 Svelt 的背景信息,以及它如何区别于其他框架,以及如何在您自己的项目中实现它。
是什么让 Svelte 与众不同?
我可以自信地说,Svelte 是学习起来最容易、并能以高效的方式投入使用的 JavaScript 组件库。
— Jeff Delaney,摘自 使用 Firebase 的 Svelte 实时待办事项列表
好的,所以 Svelte 是一个 JavaScript 组件库。但 React 也是。Angular 和 Vue 也是。是什么让 Svelte 从众多框架中脱颖而出呢?
Svelte 尝试做一些与其他框架不同的事情
- 所有代码都在构建时提前编译。
- 没有虚拟 DOM。
- 内置 CSS 作用域。
让我们稍微分解一下这些内容,因为它们将 Svelte 与其他前端框架区分开来。
所有代码都在构建时提前编译。
Svelte 是一个编译器,这意味着 Svelte 文件中的代码会从更易于编写的混合语言(混合了 HTML、JavaScript 和 CSS)转换为更低级的优化后的 JavaScript、HTML 和 CSS 文件。
这与 C# 编译成字节码或 Typescript 编译成 JavaScript 的方式非常相似。但传统编译器往往会转换为一种语言,而 Svelte 则混合了这三种语言。
这使得代码编写更加灵活,并且对客户端(Web 浏览器)更有利,因为计算是在应用程序构建时完成的,而不是在每次访问 Web 应用时都在每个浏览器上完成。
没有虚拟 DOM。
DOM(或文档对象模型)是一个接口,它定义了网页的逻辑结构。它获取 HTML 并将其转换为可以操作和访问的结构。Chris 有一篇经典文章 详细解释了它。
虚拟 DOM 扩展了 DOM 的概念,在内存中创建了一个“第二个”DOM。与 DOM 一样,它由传统的框架(例如 Angular、Vue 和 React)进行操作和访问。在构建时,这个第二个“虚拟”DOM 会与实际的 DOM 合并,从而使 UI 能够渲染。
那么 Shadow DOM 呢?好吧,Shadow DOM 从技术上讲是“真实”DOM 的一部分,只是隐藏在阴影中。因此,它是隔离不会泄漏到页面上其他元素或与之冲突的代码块的绝佳工具——有点像(但同时又几乎不像)iframe。Shadow DOM 某种程度上是大多数基于组件的前端框架的核心,因为它们利用 Shadow DOM 的隔离特性为特定元素提供特定代码。
虽然这不是 Svelte 的主要卖点,但可以实验性地使用 Shadow DOM。Shadow DOM 还没有真正流行起来,这很可惜,可能是由于草案之间存在混淆,以及 IE 和 Edge 缺乏支持。
那么,我为什么要说这些呢?Svelte 与其他 JavaScript 框架的区别在于没有虚拟 DOM。这一点很重要,因为它有助于创建更快的应用程序——比使用虚拟 DOM 的框架更快。是的,虚拟 DOM 速度可能非常快,因为它只在需要时更新 DOM 的部分,但随着应用程序的增长,存储在内存中的重复 DOM 的影响可能会对整体性能产生负面影响。
Svelte 采用了一种不同的方法,并在构建时进行许多繁重的计算。所有这些预先完成的繁重工作,使 Svelte 能够仅在需要的地方进行外科手术式的更改。
内置 CSS 作用域。
Svelte 内置了样式,这在其他现代框架中至关重要。Svelte 中的 CSS 与其他框架中的 CSS 的区别在于,Svelte 会在构建时将每个组件的 CSS 输出到一个单独的 CSS 文件中。
我个人对大多数 CSS-in-JS 方法的抱怨是,它似乎是一个过度设计的解决方案。Svelte 的方法保持了简洁、原生和封装性——同时将所有内容放在它们应该在的地方。
对于喜欢预处理器的人来说,有各种插件可供选择,无论是 Sass、Less 还是 Gulp。但由于 Svelte 仍处于起步阶段,我建议使用纯 CSS 以及您选择的最小化 CSS 框架,以便您可以利用 Svelte 方便的组件作用域。
您也可以轻松地保持您通常的样式偏好,完全放弃 Svelte 的 CSS 构建器。但是,我认为这是一种巨大的损失,因为至少在我的经验中,Svelte 的解决方案非常简洁和令人愉快。但是,任何必须使用 IE11(😬)甚至更旧浏览器的人都会知道,规范化样式是必须的。这是一个很好的停下来查看 Ollie 的文章的地方,因为他 深入探讨了 Svelte 的样式功能和优势。
Svelte 与其他框架的对比
我们刚刚了解了 Svelte 在编译、与 DOM 交互和编写 CSS 方面采用了不同的方法。您可能想知道:Svelte 与其他流行框架相比如何?
已经有很多 比较,但可以肯定地说,Svelte 非常快。但速度并不是唯一的比较依据。相反,让我们做一个并排比较,以开发社区非常喜欢的格式提供更广泛的概述:表格!
Svelte | Vue | React | Angular (2+) | |
---|---|---|---|---|
是什么 | 编译器 | 框架 | 框架 | 框架 |
首次提交 | 2016年11月16日 | 2013年7月29日 | 2013年5月24日 | 2014年9月18日 |
支持 | 开源 | 多个赞助商 | ||
社区¹ | 小 | 大 | 庞大 | 大 |
满意度2 | 88% | 87% | 89% | 38% |
考虑到 Svelte 的后期进入和较小的社区,它的发展势头非常强劲。开发者满意度很高,而前三名的框架近期满意度有所下降。Svelte 社区规模较小,但正在增长,并且代码是开源的,这对整个 Web 社区来说是一个巨大的优势。
让我们来看一个使用 Svelte 的示例
我希望我已经说服您,Svelte 至少值得一试。如果是这样,让我们启动终端并尝试一个现实世界的日常用例示例:实现 Intersection Observer。如果您曾经 运行过 Lighthouse 报告,它可能会因为您没有使用 被动滚动事件 而对您大加指责。这可能是我写过的最无聊的一句话,但它确实在性能方面得分,而且使用 Svelte 中的 Intersection Observer 实现起来并不复杂。
让我们跳过所有安装和设置步骤,因为我们可以使用 REPL(Svelte 在其网站上用于演示框架的在线编辑器)避免这些步骤。标准的“Hello world”样板代码已包含在内。请继续,在屏幕右上角下载应用程序的 ZIP 文件。
现在,解压缩文件并从终端中 cd 到该文件夹,然后运行 npm -i
以初始化项目。完成后,执行 npm run build,您将获得轻量级微型 Svelte“Hello, world!”应用程序的副本。
现在我们可以开始添加 IntersectionObserver 的实际任务了。
首先,我们导入 Svelte 团队已经编写好的代码。它位于 svelte.dev 的 Git 仓库 的源代码中(其内部机制非常值得一读)。
<script>
import { onMount } from 'svelte';
export let once = false;
export let top = 0;
export let bottom = 0;
export let left = 0;
export let right = 0;
let intersecting = false;
let container;
onMount(() => {
if (typeof IntersectionObserver !== 'undefined') {
const rootMargin = `${bottom}px ${left}px ${top}px ${right}px`;
const observer = new IntersectionObserver(entries => {
intersecting = entries[0].isIntersecting;
if (intersecting && once) {
observer.unobserve(container);
}
}, {
rootMargin
});
observer.observe(container);
return () => observer.unobserve(container);
}
function handler() {
const bcr = container.getBoundingClientRect();
intersecting = (
(bcr.bottom + bottom) > 0 &&
(bcr.right + right) > 0 &&
(bcr.top - top) < window.innerHeight &&
(bcr.left - left) < window.innerWidth
);
if (intersecting && once) {
window.removeEventListener('scroll', handler);
}
}
window.addEventListener('scroll', handler);
return () => window.removeEventListener('scroll', handler);
});
</script>
<style>
div {
width: 100%;
height: 100%;
}
</style>
<div bind:this={container}>
<slot {intersecting}></slot>
</div>
将这段代码粘贴到名为 `IntersectionObserver.svelte` 的文件中,并将该文件放在 `src/components` 文件夹中。然后,在主 Svelte 文件 `App.svelte` 中引用它。
import IntersectionObserver from “./components/IntersectionObserver.svelte”;
现在,我们已经将 Intersection Observer 作为组件可用,可以使用它来包裹其他元素。
<IntersectionObserver let:intersecting top={400}>
{#if intersecting}
<section>
This message will Show if it is intersecting
</section>
{:else}
<section>
This message won't Show if it is intersecting
</section>
{/if}
</IntersectionObserver>
就是这样!您可以看到 Intersection Observer 组件如何允许我们像使用包装器一样使用 `<IntersectionObserver>`,并定义交集触发的位置,在本例中是距离顶部 400 像素。提醒一下,所有这些都以 **原生 JavaScript** 导出!超级高效,没有花哨的东西。我们将 JavaScript 和 HTML 结合在一起,这很酷,因为我们可以看到 Intersection Observer 直接影响什么,没有歧义,并且不会影响性能。
`OnMount` 函数是必要的,它告诉 Svelte 这段代码需要在浏览器中运行,因为 Intersection Observer 无法提前确定。
我们需要添加一些样式,以便我们可以体验观察器的实际效果,我们可以在 `App.svelte` 文件中直接进行操作。如果您使用过其他任何前端框架,这可能看起来非常熟悉。
<style>
.somesection {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.somesection.even{
background: #ccc;
}
.content{
text-align: center;
width: 350px;
}
</style>
最后,我们可以将 Intersection Observer 元素复制粘贴四次以创建更多交集。这给了我们一个小型 Web 应用,它可以在内容进入视野时动态添加和移除内容——非常适合与媒体一起使用,例如 延迟加载。查看 最终结果的演示,并确保打开 DevTools 以查看 Intersection Observer。
一些最后的思考
我个人建议您尝试一下 Svelte。在这篇文章中,我们仅仅触及了这个框架的皮毛,但是自从我将我的个人网站转换为 Svelte 之后,我可以自信地说它使用起来非常愉快。它高效,拥有出色的 VSCode 代码检查工具,最棒的是,它易于使用。它可能体积小巧,而且是新兴框架,但我有一种强烈的预感,它将成为臃肿的“巨人”框架的救星,是前端开发者一直在寻找的“大卫”。
那么您是否应该在实际项目中使用 Svelte 呢?风险和回报的比较肯定需要考虑在内。与其他框架相比,它的社区规模较小,这意味着您可能会找到较少的支持和较少的教程来指导您。同时,Svelte 已经发展到第三代,这意味着大多数问题应该已经解决,留下了一个精简可靠的框架。
对于任何新事物,都要遵循常识规则,尝试一些非商业项目,试用一下,看看效果如何。
还有其他内容吗?您问得真是巧!Svelte 生态系统中还有两个协同项目:Sapper 和 Native。**Sapper** 是一个利用 Svelte 构建完整 Web 应用程序的框架,包括路由、服务工作线程以及开始构建所需的所有好东西。我用它重建了我的个人网站,到目前为止,我非常喜欢它。**Svelte Native** 是 Svelte 项目中最实验性的项目,一个利用 Svelte 的 NativeScript 移动应用程序构建器。我承认我的知识到此为止。幸运的是,它有一个 网站 提供更多信息。
您怎么看?您尝试过 Svelte 吗?您认为它与其他框架相比如何?让我们在评论区讨论吧!
我敦促该博客的编辑不要允许使用 JS 状态调查中的统计数据。它显然是一项受欢迎的调查,但年复一年地被证明是一个有偏差的样本。通过在这里引用这些数据来维持其重要性,会损害社区。
FWIW,您写道“现在,解压缩文件并从终端进入文件夹,然后运行 npm -i 初始化项目。完成后,运行 npm run build,您将获得一个轻量级小型 Svelte“Hello, world!”应用程序的副本。”
最好说明确切的命令,这样那些不是每天都使用 NPM 的人就不必停下来思考“他所说的 npm -i 是什么意思?”
在我看来,这篇文章在解释虚拟 DOM 和 Shadow DOM 方面做得非常糟糕,并且在几个不同的上下文中使用了这些术语。我建议首先明确定义它们,并解释框架如何使用它们,而不是仅仅称之为“在阴影中”。理解 Svelte 的不同之处需要对这些概念有关键的理解。
编译也是如此——JavaScript 并没有被编译,它只是被转换成不同的 JavaScript。这种区别在这里很重要,也是理解 Svelte 与众不同的关键——Svelte 中没有其他框架中存在的这种“编译”,但文章似乎暗示了这一点。
在学习 Svelte 时,我发现这个资源很有用:https://www.ideamotive.co/blog/what-should-you-know-before-using-svelte-part-1
它解释了 Svelte 的算法,基本上是它如何采用上文中提到的不同方法。
实际 DOM 操作的性能开销过大,这就是创建虚拟 DOM 的原因。它包括两个阶段:搜索更改和应用这些更改——在这里,我们需要应用的更改更少,设备负载也更小。但是 Svelte 实现了另一种算法:在编译阶段,它创建包含所有逻辑的原始低级 JS 函数,这些函数包含所有幕后操作,从而实现所有神奇的效果。