今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

OSCHINA

经过近 18 个月的开发,数十名贡献者提交了数千次代码,Svelte 5 终于发布了稳定版,这是该项目历史上最重大的版本。

Svelte 是一款类似 React、Vue 的前端 UI 框架。

如名字所言, Svelte 的体积超级小,其作者 Rich Harris 表明,他设计 Svelte 的核心思想在于“通过静态编译减少框架运行时的代码量”。

今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

Svelte 5 是一次彻底的重写:开发的应用将变得更快、更小、更可靠。同时将能够编写更一致、更符合语法习惯的代码。对于框架的新手来说,需要学习的东西更少。

值得关注的是,Svelte 几乎完全向后兼容 Svelte 4,也就是说初始升级将完全无缝:

今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

Svelt 官方介绍,随着越来越多的人使用 Svelte 构建更多、更大的应用程序,最初的一些设计决策的局限性开始变得更加明显。

例如,在 Svelte 4 中,响应性完全由编译器驱动。如果在 Svelte 4 中更改响应对象的单个属性,则整个对象将失效,由于这是编译器实际能做的全部。

与此同时,其它框架采用了基于信号的细粒度响应性,超越了 Svelte 的性能。

同样,Svelte 4 中的组件组合也比较尴尬,主要是由于它将事件处理程序和“插槽内容” (slotted content) 视为独立的概念,与传递给组件的 props 不同。

这是由于在 2019 年,Web 组件似乎很有可能成为组件的主要分发机制,而 Svelte 希望与平台保持一致。目前看,这实则是一个错误选择。

虽然 $的构造响应式重新运行语句是一个巧妙的技巧,但结果却是徒劳无功。它混淆了两个本应分开的概念(派生状态和副作用),而且由于依赖关系是在语句编译时而不是运行时确定的,因此它无法重构,搞得越来越复杂。

今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

Svelte 5 消除了这些不一致和麻烦。它引入了 runes,这是一种显式机制,用于声明响应式状态(当然它还有其它作用):

今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

与状态的交互没有改变:与其它框架不同,count 只是一个数字,而不是一个函数,或者具有值属性的对象,或者只能通过相应的 setCount 来更改的东西。

function increment {
count += 1;
console.log({ count });

}

runes 可以在 .svelte.js 和 .svelte.ts 模块中使用,除了 .svelte 组件,这意味着可以使用单一机制创建可重用的响应式逻辑。

事件处理程序目前就像其它属性一样,列如可以很容易知道组件用户是否提供了特定的事件处理程序(这对于避免昂贵的设置工作超级有用),或者将任意事件处理程序传播到某个元素上,这些对库作者尤其重大。

用于在组件之间传递内容的插槽机制,以及令人困惑的 let: 和 <svelte:fragment> 语法,已被 {#snippet …} 替代,这是一个更强劲的工具。

除了这些变化,还有无数改善:原生 TypeScript 支持(不再需要预处理器!)、许多错误修复,以及整体性能和可扩展性的提升。

此外,随着 Svelte 的新版本发布,也推出了新的命令行界面 (CLI),sv。而利用新的 Svelte 5 特性的 SvelteKit,也在计划中了。

详情查看官方公告:
https://svelte.dev/blog/svelte-5-is-alive

最后看看 Svelte 5 重大的语法更新:

Runes – 符文

本次最重大的更新,当 Runes 莫属,这是关于变量定义和效果管理的内容。

Svelte v4 的响应式写法:

<script>
let count = 0;
</script>

<button onclick={ => count++}>
clicks: {count}
</button>

Svelte v5 的响应式写法:

<script>
let count = $state(0);
</script>

<button onclick={ => count++}>
clicks: {count}
</button>

哈哈,是不是新语法有一种 Vue 的既视感?

正所谓,万法归一,殊途同归。

那么不仅如此,类似这样的语法,大致有这么些:

$state

$state.raw

$state.snapshot

$derived

$derived.by

$effect

$effect.pre

$effect.tracking

$effect.root

$props

$bindable

$inspect

$host

这不禁让我回想起了 10 年前写 PHP 的时候,满屏幕的 $的日子。。。

不过还是那句话,习惯就好,我喜爱新语法,喜爱 $

Snippets – 片段

片段的主要作用,就是让你少写重复代码。

笔者看到这个,只感觉两行感动的热泪流了下来 😭。

Vue 中的类似功能是这样的:

<script setup>import{ createReusableTemplate } from '@vueuse/core'; const[DefineTemplate,ReuseTemplate]= createReusableTemplate;</script>

<template>

<DefineTemplate>

<!-- something complex --></DefineTemplate>

<dialogv-if="showInDialog">

<ReuseTemplate/></dialog>

<divv-else>

<ReuseTemplate/></div>

</template>

Svelte v4 的写法:

{#each images as image}

{# if image.href}
<a href={image.href}>
<figure>
<img
src={image.src}
alt={image.caption}
width={image.width}
height={image.height}
/>
<figcaption>{image.caption}</figcaption>
</figure>
</a>

{:else}
<figure>
<img
src={image.src}
alt={image.caption}
width={image.width}
height={image.height}
/>
<figcaption>{image.caption}</figcaption>
</figure>

{/if}

{/each}

Svelte v5 的写法:

{#snippet figure(image)}
<figure>
<img
src={image.src}
alt={image.caption}
width={image.width}
height={image.height}
/>
<figcaption>{image.caption}</figcaption>
</figure> {
/snippet}

{#each images as image}

{#if image.href}

<a href={image.href}>
{@renderfigure(image)}
</a>

{:else}

{@renderfigure(image)}

{/if}

{/each}

代码是人在写,人在看,电脑只是执行一串二进制。

写法上的提升,对于编程体验的影响是超级大的,代码应该优先服务于人,其次才服务于机器。

这种编程体验的改变,不亚于钓鱼佬钓到一条重达 2 两的大鲫鱼的快感。

Event handlers – 事件处理

Svelte v4 单事件的写法

<script>
let count = $state(0);
</script>

<button on:click={ => count++}>
clicks: {count}
</button>

Svelte v5 单事件的写法

<script>
let count = $state(0);
</script>

<button onclick={ => count++}>
clicks: {count}
</button>

Svelte v4 多事件的写法

<button on:click={one} on:click={two}>
...
</button>

Svelte v5 多事件的写法

<button
onclick={(e) => {
one(e);
two(e);
}}
>
...
</button>

Svelte v4 事件修饰符的写法

<button on:click|once|preventDefault={handler}>...</button>

Svelte v5 事件修饰符的写法

<script>
functiononce(fn){
returnfunction(event){
if(fn) fn.call(this, event);
fn =;
};
}

functionpreventDefault(fn){
returnfunction(event){
event.preventDefault;
fn.call(this, event);
};
}
</script>

<button onclick = {
once(preventDefault(handler))
} > ... < /button>

事件上面的写法,给我的感觉就是,返璞归真了。

说实话,我喜爱原来的写法。

Imports – 导入

flushSync

<script>

import {

flushSync

}from 'svelte';

let count = $state(0);
let element;

functiononclick{
flushSync( =>(count +=1));

// without `flushSync`, the DOM would be updated in the future
console.log(element.textContent===String(count));
}
</script>

<span bind: this = {element}>{count}</span>

<button {onclick}>update</button>

mount

import {
mount
} from 'svelte';
importAppfrom './App.svelte';

const app = mount(App, {
target: document.querySelector('#app'),

props: {some: 'property'}

});

hydrate

import {
hydrate
} from 'svelte';
importAppfrom './App.svelte';

const app = hydrate(App, {
target: document.querySelector('#app'),

props: {some: 'property'}

});

本文部分内容来自「陈随易」公众号,已获授权转载。

《1年272个版本后,Svelte v5终于发布了》

相关来源

https://svelte.dev/blog/svelte-5-is-alive

https://mp.weixin.qq.com/s/J0fnK5ufOvH9_wyZUPPJ7Q

END

今年最火开源前端框架——Svelte 5正式发布稳定版、彻底重写、新增$语法 、star数近8万

© 版权声明

相关文章

暂无评论

none
暂无评论...