-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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
base: main
Are you sure you want to change the base?
docs: add developer guide #16517
Changes from 1 commit
2d0822b
8f6e250
ee30cc9
2523f73
a64ee32
425e68a
d6ea09d
3646c8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,178 @@ | ||||||
# Developer Guide | ||||||
|
||||||
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. | ||||||
|
||||||
- A component is parsed into an AST | ||||||
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
- The AST is analyzed, defining the scopes, finding stateful variables and whatnot | ||||||
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
- 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. | ||||||
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
||||||
## 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. | ||||||
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
||||||
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). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll take a look later but I think it's basically the same (but this one it's at home, with better audio)...anyway we can always update it 😄 |
||||||
|
||||||
You start from the first character of the string and try to match it with a known symbol in the language. Considering the shape of a svelte component, you either have an `element` (`<script>`, `<style>` or an HTML element in the template), a `tag` (`{#key}`, `{#if}`, an expression in the template etc) or raw `text`. Once you determine which of the three you are currently parsing, the parse is delegated to specialized functions that know how to handle each of those. | ||||||
|
||||||
You can `eat` a string to determine which "construct" you are in but don't need any information out of it. For example, if you just matched a `<` in the template you can `eat('!--')` to figure out if what you are dealing with is an HTML comment. The `eat` function will return `true` or `false`, and if it's true it will also advance the current index of the parser by `'!--'.length`. Now that you know that you are inside an HTML comment you can `read` the string until you find a `-->`. The difference between `read` and `eat` is that reading will return the value to you (in this case you need it because you need to store the information about the `data` of the comment in the AST node). Finally, you can eat that `-->` to advance the next three characters, passing the required parameters to throw an error if it's not there (if you open a comment and don't close it, you'll get a syntax error). | ||||||
|
||||||
All of the above more or less maps to this code: | ||||||
|
||||||
```js | ||||||
if (parser.eat('!--')) { | ||||||
const data = parser.read_until(regex_closing_comment); | ||||||
parser.eat('-->', true); | ||||||
|
||||||
parser.append({ | ||||||
type: 'Comment', | ||||||
start, | ||||||
end: parser.index, | ||||||
data | ||||||
}); | ||||||
|
||||||
return; | ||||||
} | ||||||
``` | ||||||
|
||||||
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). | ||||||
|
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). |
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
paoloricciuti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's unclear to me if new Scope
takes any parameters or what valid scopes can be or how they are represented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it needed in this context? It was more to illustrate how the scope is created (by walking the AST)...I think I go over what "the concept" of a scope is later (a collection of all the variable created and accessed)
Uh oh!
There was an error while loading. Please reload this page.