Skip to main content

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 和 Svelte 4——它经常在开发者满意度调查中名列前茅。

因此,当我们做出改变时,我们会慎重考虑。

随着越来越多的人用 Svelte 构建越来越多、更大的应用程序,我们的一些原始设计决策的局限性开始变得更加明显。例如,在 Svelte 4 中,响应性完全由编译器驱动。如果您在 Svelte 4 中更改一个响应式对象的单一属性,整个对象都会失效,因为这几乎是编译器唯一能做到的。而与此同时,其他框架已经采用基于 signals 的细粒度响应性,在性能上超越了 Svelte。

同样,在 Svelte 4 中的组件组合比它应该的样子更为笨拙,主要是因为它将事件处理函数和“插槽内容”视为与传递给组件的 props 不同的概念。这是因为在 2019 年,我们认为 Web 组件可能会成为组件的主要分发机制,因此我们希望与平台保持一致。但事实证明这是一个错误。

而使用 $: 构造符以响应方式重新运行语句虽然是一个巧妙的设计,但最终却成为一种陷阱。它将两个本应分开的概念(派生状态和副作用)混为一谈,并且因为依赖关系是在语句被编译时(而非运行时)确定的,这使得它难以重构,并且容易引入复杂性。

Svelte 5 消除了这些不一致性和陷阱。它引入了 runes,一种用于(包括声明响应式状态在内的)显式机制:

let count = 0;
let let count: numbercount = 
function $state<0>(initial: 0): 0 (+1 overload)
namespace $state

Declares reactive state.

Example:

let count = $state(0);

https://svelte.dev/docs/svelte/$state

@paraminitial The initial value
$state
(0);

与状态交互方式保持不变:与其他框架不同,在 Svelte 中,count 只是一个数字,而不是一个函数,或一个带有 value 属性的对象,或只能通过对应的 setCount 修改的东西:

let let count: numbercount = 0;
//移除
function function increment(): voidincrement() {
	let count: numbercount += 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
@seesource
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.

@sincev0.1.100
log
({ count: numbercount });
}

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

事件处理程序现在只是像其他任何 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-svelteSkeletonFlowbite Svelte。但您无需等待这些库升级到 Svelte 5 后再升级您的应用程序。

最终,我们会逐步淘汰对 Svelte 4 语法的支持,但这不会很快发生,并且我们会给予足够的通知。

有关更多详细信息,请参阅 全面的 Svelte 5 迁移指南

我们的新 CLI

随着新版本 Svelte 的发布,我们还推出了一个新的命令行界面(CLI),sv。您可以在公告博客文章中了解这一切。

接下来是什么?

我们计划在近期发布一个新版本的 SvelteKit,以利用 Svelte 5 的新特性。同时,您现在已经可以在 SvelteKit 中使用 Svelte 5,npx sv create 将创建一个同时安装了 Svelte 5 的新 SvelteKit 项目。

之后,我们有一长串想要在 Svelte 本身上实现的功能想法。此版本为许多在 Svelte 4 上无法实现的改进奠定了基础,我们迫不及待地想要开始了。