Svelte

JavaScript

compiler

Who is this for? Anyone who is interested in the Svelte compilation process

wants to get started in reading Svelte source code

Overview The Svelte compilation process can be broken down into 4-steps Parsing source code into Abstract Syntax Tree (AST)

Tracking references and dependencies

Creating code blocks and fragments

Generate code Which sums out by the following pseudocode: const source = fs . readFileSync ( 'App.svelte' ) ; const ast = parse ( source ) ; const component = new Component ( ast ) ; const renderer = options . generate === 'ssr' ? SSRRenderer ( component ) : DomRenderer ( component ) ; const { js , css } = renderer . render ( ) ; fs . writeFileSync ( 'App.js' , js ) ; fs . writeFileSync ( 'App.css' , css ) ;

1. Parsing source code into AST const ast = parse ( source ) ; The Svelte syntax is a superset of HTML. Svelte implements its own parser for the Svelte syntax, which handles: HTML syntax <div>

Curly brackets { data }

Logic blocks {#each list as item} The Svelte parser handles specially for <script> and <style> tags. When the parser encounters a <script> tag, it uses acorn to parse the content within the tag. When the parser sees a <style> tag, it uses css-tree to parse the CSS content. Besides, the Svelte parser differentiates instance script, <script> , and module script, <script context="module"> . The Svelte AST look like: { html : { type : 'Fragment' , children : [ ... ] } , css : { ... } , instance : { context : 'default' , content : { ... } } , module : { context : 'context' , content : { ... } } , } You can try out the Svelte parser in ASTExplorer. You can find the Svelte parser under HTML > Svelte.

Where can I learn about parsing in JavaScript? My previous article, "JSON Parser with JavaScript" introduces the terminology and guides you step-by-step on writing a parser for JSON in JavaScript. If this is the your first time learning about parser, I highly recommend you to read that.

2. Tracking references and dependencies const component = new Component ( ast ) ; In this step, Svelte traverses through the AST to track all the variable declared and referenced and their depedencies.

b. Traverse the instance script and module script AST Component traverses the instance script and module script AST to find out all the variables declared, referenced, and updated within the instance script and module script. Svelte identifies all the variables available before traversing the template. When encountering the variable during template traversal, Svelte will mark the variable as referenced from template.

c. Traverse the template Svelte traverses through the template AST and creates a Fragment tree out of the template AST. Each fragment node contains information such as: - expression and dependencies Logic blocks, {#if} , and mustache tags, { data } , contain expression and the dependencies of the expression. - scope {#each} and {#await} logic block and let: binding create new variables for the children template. Svelte creates a different Fragment node for each type of node in the AST, as different kind of Fragment node handles things differently: Element node validates the attribute, bindings, content and event handlers.

Slot node registers the slot name to the Component .

. EachBlock node creates a new scope and tracks the key , index and the name of the list to be iterated.

, and the name of the list to be iterated. ...

d. Traverse the instance script AST After traversing through the template, Svelte now knows whether a variable is ever being updated or referenced in the component. With this information, Svelte tries make preparations for optimising the output, for example: determine which variables or functions can be safely hoisted out of the instance function.

function. determine reactive declarations that does not need to be reactive

Svelte updates the CSS selectors, by adding .svelte-xxx class to the selectors when necessary. At the end of this step, Svelte has enough information to generate the compiled code, which brings us to the next step.

Where can I learn about traversing in JavaScript? Bear with my shameless plug, my previous article, "Manipulating AST with JavaScript" covers relevant knowledge you need to know about traversing AST in JavaScript.

3. Creating code blocks and fragments const renderer = options . generate === 'ssr' ? SSRRenderer ( component ) : DomRenderer ( component ) ; In this step, Svelte creates a Renderer instance which keeps track necessary information required to generate the compiled output. Depending on the whether to output DOM or SSR code (see generate in compile options), Svelte instantiates different Renderer respectively.

DOM Renderer DOM Renderer keeps track of a list of blocks and context. A Block contains code fragments for generate the create_fragment function. Context tracks a list of instance variables which will be presented in the $$.ctx in the compiled output. In the renderer, Svelte creates a render tree out of the Fragment tree. Each node in the render tree implements the render function which generate codes that create and update the DOM for the node.

SSR Renderer SSR Renderer provide helpers to generate template literals in the compiled output, such as add_string(str) and add_expression(node) .

4. Generate code const { js , css } = renderer . render ( ) ; Different renderer renders differently. The DOM Renderer traverses through the render tree and calls the render function of each node along the way. The Block instance is passed into the render function, so that each node inserts the code into the appropriate create_fragment function. The SSR Renderer, on the other hand, relies on different node handlers to insert strings or expressions into the final template literal. The render function returns js and css which will be consumed by the bundler, via rollup-plugin-svelte for rollup and svelte-loader for webpack respectively.