Svelte 5 正式发布
我们迄今为止最大的版本
经过近 18 个月的开发,包含来自数十位贡献者的数千次提交,Svelte 5 终于稳定发布。
这是该项目历史上最重要的版本。Svelte 5 进行了彻底的重写:您的应用程序将更快、更小、更可靠。您将能够编写更一致、更符合惯例的代码。对于框架的新手来说,学习内容也更少了。
尽管如此,Svelte 几乎完全向后兼容 Svelte 4——对于大多数用户来说,初始升级将完全无缝。
{
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"svelte": "^5",
// …
}
}
什么是 Svelte?
Svelte 是一个用于构建 Web 用户界面的框架。它使用编译器将基于 HTML、CSS 和 JavaScript 的声明式组件代码转换为紧密优化的 JavaScript。
由于编译器将大量工作从浏览器转移到 npm run build
,因此 Svelte 应用程序体积小且速度快。但除此之外,Svelte 旨在成为一种愉快且直观的构建应用程序的方式:它优先考虑完成任务。
Svelte 背后的团队还维护着 SvelteKit,这是一个应用程序框架,它处理路由和数据加载以及服务器端渲染,以及构建现代网站和应用程序所需的所有复杂细节。
发生了哪些变化,以及原因是什么?
首先,我们对我们的网站进行了全面改版。您可以在 此处 阅读更多相关信息。
至于 Svelte 本身,我们先来讨论一下“为什么”。我们不喜欢为了改变而改变——事实上,从 2019 年(我们推出 Svelte 3)到现在,Svelte 的变化比任何其他主要框架都要少,这在前端开发中是一个漫长的时期。而且人们非常喜欢 Svelte 3 和 4——它经常在开发者满意度调查中名列前茅。
因此,当我们进行更改时,我们不会轻易做出决定。
随着越来越多的人使用 Svelte 构建越来越大规模的应用程序,我们一些原始设计决策的局限性开始变得更加明显。例如,在 Svelte 4 中,响应性完全由编译器驱动。如果您更改 Svelte 4 中响应式对象的单个属性,则整个对象将失效,因为这是编译器所能做到的全部。同时,其他框架采用了基于信号的细粒度响应性,从而超越了 Svelte 的性能。
同样,组件组合在 Svelte 4 中比它应该的要笨拙,这主要是因为它将事件处理程序和“插槽内容”视为单独的概念,与传递给组件的 props 不同。这是因为在 2019 年,Web Components 似乎很可能成为组件的主要分发机制,我们希望与平台保持一致。这是一个错误。
虽然 $:
用于响应式地重新运行语句的结构是一个巧妙的技巧,但事实证明它是一个“坑”。它将两个概念(派生状态和副作用)混淆了,而这两个概念实际上应该保持分离,并且由于依赖项是在语句编译时(而不是运行时)确定的,因此它难以重构并成为复杂性的来源。
Svelte 5 消除了这些不一致性和“坑”。它引入了符文,这是一种明确的机制(除其他外)用于声明响应式状态。
let count = 0;
let let count: number
count = function $state<0>(initial: 0): 0 (+1 overload)
namespace $state
$state(0);
与状态的交互保持不变:与其他框架不同,在 Svelte 中,count
只是一个数字,而不是一个函数,或一个具有 value
属性的对象,或者只能使用相应的 setCount
进行更改的对象。
function function increment(): void
increment() {
let count: number
count += 1;
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log({ count: number
count });
}
除了 .svelte
组件之外,符文还可以在 .svelte.js
和 .svelte.ts
模块中使用,这意味着您可以使用单个机制创建可重用的响应式逻辑。
事件处理程序现在就像任何其他 props 一样,这使得(例如)很容易知道您的组件的用户是否提供了特定的事件处理程序(这对于避免昂贵的设置工作很有用),或者将任意事件处理程序传播到某些元素上——这些对于库作者来说尤其重要。
并且用于在组件之间传递内容的 slot
机制(以及令人困惑的 let:
和 <svelte:fragment>
语法)已被 {#snippet …}
替换,后者是一个功能更强大的工具。
除了这些更改之外,还有无数的改进:原生 TypeScript 支持(不再需要预处理器!)、许多错误修复以及全面的性能和可扩展性改进。
如何升级?
如果您目前使用的是 Svelte 3,请先 迁移到 Svelte 4。
然后,您可以更新您的 package.json
以使用最新版本的 svelte
和辅助依赖项(如 vite-plugin-svelte
)。
您**不必**立即更新您的组件——在几乎所有情况下,您的应用程序都将继续按原样工作(只是速度更快)。但我们建议您开始迁移您的组件以使用新的语法和功能。您可以使用 npx sv migrate svelte-5
迁移整个应用程序,或者——如果您在使用带有 Svelte 扩展的 VS Code——您可以通过在命令面板中选择“将组件迁移到 Svelte 5 语法”来逐个迁移组件。
Svelte 拥有一个庞大而强大的组件库生态系统,您可以在您的应用程序中使用它们,例如 shadcn-svelte、Skeleton 和 Flowbite Svelte。但是,您不必等到这些库升级到 Svelte 5 才能升级您自己的应用程序。
最终,对 Svelte 4 语法的支持将逐步淘汰,但这不会很快发生,您将有充足的预警。
有关更多详细信息,请参阅 完整的 Svelte 5 迁移指南。
我们的新 CLI
除了 Svelte 的新版本外,我们还提供了一个新的命令行界面 (CLI),即 sv
。您可以在 发布博客文章 中了解所有相关信息。
接下来是什么?
我们计划在不久的将来发布 SvelteKit 的新版本,该版本将利用新的 Svelte 5 功能。同时,您现在就可以将 Svelte 5 与 SvelteKit 一起使用,并且 npx sv create
将创建一个新的 SvelteKit 项目,并在其中安装 Svelte 5。
之后,我们还有很多想要在 Svelte 本身中实现的想法。此版本是许多改进的基础,这些改进在 Svelte 4 之上是不可能实现的,我们迫不及待地想要撸起袖子加油干了。