Chapter 01

Svelte 5 简介与 Runes 响应式革新

理解编译时框架的核心思想,掌握 Runes 响应式系统,搭建你的第一个 SvelteKit 项目

什么是编译时框架?

传统运行时框架的工作方式

React 和 Vue 是运行时框架:你的应用代码和框架代码一起打包,在浏览器中运行。React 需要在内存中维护一棵虚拟 DOM 树(Virtual DOM),每次状态变化时,React 会重新渲染出一棵新的虚拟 DOM 树,与旧树对比(Diffing),找出差异,再将差异应用到真实 DOM 上——这个过程叫做Reconciliation(调和)

这种设计的优点是灵活,但缺点也很明显:浏览器必须加载整个框架运行时(React 约 45KB gzip),而且每次更新都要执行 diffing 算法,在复杂应用中产生不必要的计算开销。

Svelte 的编译时思路

Svelte 的作者 Rich Harris 提出了一个不同的问题:"如果我们把这些工作放到构建时来做,而不是放到运行时,会怎样?"

Svelte 是一个编译器——你写的 .svelte 组件文件,经过 Svelte 编译器处理后,会变成精简的、命令式的 JavaScript 代码,这些代码直接精确地操作 DOM,不需要任何框架运行时在场。浏览器加载的只是你自己的业务代码,没有额外的框架 overhead。

编译输出示例

一个简单的 Svelte 计数器组件,编译后大约只有 500 字节的 JavaScript,而相同功能的 React 应用需要下载约 45KB 的 React 运行时 + 你的代码。

React / Vue / Svelte 核心差异对比

维度ReactVue 3Svelte 5
框架性质运行时库运行时框架编译器
虚拟 DOM有(VDOM)有(VDOM)
运行时体积~45KB gzip~22KB gzip~2KB gzip
响应式方式useState/hooksref/reactiveRunes ($state 等)
模板语言JSX模板+Composition API.svelte 单文件组件
CSS 作用域CSS Modules/styledscoped attribute编译期自动作用域
全栈框架Next.jsNuxtSvelteKit

Svelte 的发展历程

2016 年
Rich Harris 发布 Svelte 1.0,提出"无运行时框架"概念,颠覆了前端框架的固有思维。
2019 年 Svelte 3
全面重写,引入魔法式响应式变量(let count = 0 自动追踪变化)、组件生命周期 API,引发广泛关注。
2021 年 SvelteKit
官方全栈框架发布,提供文件系统路由、SSR/SSG、Adapter 多平台部署支持,对标 Next.js。
2024 年 Svelte 5
革命性引入 Runes 系统,彻底重构响应式机制,解决了 Svelte 3/4 中响应式的诸多限制,成为生产级首选。

认识 Runes 系统

旧版响应式的局限性

在 Svelte 3/4 中,响应式是通过魔法赋值实现的:只要在 <script> 标签中声明的变量被重新赋值,Svelte 就会自动更新对应的 DOM。这听起来很方便,但有严重的局限:

Runes:显式的响应式原语

Runes(符文)是 Svelte 5 引入的一套以 $ 前缀开头的特殊函数,用于显式声明响应式状态。它们不是普通的 JavaScript 函数,而是 Svelte 编译器能识别的特殊语法,会在编译期被转换为高效的响应式代码。

$state()
声明响应式状态变量。等同于 React 的 useState,但更简洁。支持对象和数组的深层响应式追踪。
$derived()
声明派生值——依赖其他响应式状态自动计算的值。等同于 Vue 的 computed。
$effect()
声明副作用——当依赖的响应式状态变化时自动重新运行的函数。等同于 React 的 useEffect。
$props()
在组件内声明接收的 props,替代旧版的 export let。返回包含所有 props 的对象。
$bindable()
声明可从父组件绑定的 prop(允许父组件用 bind:propName 双向绑定)。
<!-- Svelte 5 Runes 示例 -->
<script>
  // $state() 声明响应式变量
  let count = $state(0);

  // $derived() 声明派生值
  let doubled = $derived(count * 2);

  // $effect() 声明副作用
  $effect(() => {
    console.log(`count changed to ${count}`);
  });

  function increment() {
    count++;
  }
</script>

<button onclick={increment}>
  Count: {count} (doubled: {doubled})
</button>

安装 SvelteKit 项目

前置要求

你需要安装 Node.js 18+(推荐 LTS 版本)和 npm / pnpm / bun 包管理器。验证安装:

node --version   # v20.x.x 或更高
npm --version    # 10.x.x 或更高

创建项目

# 使用官方脚手架创建 SvelteKit 项目
npx sv create my-app

# 交互式选择:
# Template: SvelteKit minimal / SvelteKit demo app
# TypeScript: Yes (strongly recommended)
# Add-ons: ESLint, Prettier, Vitest

# 进入目录并安装依赖
cd my-app
npm install

# 启动开发服务器
npm run dev

# 打开 http://localhost:5173

SvelteKit 项目目录结构

my-app/ ├── src/ │ ├── routes/ # 页面路由目录(文件即路由) │ │ ├── +page.svelte # 首页 / │ │ ├── +layout.svelte # 全局布局 │ │ └── about/ │ │ └── +page.svelte # /about 页面 │ ├── lib/ # 可被 $lib 别名引用的模块 │ │ ├── components/ # 可复用组件 │ │ └── utils/ # 工具函数 │ └── app.html # HTML 模板(注入点) ├── static/ # 静态资源(直接复制到 build) ├── svelte.config.js # SvelteKit 配置 ├── vite.config.ts # Vite 构建配置 ├── tsconfig.json # TypeScript 配置 └── package.json

.svelte 文件的三个部分

每个 .svelte 文件都是一个自包含的组件,由三个可选部分组成:

<!-- src/routes/+page.svelte -->

<!-- 1. Script 块:组件逻辑 -->
<script lang="ts">
  // TypeScript / JavaScript 代码
  // 组件状态、函数、导入
  import { page } from '$app/stores';

  let title = $state('Hello Svelte!');
</script>

<!-- 2. Template 块:HTML 模板(无需特定标签包裹) -->
<h1>{title}</h1>
<p>当前路径:{$page.url.pathname}</p>

<!-- 3. Style 块:组件作用域样式 -->
<style>
  /* 这里的样式只作用于当前组件 */
  h1 {
    color: #FF3E00;
    font-size: 2rem;
  }
</style>
lang="ts" 强烈推荐

在 script 标签添加 lang="ts" 启用 TypeScript。SvelteKit 内置完整的 TypeScript 支持,包括路由参数类型、load 函数返回值类型等,能显著提升开发体验和代码健壮性。

第一个完整示例:计数器应用

创建计数器组件

<!-- src/lib/components/Counter.svelte -->
<script lang="ts">
  // 使用 $props() 声明接收的 props
  let { initialValue = 0, label = 'Count' } = $props<{
    initialValue?: number;
    label?: string;
  }>();

  // 使用 $state() 声明响应式状态
  let count = $state(initialValue);

  // 使用 $derived() 派生值
  let isEven = $derived(count % 2 === 0);
  let status = $derived(isEven ? '偶数' : '奇数');

  // 使用 $effect() 追踪副作用
  $effect(() => {
    document.title = `${label}: ${count}`;
  });

  function increment() { count++; }
  function decrement() { count--; }
  function reset() { count = initialValue; }
</script>

<div class="counter">
  <h2>{label}</h2>
  <div class="display">
    <button onclick={decrement}>-</button>
    <span class:even={isEven}>{count}</span>
    <button onclick={increment}>+</button>
  </div>
  <p>状态:{status}</p>
  <button onclick={reset}>重置</button>
</div>

<style>
  .counter {
    padding: 1.5rem;
    border: 1px solid #ff3e00;
    border-radius: 8px;
    text-align: center;
  }
  .display {
    display: flex;
    align-items: center;
    gap: 1rem;
    justify-content: center;
    margin: 1rem 0;
  }
  span { font-size: 2rem; font-weight: bold; }
  /* :global() 用于选择子组件元素 */
  span.even { color: #4ade80; }
</style>

在页面中使用组件

<!-- src/routes/+page.svelte -->
<script lang="ts">
  import Counter from '$lib/components/Counter.svelte';
</script>

<main>
  <h1>Svelte 5 计数器演示</h1>
  <Counter initialValue={10} label="购物车数量" />
  <Counter label="浏览次数" />
</main>
Svelte 5 与 Svelte 4 的兼容性

Svelte 5 提供了旧版 API 的兼容层,现有的 Svelte 4 代码可以在 Svelte 5 中运行。但新项目强烈推荐直接使用 Runes。混用旧版 $: 语法和 Runes 时,Svelte 会提示警告。

开发工具推荐

VS Code 扩展
安装「Svelte for VS Code」(svelte.svelte-vscode),提供语法高亮、类型检查、代码补全、组件跳转等功能。
Svelte DevTools
浏览器扩展(Chrome/Firefox),可在开发时检查 Svelte 组件树、查看响应式状态值,调试利器。
Vite HMR
SvelteKit 基于 Vite 构建,享有极快的热模块替换(HMR),保存文件后页面状态保留并即时更新。
Prettier + svelte 插件
安装 prettier-plugin-svelte,格式化 .svelte 文件,保持团队代码风格一致。
# 查看项目依赖和可用脚本
cat package.json

# 常用命令
npm run dev      # 启动开发服务器(端口 5173)
npm run build    # 生产构建
npm run preview  # 预览生产构建结果
npm run check    # TypeScript 类型检查
npm run lint     # ESLint 代码检查
npm run format   # Prettier 格式化
在线试验 Svelte

访问 svelte.dev/playground 可以在浏览器中直接试验 Svelte 5 代码,无需本地安装,非常适合快速验证想法。