Skip to content

Commit 8f6e250

Browse files
chore: apply suggestions from code review
Co-authored-by: Ben McCann <[email protected]>
1 parent 2d0822b commit 8f6e250

File tree

1 file changed

+17
-17
lines changed

1 file changed

+17
-17
lines changed

DEVELOPER_GUIDE.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
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.
44

5-
In the most general sense this is how `svelte` works.
5+
In the most general sense, Svelte works as follows:
66

7-
- A component is parsed into an AST
8-
- The AST is analyzed, defining the scopes, finding stateful variables and whatnot
7+
- 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)
8+
- The AST is analyzed - defining the scopes, finding stateful variables, etc.
99
- 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
1010
- 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`
11-
- 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.
11+
- 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.
1212

1313
## Phase 1: Parsing
1414

15-
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.
15+
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.
1616

1717
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).
1818

@@ -40,13 +40,13 @@ if (parser.eat('!--')) {
4040

4141
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).
4242

43-
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).
43+
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).
4444

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

4747
## Phase 2: Analysis
4848

49-
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).
49+
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).
5050

5151
The very first thing to do is to create the scopes for every variable. What this operation does is to create a map from a node to a specific set of references, declarations and declarators. This is useful because if you have a situation like this
5252

@@ -70,16 +70,16 @@ The very first thing to do is to create the scopes for every variable. What this
7070
{count}
7171
```
7272

73-
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.
73+
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.
7474

7575
This is done by walking the AST and manually create a `new Scope` class every time we encounter a node that creates one.
7676

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

80-
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.
80+
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.
8181

82-
For example a `$state(1)` node will look like this (excluding positions information)
82+
For example, a `$state(1)` node will look like this (excluding position information):
8383

8484
```js
8585
{
@@ -96,7 +96,7 @@ This is done by walking the AST and manually create a `new Scope` class every ti
9696
}
9797
```
9898

99-
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.
99+
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.
100100

101101
</details>
102102

@@ -118,15 +118,15 @@ walk(ast, state, {
118118
});
119119
```
120120

121-
what this snippet of code is doing is
121+
What this snippet of code is doing is:
122122

123-
- Checking if the function declaration has an Identifier (basically if it's a named or anonymous function)
123+
- checking if the function declaration has an identifier (basically if it's a named or anonymous function)
124124
- if it has one it's declaring a new variable in the current scope
125125
- creating a new scope (since in Javascript when you create a function you are creating a new lexical scope) with the current scope as the parent
126126
- declare every argument of the function in the newly created scope
127127
- invoking the next method that will continue the AST traversal, with the brand new scope as the current scope
128128

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

131131
```ts
132132
walk(ast, state, {
@@ -152,7 +152,7 @@ walk(ast, state, {
152152
});
153153
```
154154

155-
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)
155+
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):
156156

157157
```ts
158158
const visitors = {
@@ -175,4 +175,4 @@ const visitors = {
175175
};
176176
```
177177

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

0 commit comments

Comments
 (0)