编译时特性 #

一、编译时框架 #

Svelte 是编译时框架,在构建阶段将组件转换为高效的 JavaScript 代码。

text
┌─────────────────────────────────────────────────────────────┐
│                    Svelte 编译流程                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  源代码 (.svelte)                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  <script>                                           │   │
│  │    let count = 0;                                   │   │
│  │  </script>                                          │   │
│  │  <button on:click={() => count++}>                 │   │
│  │    {count}                                          │   │
│  │  </button>                                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                         ↓                                   │
│  解析器 (Parser)                                            │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  解析 HTML、CSS、JavaScript                         │   │
│  │  生成 AST(抽象语法树)                             │   │
│  └─────────────────────────────────────────────────────┘   │
│                         ↓                                   │
│  编译器 (Compiler)                                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  分析响应式依赖                                     │   │
│  │  生成优化代码                                       │   │
│  │  作用域化 CSS                                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                         ↓                                   │
│  输出代码 (.js)                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  function create_fragment(ctx) {                    │   │
│  │    // 直接操作 DOM 的代码                           │   │
│  │  }                                                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、编译优化 #

2.1 无虚拟 DOM #

javascript
// React 方式(运行时)
function Component() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

// Svelte 编译后(简化)
function create_fragment(ctx) {
  let button;
  let t1;
  
  return {
    c() {
      button = element("button");
      t1 = text(ctx[0]);
    },
    m(target, anchor) {
      insert(target, button, anchor);
      append(button, t1);
      listen(button, "click", ctx[1]);
    },
    p(ctx, dirty) {
      if (dirty & 1) set_data(t1, ctx[0]);
    }
  };
}

2.2 静态提升 #

svelte
<script>
  let count = 0;
</script>

<div class="static-content">
  <p>Static text</p>
</div>

<button onclick={() => count++}>
  {count}
</button>

编译后静态内容只创建一次:

javascript
// 静态部分提升到模块作用域
const static_content = document.createElement("div");
static_content.className = "static-content";
// ...

function create_fragment(ctx) {
  // 只处理动态部分
  let button;
  let t1;
  // ...
}

2.3 事件委托 #

svelte
<script>
  let items = [1, 2, 3, 4, 5];
</script>

<ul>
  {#each items as item}
    <li onclick={() => console.log(item)}>{item}</li>
  {/each}
</ul>

编译器会自动优化事件处理,减少内存占用。

2.4 CSS 作用域 #

svelte
<style>
  .button {
    background: red;
  }
</style>

<button class="button">Click</button>

编译后:

css
.button.svelte-xyz123 {
  background: red;
}
html
<button class="button svelte-xyz123">Click</button>

三、响应式编译 #

3.1 依赖追踪 #

svelte
<script>
  let a = 1;
  let b = 2;
  
  $: sum = a + b;
</script>

<p>{sum}</p>

编译器分析依赖关系:

javascript
// 伪代码
function instance($$self, $$props, $$invalidate) {
  let a = 1;
  let b = 2;
  let sum;
  
  // 依赖追踪:sum 依赖 a 和 b
  $$self.$$.update = () => {
    if ($$.dirty & /* a, b */ 3) {
      $$invalidate(2, sum = a + b);
    }
  };
  
  return [a, b, sum];
}

3.2 精确更新 #

svelte
<script>
  let user = { name: 'Alice', age: 25 };
</script>

<p>{user.name}</p>
<p>{user.age}</p>

user.name 变化时,只更新第一个 <p>,不会重新渲染整个组件。

3.3 批量更新 #

svelte
<script>
  let a = 1;
  let b = 2;
  
  function update() {
    a = 3;
    b = 4;
  }
</script>

<p>{a} + {b} = {a + b}</p>

编译器会批量处理更新,只触发一次 DOM 更新。

四、编译选项 #

4.1 svelte.config.js #

javascript
import adapter from '@sveltejs/adapter-auto';

export default {
  compilerOptions: {
    // 生成开发模式代码
    dev: process.env.NODE_ENV === 'development',
    
    // 启用 CSS 作用域
    cssHash: ({ hash, css }) => `s-${hash(css)}`,
    
    // 自定义警告处理
    warningFilter: (warning) => {
      return !warning.code.includes('a11y');
    },
    
    // 启用 runes 模式(Svelte 5)
    runes: true
  },
  
  kit: {
    adapter: adapter()
  }
};

4.2 预处理器 #

javascript
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import adapter from '@sveltejs/adapter-auto';

export default {
  preprocess: vitePreprocess(),
  
  compilerOptions: {
    dev: true
  }
};

4.3 TypeScript 支持 #

javascript
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

export default {
  preprocess: vitePreprocess({
    script: {
      define: {
        'process.env.NODE_ENV': JSON.stringify('production')
      }
    }
  })
};

五、性能优化 #

5.1 减少响应式依赖 #

svelte
<script>
  let items = [];
  let filter = '';
  
  // 不推荐:每次都计算
  $: filtered = items.filter(i => i.includes(filter));
  
  // 推荐:使用函数
  function getFiltered() {
    return items.filter(i => i.includes(filter));
  }
</script>

{#each getFiltered() as item}
  {item}
{/each}

5.2 使用 key 优化列表 #

svelte
<script>
  let items = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }];
</script>

<!-- 推荐:使用唯一 key -->
{#each items as item (item.id)}
  <div>{item.name}</div>
{/each}

<!-- 不推荐:无 key -->
{#each items as item}
  <div>{item.name}</div>
{/each}

5.3 避免不必要的重新渲染 #

svelte
<script>
  let data = [];
  let selectedId = null;
  
  // 推荐:分离状态
  let selectedItem = $derived(data.find(i => i.id === selectedId));
</script>

{#each data as item (item.id)}
  <Item {item} selected={item.id === selectedId} />
{/each}

5.4 懒加载组件 #

svelte
<script>
  import { onMount } from 'svelte';
  
  let HeavyComponent;
  let showHeavy = false;
  
  onMount(async () => {
    if (showHeavy) {
      const module = await import('./HeavyComponent.svelte');
      HeavyComponent = module.default;
    }
  });
</script>

<button onclick={() => showHeavy = true}>Load Heavy Component</button>

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

六、调试技巧 #

6.1 编译输出查看 #

bash
# 查看编译后的代码
npx svelte compile src/App.svelte --output compiled.js

6.2 响应式调试 #

svelte
<script>
  let count = 0;
  
  $: {
    console.log('count changed:', count);
    console.trace('stack trace');
  }
</script>

<button onclick={() => count++}>
  {count}
</button>

6.3 开发工具 #

svelte
<svelte:options dev={true} />

<script>
  let count = 0;
</script>

<button onclick={() => count++}>{count}</button>

七、编译时 vs 运行时 #

7.1 对比 #

特性 Svelte(编译时) React(运行时)
包体积 ~2KB ~42KB
运行时开销 虚拟DOM Diff
首次渲染 中等
更新性能 直接DOM操作 Diff + Patch
开发体验 简洁 需要理解Hooks

7.2 编译时优势 #

text
✅ 优势
├── 极小的运行时代码
├── 无虚拟 DOM 开销
├── 编译时优化
├── 更好的性能
└── 简洁的代码

⚠️ 注意
├── 需要构建步骤
├── 调试时看到编译后代码
└── 某些动态特性受限

八、最佳实践 #

8.1 组件拆分 #

svelte
<!-- 推荐:小组件 -->
<script>
  let { title, content } = $props();
</script>

<article>
  <h2>{title}</h2>
  <p>{content}</p>
</article>

<!-- 不推荐:大组件 -->
<script>
  // 大量逻辑
</script>

<div>
  <!-- 大量模板 -->
</div>

8.2 响应式设计 #

svelte
<script>
  // 推荐:明确依赖
  let a = 0;
  let b = 0;
  let sum = $derived(a + b);
  
  // 不推荐:隐式依赖
  let c = 0;
  $: {
    // 复杂逻辑
  }
</script>

8.3 样式优化 #

svelte
<!-- 推荐:作用域样式 -->
<style>
  .button {
    background: red;
  }
</style>

<button class="button">Click</button>

<!-- 避免:全局样式污染 -->
<style>
  :global(.button) {
    background: red;
  }
</style>

九、总结 #

特性 说明
编译时优化 无运行时开销
静态提升 减少重复创建
精确更新 只更新变化部分
CSS 作用域 自动隔离样式
依赖追踪 自动分析响应式

编译时特性要点:

  • Svelte 在编译时完成大部分工作
  • 生成的代码直接操作 DOM
  • 静态内容被提升优化
  • 响应式依赖在编译时分析
  • 合理使用 key 优化列表渲染
  • 拆分组件提高编译效率
最后更新:2026-03-28