发布于 2026-01-06 0 阅读
0

🤖 Svelte测评:赋能大师班 🤖

🤖 Svelte测评:赋能大师班 🤖

网络增强型网络应用程序。

自Svelte框架第 3 版以来,其标语就非常有趣。Svelte 团队以其积极的编译时自动化和优化而自豪——以至于他们之前的标语实际上是“神奇的消失的 UI 框架”(字面意义上的!)。

即使在今天,编译器已经剥离了框架的许多内部机制,这一点仍然适用。¹ Svelte 的创建者Rich Harris秉持着这样的理念:如果框架能够自动分析,那么开发者就无需为此操心——这实际上是对主流 UI 框架的一种微妙讽刺,因为主流框架会在运行时进行状态分析和解析。这就是网络增强型 Web 应用的理念:让工具来完成这些工作!

但 Svelte 将这种理念贯彻到了什么程度?Svelte 是否达到了零成本抽象的程度?抛开所有花哨的编译时机制不谈,开发者的体验究竟如何?在本文中,我们将探讨 Svelte 框架及其生态系统的优势。

精彩的文档

就像生活中的大多数事情一样,第一印象在科技领域也至关重要。糟糕的示例、冗长的指南、不便的先决条件以及奇怪的语法很容易让最热情的学习者望而却步。因此,经典的“入门指南”是框架展现其最佳形象的关键所在。

Svelte 的表现堪称完美,他们确实展现出了最佳水平。该框架为新用户提供了以下必要的入门资源:

标题 描述
苗条 Svelte框架的官方文档/参考资料。
SvelteKit SvelteKit 元框架的官方文档/参考资料。
示例 一个示例库,用于引导用户了解 Svelte 的各项功能。
REPL 一个用于在 Svelte 中尝试各种想法的实时 REPL 编辑器/试验环境。
教程 一个交互式教程,包含全面的指导以及实时编辑环境。

毋庸置疑,Svelte 的文档非常完善。指南内容全面详尽,同时又简洁明了,直奔主题。此外,其语言风格和技术性也恰到好处,既不枯燥乏味,也不充斥着晦涩难懂的术语。

最好的例子来自交互式教程,其中的指导者会在介绍功能之前,先通过一个引人入胜的示例引导读者理解。因此,该教程更像是一次探索 Svelte 精髓的旅程,而不是一场关于 Svelte 的讲座

同时,为了快速进行实验,实时示例和 REPL 是测试框架行为的最简便方法。就我个人经验而言,在构建有状态组件原型时,REPL 是一个非常宝贵的工具。此外,REPL 也是我向同事演示 Svelte 最酷功能时的首选资源。

低准入门槛

就我个人而言,Svelte 最棒的地方在于它的低入门门槛。与TypeScriptVue.js的理念类似,Svelte 语言力求成为 Web 开发三大核心技术(HTML、CSS 和 JavaScript)的超集。

作为许多同行的导师,在讨论完基本的 Web 特性和 API 之后,过渡到 Svelte 非常自然。也就是说,Svelte更像是Web 平台的扩展,而不是替代品。所有的 Web API 和 DOM API 都相同。无需学习标签<a>之类的替代方法。背景知识可以无缝迁移。

Svelte 的语言设计让初学者能够亲身验证 UI 框架背后并没有什么神秘之处;一切都只是构建在核心 Web API 之上;归根结底,一切都只是普通的 HTML、CSS 和 JavaScript。这种思维模式完美地弥合了组件世界与 Web 平台现实之间的鸿沟。

SvelteKit:终极 SSR、CSR 和 SSG 解决方案

在继续之前,让我们先来定义一些术语:

  1. 服务器端渲染(SSR)
    • Web 服务器会根据服务器、数据库、请求等的某些变量动态地即时生成新的(模板化的)HTML。
  2. 客户端渲染 (CSR)
    • Web 服务器向浏览器发送一个空的 HTML 应用程序外壳。
    • 浏览器执行 JavaScript 代码来填充用户界面。4
    • 通常意味着需要额外多次往返服务器来获取应用程序数据(通常为 JSON 格式)。
  3. 静态站点生成 (SSG)
    • 构建系统会提前预编译HTML
    • 因此,Web 服务器仅托管静态资源(例如 HTML、CSS 和 JS)。

几十年来,互联网在这三种策略之间摇摆不定——一种趋势不断更迭,却始终没有定型。公平地说,每种策略都有其自身的优点和不足(就像工程领域的大多数事情一样)。

然而,Svelte 生态系统最令人印象深刻之处在于它能够无缝地混合搭配这些策略。而这正是SvelteKit 的用武之地。

SvelteKitVite提供技术支持,是一个官方维护的元框架,它在 Svelte 框架之上提供了一套完整的路由解决方案(客户端和服务端)。它融合了各方优势,使开发者能够精细地选择哪些路由在服务器端渲染 (SSR)、哪些路由仅在客户端进行水合 (CSR),以及哪些路由预渲染为静态 HTML (SSG)。

这种看似零成本灵活性对于像我这样追求极致效率、力求榨干网络每一字节性能的严谨主义者来说,简直是天赐之福。与过去截然不同,那时我们常常被迫每个应用只能采用一种策略——否则我们就会“脱离”既定的项目结构,自行实现所谓的“魔法”。

例如,可以考虑仅仅为了实现服务器端渲染 (SSR) 而使用PHPExpress框架和EJS模板引擎来搭建应用。也可以考虑仅仅为了实现客户端渲染 (CSR) 而搭建 2016 年之前流行的 React 应用。或者,也可以考虑仅仅为了实现静态站点生成 (SSG) 而搭建 Gatsby 应用。

在所有情况下,我们通常都要求这些是独立的应用程序。当时,我们还没有一个能够简化路由级别混合渲染策略概念的整体解决方案/框架。现在我们有了。7

换句话说,SvelteKit 让我们不必纠结于是否应该只使用 SSR CSRSSG,而是可以专注于哪些路由可以使用 SSR CSRSSG。一切都开箱即用,这种体验真是令人耳目一新。

无障碍环境作为一等公民

Svelte 最令人称道的特点之一是它将可访问性视为首要考虑因素。Svelte 编译器甚至会强制执行可访问性最佳实践,并对反模式发出警告。

那些没完没了的黄色波浪线起初可能看起来很麻烦,但必须始终记住,禁用它们就完全忽略了重点!

有人认为这是 Svelte 最令人恼火的功能之一。我个人并不认同。作为一个对无障碍设计不太了解的人,我非常感谢这些自动提醒功能,让我放下身段,设身处地地站在残障人士的角度思考问题。

不过,我必须承认, Svelte 中的事件委托模式有点繁琐。事件委托通常涉及将事件监听器附加到不可见的父容器上,而编译器会将此标记为可访问性警告。

click确实,给看似任意的标签添加监听器有点奇怪<div>——尤其是嵌套标签!通常情况下,这些警告可以通过应用正确的 ARIA 角色并添加相应的keydown监听器来解决。然而,在这些罕见的误报情况下,我并不完全反对彻底禁用该警告

小型生态系统

是的,Svelte 生态系统相对较小,尤其与 React 相比。乍一看,这似乎对 Svelte 生态系统不利。甚至有人会说:“Svelte 已死!”但我认为,生态系统规模小背后有一个更令人满意的原因——它根本不需要庞大的生态系统!

请注意,Svelte 语言旨在扩展Web平台。因此,该框架的许多内部机制都使用并接受(作为参数)浏览器中已内置的标准 Web API 对象。

例如fetch,考虑一下浏览器RequestResponse浏览器、浏览器FormData、浏览器NodeCustomEvent浏览器等等。当大多数基本功能都已内置于浏览器中时,Svelte 开发人员很少会去使用库。

轻松集成到 Web 优先库中

当与成熟的第三方库(这些库是为 Web 而非特定框架构建的)集成时,这一点尤为重要。我可以根据自身经验举一个例子:Chart.js库,它处理的是普通的对象。在 Svelte 中,只需HTMLCanvasElement一个简单的配置即可启动整个流程,无需太多繁琐的步骤。当然,为了方便起见,也可以选择使用封装bind:this

然而,关键在于,在 Svelte 世界中,封装库主要是为了方便。它们足以完成任务,但并非像其他框架那样必不可少。10第三方库很少需要额外的软件包才能与 Svelte 的响应式特性进行清晰的交互svelte-adapter-*

无需状态管理库

说到 Svelte 的响应式特性,还有一点值得一提,那就是 Svelte 世界里几乎没有状态管理库。这并非因为“Svelte 生态系统已死”。更确切地说,Svelte 生态系统根本不需要状态管理库!

内置的存储和响应式变量几乎涵盖了所有用例。事实上,响应式原语和逻辑块结合起来非常强大,它们可以优雅地表达组件级状态机——完全不需要任何第三方库!

万一这些响应式原语还不够用,那么或许应该彻底重新考虑一下架构了。总有更好的方法……

精细反应性(有时!)

得益于编译器,Svelte 拥有一个“神奇消失的 UI 框架”,其中响应式和状态依赖关系在编译时即可解析和绑定。对于大多数基本类型变量(例如字符串、数字、布尔值等),细粒度的响应式就足够了,并且开箱即用,效果极佳。事实上,正是这种细粒度的响应式使得 Svelte 的性能始终优于除少数几个 UI 框架之外的所有其他框架。稍后我们将对此进行更详细的讨论。

在组件层面,响应式的基本单元是变量,而响应式的催化剂是重新赋值。如果新赋值的状态与其先前的值完全相等,Svelte 甚至会阻止 DOM 重新渲染。需要注意的是,对于对象和数组,这种检查是递归进行的,以实现更细粒度的响应式。

尽管有这些保护条件,但对于非原始变量(例如对象)而言,一个不幸的常见错误会导致对响应式副作用(在重新渲染保护之前执行)产生微妙的负面效果。

考虑以下示例,其中我们有一个data包含两个字段的对象:countother。在本例中,我们只会data.count在单击时修改<button>。同时,data.other字段将始终保持不变。

<script>
    // Recall that _only_ the `count` will be modified.
    let data = { count: 0, other: null };
    const increment = () => ++data.count;

    // Intuitively, this side effect should run per increment.
    $: console.log('updated count', data.count);

    // With that said, will this side effect ever run?
    $: console.log('updated other', data.other);
</script>

<!-- Increment `data.count` per click. -->
<button on:click={increment}>+</button>
Enter fullscreen mode Exit fullscreen mode

令人惊讶的是,这个副作用data.other居然真的会执行!这要归功于变量是响应式的基本单元,而重新赋值则是响应式的催化剂。由于 ` data.countwith` 位于data变量内部(作为一个整体),因此所有依赖于该对象的data对象都会收到更改通知!data.other副作用之所以会执行,仅仅是因为它恰好隐式地引用了data变量(作为一个整体)。

解决方法出乎意料地简单:规范化基本元素!

<script>
    // Same old `data` here.
    let data = { count: 0, other: null };

    // Now we "normalize" the object into its primitives.
    // Alternatively, we could have just separated the variables
    // to begin with rather than putting them in an object.
    $: ({ count, other } = data);

    // Same click handler.
    const increment = () => ++count;

    // Now only this side effect will run.
    $: console.log('updated count', count);

    // This is unreachable code because we hold no references
    // to `data` nor to the normalized `count` variable.
    $: console.log('updated other', other);
</script>

<!-- Increment `count` per click. -->
<button on:click={increment}>+</button>
Enter fullscreen mode Exit fullscreen mode

Kevin Bridges ( @kevinast ) 在他的文章《探索 Svelte 的响应式特性》中详细阐述了这种行为。关键在于,Svelte 允许我们“微调响应式特性”——无论好坏……

还有更多例子表明,Svelte 的粒度并没有我最初想象的那么细。举个例子,当底层数组被修改时,{#each}代码块实际上会根据提供的键表达式进行差异比较。这本应是一个速度极快的操作,但令我失望的是,它并没有在后台使用任何高级的编译时机制。

回到框架基准测试,或许正是因为这个原因,SolidJS 的性能才始终优于 Svelte。简而言之,在处理非原始变量时,SolidJS 的 store(本质上是带有细粒度 mutation 辅助函数的递归信号)比 Svelte 的 store 更细粒度。

如果能找到某种方法,在编译时将 SolidJS 信号的细粒度响应式特性与 Svelte 语言的表达能力整合起来,那它将成为史上最强大的框架!可惜我们生活在一个并不完美的世界……至少现在还没有!

更新: 2023 年 9 月 20 日,Svelte 团队发布了Svelte 5 的Runes。这项基于信号的框架内部重写实现了更细粒度的、类似 SolidJS 的编译时响应式编程!或许,完美的世界离我们并不遥远…… 🎉

充满异域风情的神奇美元

如果说 Svelte 有什么值得挑剔的地方,那无疑是它大胆地改变了 JavaScript 中一个鲜少使用的特性——标签(labels)的语义。这种$语法既是 Svelte 语言中最优雅精妙之处,也是最奇特、最神奇的特性。

在本次评测的开头,我强调 Svelte 一直致力于证明 UI 框架背后并没有什么魔法。而这(Svelte 框架)是个例外。

作为一个 JavaScript 纯粹主义者,一开始看到 `<store>`$到处都是 `<store>` 让我感到非常震惊。我可以接受(甚至赞赏)$:标签语法,但`<store>` 前缀(例如 `<store> $store`)让我无法容忍。

一开始,我经常忘记在$访问存储值之前加上前缀。说实话,这挺让人沮丧的,尤其是考虑到它对我来说太过神奇。我知道这样会简化成更冗长的subscribe模式,但我内心那个完美主义者还是忍不住对这种非标准的语义感到不适。最终我还是接受了这种语法,但过程确实很不适应。

每当我教 JavaScript 初学者 Svelte 时,我总是会强调它的$语法是 Svelte 特有的非标准特性。作为一名导师,每次讲课前都要重复这样的免责声明,最终难免会让人感到厌烦。但没办法,这种反复提醒是必要的——否则我们很容易陷入只做 Svelte 开发者的陷阱,而忽略了 JavaScript 开发者的本质

赋能大师班

在我的所有大型项目中,Svelte 已成为我的首选框架。在我多年的全栈开发经验中,没有其他框架能像它一样接近完美(至少目前如此!)。

  • 入职门槛低(即,只需掌握 HTML、CSS 和 JS 即可)。
  • 出色的文档和互动式游乐场。
  • 除了上述$语法之外,框架几乎没有其他特殊功能。
  • 性能开销极小(除了前面提到的“粒度不够细”的脚炮之外),如果有的话。
  • 模板语言背后有着优美直观的语法和语义。
  • 保持零成本2抽象(或最小开销)的精神。
  • (使用 SvelteKit)在渲染策略方面实现最大的路由级灵活性。
  • 简化的开发者工作流程和插件系统(感谢 Vite)。

正是基于以上种种原因,我才毫不犹豫地在系里大力推广 Svelte。仅在上个学期,我就亲自领导了几个成功的 Svelte 项目。事实上,其中许多项目都涉及对完全新手和经验丰富的开发人员的培训无论团队构成如何,Svelte 都从未让项目失败。我曾为其他团队提供技术咨询,结果也同样如此。

细心的读者或许会注意到这篇评论的一个共同主题:赋能。Svelte 及其零成本理念赋予团队力量,让他们能够轻松自信地快速行动。

由于 Svelte 不需要火箭科学学位就能理解,它也让人们相信自己能力构建全栈应用程序;前端开发可以很直观;后端开发不必那么可怕;而且他们比最初想象的更有能力。13

这就是为什么 Svelte 是赋能领域的典范。


毋庸置疑,我是Svelte 团队的忠实拥趸。我要感谢他们赋能开发者,保持创新精神,并不断拓展全栈 Web 开发的边界。


  1. 当然,除了必需的部分之外!这些必需部分包括:水合代码、客户端路由和效果调度。请注意,如果您决定完全预渲染页面(即静态网站生成), 则这些实际上是可选的。↩

  2. 我所说的“零成本”是指 C++ 意义上的,框架特性只有在实际使用时才会被编译并打包到最终的软件包中。此外,这些被编译和打包的特性不可能通过手工编写得更好。 

  3. 是的,Svelte 是一种编程语言。 

  4. 在Svelte的术语中,这叫做补水。 

  5. 在 Svelte 术语中,这被称为渲染。 

  6. 或许并非完全零成本,因为 SvelteKit 的 SSR 功能需要(额外的开销)一个与 Node.js 兼容的 JavaScript 运行时环境,而不是像 Rust 或 Go 等语言编写的外部 Web 服务器底层。当然,也有办法解决这个问题,但这超出了本文的讨论范围 。↩

  7. 请注意,如今 SvelteKit并非唯一支持这种灵活性的框架。不过,这超出了本文的讨论范围 。↩

  8. 是的,我知道在 React 中也可以做到这一点useRef,但这并非我们今天讨论的重点 。↩

  9. 这个库似乎很受Sveltesvelte-chartjs开发者的欢迎。 

  10. 所谓“必要”,我的意思是,如果我们自己编写集成代码,将会非常繁琐。也就是说,之所以“繁琐”,是因为我们必须考虑诸多潜在问题才能确保其正确运行:双向数据绑定、重新渲染、缓存、性能等等 

  11. 这就是许多初学者在未先学习 JavaScript 基础知识的情况下 就急于学习React时容易陷入的陷阱

  12. 有些团队使用 Electron 构建了 CSR Svelte 应用。另一些团队则选择了传统的混合 SSR 和 CSR 方案。在我的一些项目中,SvelteKit 已成为我首选的 SSG 解决方案 

  13. 事实上,我的一位朋友在被我推荐 Svelte 后,仅用了三个月时间就从零基础跃升为 AWS 认证的云从业者 

文章来源:https://dev.to/somedood/svelte-reviewed-a-masterclass-on-empowerment-2544