Open-Source Wikis

/

Svelte

/

Packages

/

Compiler

sveltejs/svelte

Compiler

Active contributors: Rich Harris, Simon H, Dominic Gannaway, Paolo Ricciuti

Purpose

The compiler turns a .svelte source file into a JavaScript module that imports a small set of runtime primitives. It also runs a separate path for .svelte.js / .svelte.ts modules that contain runes outside a component (compileModule). Both share the same parser and analyzer; they diverge in the transform phase.

The public entry is packages/svelte/src/compiler/index.js, exporting compile, compileModule, parse, parseCss, preprocess, print, migrate, and VERSION. These are re-exported as the svelte/compiler subpath in packages/svelte/package.json.

Pipeline at a glance

graph TD
    SRC[".svelte source"] --> RBOM["remove_bom()"]
    RBOM --> P["_parse()<br/><code>phases/1-parse/index.js</code>"]
    P --> PARSED["AST.Root<br/>{fragment, instance, module, options, css}"]
    PARSED --> RTS{"parsed.metadata.ts?"}
    RTS -->|yes| RTNS["remove_typescript_nodes()"]
    RTS -->|no| MERGE
    RTNS --> MERGE["combine validate_component_options + parsed.options"]
    MERGE --> AC["analyze_component()<br/><code>phases/2-analyze/index.js</code>"]
    AC --> ANALYSIS["ComponentAnalysis"]
    ANALYSIS --> TC["transform_component()<br/><code>phases/3-transform/index.js</code>"]
    TC --> RESULT["{js, css, ast, warnings, ...}"]

Phases

1 — parse

packages/svelte/src/compiler/phases/1-parse/

  • index.js exposes a Parser class and a parse helper. The state machine is split into state/fragment.js, state/element.js (~26 KB, the largest single state file), state/tag.js, and state/text.js.
  • read/options.js parses <svelte:options>.
  • read/script.js and read/style.js extract <script> and <style> blocks; the latter is reused by parseCss (packages/svelte/src/compiler/index.js).
  • read/expression.js and read/context.js defer to a forked acorn (@sveltejs/acorn-typescript) for JS/TS parsing.
  • remove_typescript_nodes.js strips as, type annotations, etc. once we know it's TS.
  • utils/entities.js is a 2.2k-line generated table of HTML entity decodings — the largest single source file in the compiler.

The output is the Svelte AST (AST.Root) plus an options object derived from <svelte:options> and from per-attribute parsing.

2 — analyze

packages/svelte/src/compiler/phases/2-analyze/

  • index.js (~1.3k lines) is the orchestrator. It builds the ComponentAnalysis shape: a graph of scopes, declared variables, $state/$derived/$effect references, slot usage, dynamic CSS bindings, etc.
  • visitors/ contains a per-AST-node visitor (~70 files). Each visitor decorates the AST with metadata or pushes warnings/errors.
  • css/ runs CSS-specific passes:
    • css-prune.js removes unused selectors based on the markup.
    • css-analyze.js (alongside css-prune.js) discovers what selectors actually match.
    • keyframes.js, css-warnings.js, etc.
  • utils/ and types.d.ts define the analysis model.

The component scope graph is built by packages/svelte/src/compiler/phases/scope.js (~1.5k lines) — the second-largest single file in the compiler, after the entities table. It tracks bindings, references, mutation kinds ('state', 'derived', 'prop', 'normal', ...), and is queried throughout phase 3.

3 — transform

packages/svelte/src/compiler/phases/3-transform/

The transform splits into three sub-targets:

Sub-target File / dir Purpose
Client packages/svelte/src/compiler/phases/3-transform/client/transform-client.js (~720 LOC) + visitors/ Generates DOM-targeting JS that imports svelte/internal/client.
Server packages/svelte/src/compiler/phases/3-transform/server/transform-server.js (~430 LOC) + visitors/ Generates HTML-emitting JS that imports svelte/internal/server.
CSS packages/svelte/src/compiler/phases/3-transform/css/ Emits scoped/encapsulated CSS using hashes from analysis.

A shared phases/3-transform/index.js dispatches to the right target based on compile_options.generate ('client' or 'server'), and a shared/ folder under each target holds helpers used by multiple visitors.

The visitors are per AST node type: EachBlock.js, IfBlock.js, BindDirective.js, SvelteElement.js, etc. There are over 70 client-side visitors and a similar number of server visitors. They use the b (statement) and x (expression) builders from packages/svelte/src/compiler/utils/builders.js to produce estree nodes, which esrap then prints to source.

Errors and warnings

packages/svelte/src/compiler/errors.js (1.7k lines, generated) and warnings.js (840 lines) are produced by packages/svelte/scripts/process-messages from the markdown sources under packages/svelte/messages/compile-errors/ and messages/compile-warnings/. To add a new compile error, see Patterns and conventions.

state.js (packages/svelte/src/compiler/state.js) is a tiny module-level state holder used to carry the current source, filename, and warning filter through the pipeline without threading them through every function.

Validation of options

validate-options.js (packages/svelte/src/compiler/validate-options.js, ~10 KB) defines schemas for CompileOptions and ModuleCompileOptions, including default values and friendly errors. validate_component_options is called at the top of compile().

Migrate codemod

packages/svelte/src/compiler/migrate/index.js (~2k lines) implements the Svelte 4 → 5 migration. It reuses the parser and analyzer to build a ComponentAnalysis, then rewrites the source with magic-string. Exposed as svelte/compiler#migrate.

packages/svelte/src/compiler/print/ re-emits a Svelte AST to source, used by tests under tests/print/ and by the migration tool when only specific nodes need to be re-emitted.

Preprocess

packages/svelte/src/compiler/preprocess/index.js exposes preprocess(source, transformers, options), which runs user-supplied script/style/markup transforms before the file reaches compile. Source-map handling lives in decode_sourcemap.js and replace_in_code.js. Public types are in preprocess/public.d.ts.

Key source files

File Purpose
packages/svelte/src/compiler/index.js Public compile, compileModule, parse, etc.
packages/svelte/src/compiler/phases/1-parse/index.js Parser entry + Parser class.
packages/svelte/src/compiler/phases/1-parse/state/element.js Tag and attribute parser state machine (~26 KB).
packages/svelte/src/compiler/phases/2-analyze/index.js Component/module analyzer.
packages/svelte/src/compiler/phases/scope.js Scope graph.
packages/svelte/src/compiler/phases/3-transform/client/transform-client.js Client-target transformer.
packages/svelte/src/compiler/phases/3-transform/server/transform-server.js Server-target transformer.
packages/svelte/src/compiler/utils/builders.js b.statement(...) / x.expression(...) builders.
packages/svelte/src/compiler/migrate/index.js Svelte 4 → 5 codemod.
packages/svelte/src/compiler/preprocess/index.js Pluggable preprocessor.

Entry points for modification

If you need to change parsing of a new syntax, start in phases/1-parse/state/element.js or state/tag.js and add an AST node type to phases/1-parse/types.d.ts. For semantic checks, add or extend a visitor under phases/2-analyze/visitors/. For code generation, add the corresponding visitor under phases/3-transform/client/visitors/ and phases/3-transform/server/visitors/. Almost all changes touch all three phases.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Compiler – Svelte wiki | Factory