Skip to content

docs: add developer guide #16517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

docs: add developer guide #16517

wants to merge 1 commit into from

Conversation

paoloricciuti
Copy link
Member

@paoloricciuti paoloricciuti commented Jul 28, 2025

This adds a developer guide document, a in depth guite to the svelte internals that should help people interested to contributing to better understand where to start.

Still a big draft but publishing it to get feedback.

Rendered version

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

Copy link

changeset-bot bot commented Jul 28, 2025

⚠️ No Changeset found

Latest commit: 2d0822b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

Playground

pnpm add https://pkg.pr.new/svelte@16517

@svelte-docs-bot
Copy link


The aim of this document is to give a general description of the codebase to those who would like to contribute. It will use technical language and will go deep into the various parts of the codebase.

In the most general sense this is how `svelte` works.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In the most general sense this is how `svelte` works.
In the most general sense, Svelte works as follows:


In the most general sense this is how `svelte` works.

- A component is parsed into an AST
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beginners might not know what an AST is, so defining the abbreviation and providing a reference could help. Also probably helpful to specify which AST. Is there a certain Typescript AST that we follow?

Suggested change
- A component is parsed into an AST
- A component is parsed into an [abstract syntax tree (AST)](https://en.m.wikipedia.org/wiki/Abstract_syntax_tree) compatible with the [ESTree spec](https://github.com/estree/estree)

In the most general sense this is how `svelte` works.

- A component is parsed into an AST
- The AST is analyzed, defining the scopes, finding stateful variables and whatnot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The AST is analyzed, defining the scopes, finding stateful variables and whatnot
- The AST is analyzed - defining the scopes, finding stateful variables, etc.

- The AST is analyzed, defining the scopes, finding stateful variables and whatnot
- The AST is transformed, either into a server component or a client component based on the `generate` option. The transformation produces a JS module and some CSS if there's any
- A server component imports the server runtime from `svelte/internal/server` and when executed with `render` produces a string of the `body` and a string of the `head`
- A client component imports the client runtime from `svelte/internal/client` and when executed either with `mount` or `hydrate` creates the elements (or retrieves them from the pre-existing DOM in case of hydration), attaches listeners and creates state and effects that are needed to keep the DOM in sync with the state.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A client component imports the client runtime from `svelte/internal/client` and when executed either with `mount` or `hydrate` creates the elements (or retrieves them from the pre-existing DOM in case of hydration), attaches listeners and creates state and effects that are needed to keep the DOM in sync with the state.
- A client component imports the client runtime from `svelte/internal/client` and when executed - either with `mount` or `hydrate` - creates the DOM elements (or retrieves them from the pre-existing DOM in case of hydration), attaches listeners, and creates state and effects that are needed to keep the DOM in sync with the state.


## Phase 1: Parsing

Parsing is the first step to convert the component into a runnable JS file. Your `svelte` component is effectively a string and while we could try to do something with regexes and replacements the standard way to do manipulation is to first build an Abstract Syntax Tree and then manipulate that. An Abstract Syntax Tree (AST from now on) is a structured representation of code. Each language has its own syntax and relative AST (based on the parser used). Every JavaScript part of a `svelte` component, be it the script tag or an expression tag in your template, is parsed with `acorn` (`acorn-typescript` in case you use `lang="ts"`) to produce an ESTree compatible tree.
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should define AST the first time it's used above and so don't need to do it here. Would be helpful to include what Typescript AST spec is used here

Suggested change
Parsing is the first step to convert the component into a runnable JS file. Your `svelte` component is effectively a string and while we could try to do something with regexes and replacements the standard way to do manipulation is to first build an Abstract Syntax Tree and then manipulate that. An Abstract Syntax Tree (AST from now on) is a structured representation of code. Each language has its own syntax and relative AST (based on the parser used). Every JavaScript part of a `svelte` component, be it the script tag or an expression tag in your template, is parsed with `acorn` (`acorn-typescript` in case you use `lang="ts"`) to produce an ESTree compatible tree.
Parsing is the first step to convert the component into a runnable JS file. Your Svelte component is effectively a string and while we could try to do something with regexes and replacements the standard way to do manipulation is to first build an AST and then manipulate that. An AST is a structured representation of code. Each language has its own syntax and relative AST (based on the parser used). Every JavaScript part of a Svelte component, be it the script tag or an expression tag in your template, is parsed with `acorn` (`acorn-typescript` in case you use `lang="ts"`) to produce an ESTree compatible tree.


Parsing is the first step to convert the component into a runnable JS file. Your `svelte` component is effectively a string and while we could try to do something with regexes and replacements the standard way to do manipulation is to first build an Abstract Syntax Tree and then manipulate that. An Abstract Syntax Tree (AST from now on) is a structured representation of code. Each language has its own syntax and relative AST (based on the parser used). Every JavaScript part of a `svelte` component, be it the script tag or an expression tag in your template, is parsed with `acorn` (`acorn-typescript` in case you use `lang="ts"`) to produce an ESTree compatible tree.

If you want a more in-depth explanation of how a Parser works, you can refer to [this video](https://www.youtube.com/watch?v=mwvyKGw2CzU) by @tanhauhau where he builds a mini svelte 4 from scratch, but the gist of it is that you can basically have three main operations during the parsing phase: `eat`, `read` and `match` (with some variations).
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you want a more in-depth explanation of how a Parser works, you can refer to [this video](https://www.youtube.com/watch?v=mwvyKGw2CzU) by @tanhauhau where he builds a mini svelte 4 from scratch, but the gist of it is that you can basically have three main operations during the parsing phase: `eat`, `read` and `match` (with some variations).
If you want a more in-depth explanation of how a parser works, you can refer to [this video](https://www.youtube.com/watch?v=mwvyKGw2CzU) by @tanhauhau where he builds a mini Svelte 4 from scratch, but the gist of it is that you can basically have three main operations during the parsing phase: `eat`, `read` and `match` (with some variations).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't watch it as I'm currently on an airplane, but he's got one for Svelte 5 and I wonder if it covers the same stuff and would be better to refer to here: https://youtu.be/4uV27-OMJR8


If the parser doesn't enter this `if`, it will check for all the other language constructs using different strategies to read the information that is needed in the AST (an HTML element for example will need the name, the list of arguments, the fragment etc).

If you want to familiarize yourself with the `svelte` AST, you can go [to the playground](https://svelte.dev/playground), write your `svelte` component and open the `AST Output` tab. This will not only show you the AST of the component but also provide you with hover functionality that will highlight each section of the component when you hover over a section of the AST (and vice versa).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Svelte AST instead of svelte AST


## Phase 2: Analysis

Once we have a AST we need to perform analysis on it...during this phase we will collect information about which variables are used, where are they used, if they are stores etc etc. This information will be later used during the third phase to properly transform and optimizing your component (for example if you declare a stateful variable but never reassign to it or never use it in a reactive context we will not bother with creating a stateful variable at all).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Once we have a AST we need to perform analysis on it...during this phase we will collect information about which variables are used, where are they used, if they are stores etc etc. This information will be later used during the third phase to properly transform and optimizing your component (for example if you declare a stateful variable but never reassign to it or never use it in a reactive context we will not bother with creating a stateful variable at all).
Once we have a AST we need to perform analysis on it. During this phase we will collect information about which variables are used, where are they used, if they are stores etc etc. This information will be later used during the third phase to properly transform and optimizing your component (for example if you declare a stateful variable but never reassign to it or never use it in a reactive context we will not bother with creating a stateful variable at all).


If the parser doesn't enter this `if`, it will check for all the other language constructs using different strategies to read the information that is needed in the AST (an HTML element for example will need the name, the list of arguments, the fragment etc).

If you want to familiarize yourself with the `svelte` AST, you can go [to the playground](https://svelte.dev/playground), write your `svelte` component and open the `AST Output` tab. This will not only show you the AST of the component but also provide you with hover functionality that will highlight each section of the component when you hover over a section of the AST (and vice versa).
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you want to familiarize yourself with the `svelte` AST, you can go [to the playground](https://svelte.dev/playground), write your `svelte` component and open the `AST Output` tab. This will not only show you the AST of the component but also provide you with hover functionality that will highlight each section of the component when you hover over a section of the AST (and vice versa).
If you want to familiarize yourself with the Svelte AST, you can go [to the playground](https://svelte.dev/playground), write your Svelte component and open the `AST Output` tab. This will not only show you the AST of the component but also provide you with hover functionality that will highlight each section of the component when you hover over a section of the AST (and vice versa).


If you want to familiarize yourself with the `svelte` AST, you can go [to the playground](https://svelte.dev/playground), write your `svelte` component and open the `AST Output` tab. This will not only show you the AST of the component but also provide you with hover functionality that will highlight each section of the component when you hover over a section of the AST (and vice versa).

![svelte playground showing the AST tab and the hover functionality](assets/developer-guide/ast.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
![svelte playground showing the AST tab and the hover functionality](assets/developer-guide/ast.png)
![Svelte playground showing the AST tab and the hover functionality](assets/developer-guide/ast.png)

{count}
```

depending on where you read `count` it will refer to a different variable that has been shadowed. The `count` in the template and in `increase` refers to the `count` declared in instance script, while the one in the `log` function will refer to it's argument.
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
depending on where you read `count` it will refer to a different variable that has been shadowed. The `count` in the template and in `increase` refers to the `count` declared in instance script, while the one in the `log` function will refer to it's argument.
Depending on where you read `count` it will refer to a different variable that has been shadowed. The `count` in the template and in `increase` refers to the `count` declared in instance script, while the one in the `log` function will refer to its argument.

<details>
<summary>What does walking the AST means?</summary>

As we've seen the AST is basically a giant Javascript object with a `type` property to indicate the node type and a series of extra properties.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
As we've seen the AST is basically a giant Javascript object with a `type` property to indicate the node type and a series of extra properties.
As we've seen, the AST is basically a giant Javascript object with a `type` property to indicate the node type and a series of extra properties.


As we've seen the AST is basically a giant Javascript object with a `type` property to indicate the node type and a series of extra properties.

For example a `$state(1)` node will look like this (excluding positions information)
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For example a `$state(1)` node will look like this (excluding positions information)
For example, a `$state(1)` node will look like this (excluding position information):

}
```

walking allows you to invoke a function (that's called a visitor) for each of the nodes in the AST, receiving the node itself as an argument.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
walking allows you to invoke a function (that's called a visitor) for each of the nodes in the AST, receiving the node itself as an argument.
Walking allows you to invoke a function (that's called a visitor) for each of the nodes in the AST, receiving the node itself as an argument.

});
```

what this snippet of code is doing is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
what this snippet of code is doing is
What this snippet of code is doing is:


what this snippet of code is doing is

- Checking if the function declaration has an Identifier (basically if it's a named or anonymous function)
Copy link
Member

@benmccann benmccann Aug 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's referring to the specific code it should be uppercase and in backticks or if it's generally using the term it should be lowercase

Suggested change
- Checking if the function declaration has an Identifier (basically if it's a named or anonymous function)
- checking if the function declaration has an identifier (basically if it's a named or anonymous function)

- declare every argument of the function in the newly created scope
- invoking the next method that will continue the AST traversal, with the brand new scope as the current scope

The same is obviously true for svelte specific nodes too: the `SnippetBlock` visitor looks basically identical to the `FunctionDeclaration` one:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The same is obviously true for svelte specific nodes too: the `SnippetBlock` visitor looks basically identical to the `FunctionDeclaration` one:
The same is obviously true for Svelte-specific nodes too: the `SnippetBlock` visitor looks basically identical to the `FunctionDeclaration` one:

});
```

After the initial walk to figure out the right scopes we can now walk once again, we use a generic visitor (that runs before any visit to a node) to pass down the appropriate scope to the node (and collect information about the `// svelte-ignore` comments)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
After the initial walk to figure out the right scopes we can now walk once again, we use a generic visitor (that runs before any visit to a node) to pass down the appropriate scope to the node (and collect information about the `// svelte-ignore` comments)
After the initial walk to figure out the right scopes we can now walk once again, we use a generic visitor (that runs before any visit to a node) to pass down the appropriate scope to the node (and collect information about the `// svelte-ignore` comments):

};
```

this means that in every visitor we can access the `scope` property and ask information about every variable by name.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this means that in every visitor we can access the `scope` property and ask information about every variable by name.
This means that in every visitor we can access the `scope` property and ask information about every variable by name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants