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 是一個用於在網路上建立使用者介面的框架。它使用編譯器將基於 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 年,網頁元件似乎很可能成為元件的主要發布機制,而我們希望與平台保持一致。這是一個錯誤。
雖然用於響應式重新執行語句的 $:
結構是一個巧妙的技巧,但它最終變成了一個陷阱。它混淆了兩個概念(衍生狀態和副作用),這兩個概念應該分開,而且由於依賴項是在編譯語句時(而不是在執行語句時)確定的,因此它會阻礙重構並成為複雜性的磁鐵。
Svelte 5 消除了這些不一致性和陷阱。它引入了 runes,這是一種(除其他外)宣告響應式狀態的明確機制
let count = 0;
let let count: number
count = function $state<0>(initial: 0): 0 (+1 overload)
namespace $state
Declares reactive state.
Example:
let count = $state(0);
$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
元件之外,runes 還可以用在 .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 之上,我們迫不及待地想要捲起袖子開始工作了。