普通视图

发现新文章,点击刷新页面。
昨天 — 2025年7月25日首页

为什么越来越多开发者偷偷用上了 Svelte?

作者 天涯学馆
2025年7月25日 21:07

说真的,前端框架这几年太卷了。React、Vue、Angular 打得火热,每年还有新秀冒出来。就在大家还在比较 hooks 和 Composition API 的时候,Svelte 悄悄杀出来了,而且很多资深开发者正在偷偷用。

第一次上手 Svelte 的感觉,就像从写作文变成填空题——没有冗长的 boilerplate、没有烦人的状态管理库,一切都干净、直接、高效。它不是像 React/Vue 那样运行时处理 DOM,而是编译时就把你的代码变成原生 JS 操作,这让它的速度快得吓人。

如果你厌倦了“前端框架越来越重”,想找一个轻巧但不牺牲体验的选择,Svelte 可能就是你要找的那把钥匙。

Svelte 简介

Svelte 是一个现代前端框架,与 React 和 Vue 不同,它是一个编译时框架,将组件代码在构建时转换为高效的原生 JavaScript,无需运行时库。Svelte 的核心理念是“Compile-time over runtime”,通过在编译阶段完成大部分工作,生成轻量、高性能的代码。

Svelte 的核心特性

  • 编译时优化:组件编译为纯 JavaScript,无虚拟 DOM 开销。
  • 响应式系统:基于编译时的变量追踪,简化状态管理。
  • 轻量级:无运行时库,生成的代码体积小。
  • 简洁语法:接近原生 HTML/CSS/JS,学习曲线低。
  • 内置功能:动画、过渡、插槽、上下文 API 开箱即用。

前端价值

  • 提升性能(快速加载、流畅交互)。
  • 降低开发复杂度(简洁 API、零配置)。
  • 适合多种场景(从静态网站到复杂应用)。

本教程基于 Svelte 3 和 SvelteKit 1.x(截至 2025 年 5 月 26 日的稳定版本),涵盖 Svelte 的优势、实现方式及应用场景。

Svelte 的核心优势

1. 编译时框架:无运行时开销

Svelte 的最大优势是其编译时架构。与 React 和 Vue 依赖运行时虚拟 DOM 不同,Svelte 在构建时将组件编译为高效的原生 JavaScript,直接操作 DOM。

示例(简单计数器):
Counter.svelte

<script>
    let count = 0;
    
    function increment() {
        count += 1;
    }
</script>

<button on:click={increment}>
    Count: {count}
</button>

编译后(简化版)

function create_fragment(ctx) {
    let button;
    let t;
    return {
        c() {
            button = element("button");
            t = text("Count: " + ctx[0]);
            add_listener(button, "click", ctx[1]);
        },
        m(target, anchor) {
            insert(target, button, anchor);
            append(button, t);
        },
        p(ctx, [dirty]) {
            if (dirty & 1) set_data(t, "Count: " + ctx[0]);
        },
        d(detaching) {
            if (detaching) detach(button);
            remove_listener(button, "click", ctx[1]);
        }
    };
}

class Counter extends SvelteComponent {
    constructor(options) {
        super();
        init(this, options, instance, create_fragment, safe_not_equal, {});
    }
}
  1. Svelte 编译器将组件转换为纯 JavaScript 函数(如 create_fragment)。
  2. 直接操作 DOM(如 elementappend),无虚拟 DOM Diff。
  3. 更新逻辑(如 p 方法)仅针对变化的变量(count)。

优势

  • 性能:无运行时库,减少 JavaScript 解析和执行开销。
  • 体积:生成代码小,适合移动设备。
  • 确定性:编译时优化确保一致的性能。

与 React 对比

  • React:

    function Counter() {
        const [count, setCount] = useState(0);
        return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
    }
    
  • React 依赖运行时(ReactDOM)、虚拟 DOM Diff,增加开销。

  • Svelte 的编译结果更轻量,运行时开销接近零。

面试题 1:编译时 vs 运行时

问题:Svelte 的编译时架构相比运行时框架(如 React)有何优势?

答案

  • 优势
    • 无运行时库,减少包体积(React ~30KB,Svelte ~2KB)。
    • 直接 DOM 操作,性能接近原生。
    • 编译时优化,减少浏览器计算。
  • 局限
    • 编译步骤增加构建时间。
    • 动态组件(如 React.createElement)支持较弱。

2. 响应式系统:简洁高效

Svelte 的响应式系统基于编译时的变量追踪,无需显式状态管理(如 useState)。

示例(响应式计算):

<script>
    let a = 1;
    let b = 2;
    $: sum = a + b; // 响应式声明
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>
<p>Sum: {sum}</p>

编译后(简化版)

function instance($$self, $$props, $$invalidate) {
    let a = 1;
    let b = 2;
    let sum;
    
    $$self.$$.update = () => {
        if ($$self.$$.dirty & 3) {
            sum = a + b;
        }
    };
    
    return [a, b, sum, e => $$invalidate(0, a = +e.target.value), e => $$invalidate(1, b = +e.target.value)];
}
  1. $: 标记响应式依赖,编译器生成更新逻辑。
  2. $$invalidate 标记变量变化,触发局部更新。
  3. 无需 useStatesetState,代码简洁。

优势

  • 简洁:响应式声明直观,减少样板代码。
  • 高效:编译时追踪依赖,更新精确。
  • 直观:接近原生 JavaScript 语法。

与 Vue 对比

  • Vue:

    <template>
        <div>
            <input v-model="a" type="number">
            <input v-model="b" type="number">
            <p>Sum: {{ sum }}</p>
        </div>
    </template>
    <script>
    export default {
        data() {
            return { a: 1, b: 2 };
        },
        computed: {
            sum() {
                return this.a + this.b;
            }
        }
    };
    </script>
    
  • Vue 使用 computed 和运行时代理,增加开销。

  • Svelte 的响应式更轻量,无需运行时代理。

面试题 2:Svelte 响应式

问题:Svelte 的响应式系统如何工作?与 Vue 的区别?

答案

  • Svelte
    • 编译时分析 $: 声明,生成更新逻辑。
    • 直接修改变量触发更新,无代理。
    • 性能高,代码量少。
  • Vue
    • 运行时使用 ProxyObject.defineProperty
    • computedwatch 定义依赖。
    • 运行时开销较高。

3. 轻量级:小体积高性能

Svelte 生成的代码体积极小,适合性能敏感场景。

示例(Todo 应用):
Todo.svelte

<script>
    let todos = [];
    let newTodo = '';
    
    function addTodo() {
        if (newTodo.trim()) {
            todos = [...todos, { id: Date.now(), text: newTodo, done: false }];
            newTodo = '';
        }
    }
    
    function toggleTodo(id) {
        todos = todos.map(todo =>
            todo.id === id ? { ...todo, done: !todo.done } : todo
        );
    }
</script>

<form on:submit|preventDefault={addTodo}>
    <input bind:value={newTodo} placeholder="Add todo">
    <button type="submit">Add</button>
</form>

<ul>
    {#each todos as todo (todo.id)}
        <li>
            <input type="checkbox" checked={todo.done} on:change={() => toggleTodo(todo.id)}>
            <span class:done={todo.done}>{todo.text}</span>
        </li>
    {/each}
</ul>

<style>
    .done {
        text-decoration: line-through;
        opacity: 0.5;
    }
</style>

编译后

  • 生成的 JS 代码约 2-3KB(压缩后)。
  • 无运行时依赖,加载速度快。

优势

  • 小体积:适合移动设备和弱网环境。
  • 快速加载:减少初始解析时间。
  • 低内存占用:无虚拟 DOM 和运行时状态。

与 React 对比

  • React 的 Todo 应用(含 React 和 ReactDOM)约 30-40KB。
  • Svelte 的代码体积仅为其 1/10。

面试题 3:Svelte 轻量级

问题:Svelte 的轻量级特性如何影响性能?

答案

  • 影响
    • 减少 JavaScript 解析和执行时间。
    • 降低内存占用,适合低端设备。
    • 提高首屏渲染速度(FCP、LCP)。
  • 场景:移动端、嵌入式设备、弱网环境。

4. 简洁语法与开发者体验

Svelte 的语法接近原生 HTML/CSS/JS,学习成本低。

示例(动画):

<script>
    import { fade } from 'svelte/transition';
    let visible = true;
</script>

<button on:click={() => visible = !visible}>
    Toggle
</button>

{#if visible}
    <div transition:fade={{ duration: 500 }}>
        Hello, Svelte!
    </div>
{/if}
  • transition:fade 内置动画,无需额外库。
  • 语法直观,接近原生 HTML。

优势

  • 易学:适合初学者和快速原型开发。
  • 内置功能:动画、插槽、上下文 API 减少依赖。
  • CSS 作用域:自动添加唯一类名,避免冲突。

与 Vue 对比

  • Vue 的动画需 transition 组件和 CSS:

    <transition name="fade">
        <div v-if="visible">Hello, Vue!</div>
    </transition>
    <style>
    .fade-enter-active, .fade-leave-active {
        transition: opacity 0.5s;
    }
    .fade-enter, .fade-leave-to {
        opacity: 0;
    }
    </style>
    
  • Svelte 的动画更简洁,内置支持。

Svelte 的实现与实践

项目搭建

使用 SvelteKit

SvelteKit 是 Svelte 的全栈框架,支持 SSR、SSG 和 SPA。

初始化项目

npm create svelte@latest svelte-demo
cd svelte-demo
npm install
npm run dev

项目结构

svelte-demo/
├── src/
│   ├── lib/              # 共享代码
│   ├── routes/           # 页面和 API 路由
│   │   ├── +page.svelte  # 首页
│   │   └── api/          # API 端点
│   └── app.html          # 应用模板
├── static/               # 静态资源
├── svelte.config.js      # 配置
└── vite.config.js        # Vite 配置

第一个组件

src/routes/+page.svelte

<script>
    let name = '';
</script>

<h1>Welcome to Svelte</h1>
<input bind:value={name} placeholder="Enter your name">
<p>Hello, {name || 'Guest'}!</p>
  • SvelteKit 使用文件系统路由,+page.svelte 对应 / 路由。
  • bind:value 双向绑定,简化表单处理。

状态管理

Svelte 使用响应式变量Store管理状态。

Store 示例

src/lib/store.js

import { writable } from 'svelte/store';

export const count = writable(0);

Counter.svelte

<script>
    import { count } from '$lib/store';
</script>

<button on:click={() => $count += 1}>
    Count: {$count}
</button>
  • writable 创建可写 Store。
  • $count 自动订阅和更新,语法简洁。

与 Redux 对比

  • Redux(React):

    import { useSelector, useDispatch } from 'react-redux';
    import { increment } from './store';
    
    function Counter() {
        const count = useSelector(state => state.count);
        const dispatch = useDispatch();
        return <button onClick={() => dispatch(increment())}>Count: {count}</button>;
    }
    
  • Redux 需样板代码(action、reducer),Svelte Store 更直观。

面试题 4:Svelte Store

问题:Svelte 的 Store 与 React 的 Redux 相比有何优势?

答案

  • Svelte Store
    • 内置,无需额外库。
    • 简洁 API(如 $count)。
    • 编译时优化,性能高。
  • Redux
    • 配置复杂,需 action/reducer。
    • 运行时开销大。
    • 适合大型应用。

路由与 SSR

SvelteKit 支持文件系统路由和服务器端渲染(SSR)。

示例(动态路由)

src/routes/blog/[id]/+page.svelte

<script>
    export let data;
</script>

<h1>Blog Post: {data.id}</h1>
<p>{data.content}</p>

src/routes/blog/[id]/+page.server.js

export async function load({ params }) {
    // 模拟数据库查询
    const post = {
        id: params.id,
        content: `This is post ${params.id}`
    };
    return { post };
}
  • [id] 创建动态路由,匹配 /blog/1 等。
  • +page.server.js 处理服务器端数据加载。
  • SSR 提升 SEO 和首屏速度。

Svelte 与其他框架的对比

性能对比

基准测试(基于 js-framework-benchmark):

  • Svelte

    • 渲染时间:~10ms(1000 行表格)。
    • 内存占用:~20MB。
    • 包体积:~2KB(压缩)。
  • React

    • 渲染时间:~15ms。
    • 内存占用:~30MB。
    • 包体积:~30KB。
  • Vue

    • 渲染时间:~12ms。
    • 内存占用:~25MB。
    • 包体积:~20KB。
  • Svelte 在渲染速度、内存占用和包体积上领先。

  • 适合性能敏感场景。

开发体验对比

  • Svelte
    • 简洁语法,学习曲线低。
    • 内置功能丰富(动画、Store)。
    • 无需复杂配置。
  • React
    • 需掌握 Hooks、Context 等。
    • 依赖第三方库(如 Redux、React Router)。
    • JSX 增加学习成本。
  • Vue
    • 语法友好,但 Options API 较繁琐。
    • Composition API 更灵活,但学习成本高。
    • 运行时代理增加开销。

Svelte 的性能优化

1. 编译优化

Svelte 编译器默认优化代码,可通过配置进一步提升。

svelte.config.js

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';

export default {
    preprocess: vitePreprocess(),
    kit: {
        adapter: adapter(),
        vite: {
            optimizeDeps: {
                include: ['lodash']
            }
        }
    }
};

分析

  • Vite 预打包依赖,加速开发。
  • -O3 优化生成更小代码。

2. 懒加载组件

示例

<script>
    import { onMount } from 'svelte';
    let HeavyComponent = null;
    
    onMount(async () => {
        HeavyComponent = (await import('./HeavyComponent.svelte')).default;
    });
</script>

{#if HeavyComponent}
    <svelte:component this={HeavyComponent} />
{/if}

分析

  • 动态导入减少初始加载时间。
  • 适合大型组件。

3. Workbox 集成(PWA)

配置 SvelteKit 为 PWA

npm install -D @sveltejs/vite-plugin-pwa

vite.config.js

import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { SvelteKitPWA } from '@sveltejs/vite-plugin-pwa';

export default defineConfig({
    plugins: [
        sveltekit(),
        SvelteKitPWA({
            manifest: {
                name: 'Svelte PWA',
                short_name: 'SveltePWA',
                start_url: '/',
                display: 'standalone',
                icons: [
                    {
                        src: '/icon-192.png',
                        sizes: '192x192',
                        type: 'image/png'
                    }
                ]
            }
        })
    ]
});

分析

  • 自动生成 Service Worker 和 Manifest。
  • 支持离线访问和推送通知。

与 WebAssembly 整合

Svelte 结合 WebAssembly 提升性能。

示例:Markdown 解析

Rust 代码src/lib.rs):

use wasm_bindgen::prelude::*;
use pulldown_cmark::{html, Parser};

#[wasm_bindgen]
pub fn render_markdown(md: &str) -> String {
    let parser = Parser::new(md);
    let mut html_output = String::new();
    html::push_html(&mut html_output, parser);
    html_output
}

编译

wasm-pack build --target web

Svelte 组件

<script>
    import { onMount } from 'svelte';
    let markdown = '# Hello\nThis is **Svelte**!';
    let html = '';
    
    onMount(async () => {
        const { render_markdown } = await import('../pkg/markdown.js');
        html = render_markdown(markdown);
    });
</script>

<textarea bind:value={markdown}></textarea>
<div>{@html html}</div>
  • WASM 加速 Markdown 解析。
  • Svelte 管理 UI,响应式更新。

所以说,Svelte 不是什么“前端框架终结者”,但它真的像一股清流,在复杂繁重的前端世界里提供了一种更轻松的可能性。写起来更像原生 JS,跑得也快,部署后的包又小,适合那种不想折腾、但又追求性能的你。

当然,每个项目都有自己的需求。大型团队可能更适合用 React,生态全、组件库多;但如果你在做个人项目、组件库、嵌入式小模块,甚至是纯静态网站,Svelte 真的是一个值得一试的好朋友。

别听别人说什么框架死不死的,自己动手写两页代码,你就知道它香不香了。技术这回事,体验才是最好的判断标准。

❌
❌