compiler-overview
Last updated
Last updated
svelte小记
解析:
解析源码成为抽象语法树(AST)
跟踪引用和依赖项
创建代码块和fragments
生成代码
大致可以用下图来解释:
如果用一段伪代码来实现,就是:
Svelte是HTML的超级。Svelte实现了自己的解析器用于Svelte语法,处理和。
怎么处理的呢?当这个解析器碰到标签的时候,使用acorn去解析标签内的内容。当解析器碰到标签时,使用css-tree去解析CSS内容。
并且,Svelte解析器区别对待了script的实例,和module script,。
Svelte的AST就像下面这样:
可以在ASTExplorer试试Svelte的解析器。可以在HTML > Svelte下找到。
解析从这里开始。解析器在src/compiler/parse/index.ts实现。
“JSON Parser with JavaScript”这个文章里有介绍,并指导一步步的写了一个JSON解析器。
如果第一次看解析器,还是狠推荐去学习一下上文。
在这一步,Svelte会traverse这个AST去跟踪所有声明和引用的变量及依赖项。
Component
这个类,存储Svelte组件的信息,包含信息如下:
HTML片段,fragment
实例的脚本和模块脚本的AST及其词法作用域,instance_scope
和module_scope
实例的变量,vars
reactive的变量,reactive_declarations
使用的变量名用以防止当创建临时变量时命名冲突。
Component
会遍历(traverse)AST的实例脚本和模块脚本去 找出所有的声明,引用和更新的变量 。
Svelte会在遍历模版之前标识出所有可用的变量。当在遍历模版的过程中遇到变量时,Svelte会标记这个变量被模板引用了(referenced
)。
Svelte会遍历模板的AST,并且会从这个模板AST创建一个Fragment树。
每个fragment节点会包含一些信息:
- expression and dependencies(表达式和依赖关系)
逻辑块({#if}
),mustache标签({ data }
),包含表达式和表达式的依赖项。
- scope
{#each}
和{#await}
逻辑块及let:
绑定,为子模板创建了新的变量。
Svelte为AST中的每种类型的节点创建不同的片段节点,因为不同类型的片段节点处理事情的方式不同
Slot node注册了一个slot名称到Component
EachBlock node创建了一个新的作用域和跟踪迭代列表里的key
,index
和名称,
还有其他的一些
遍历模板后,Svelte就知道组件中是否更新或引用了某个变量。
有了这些信息,Svelte尝试为优化输出做一些准备,譬如:
确定哪些变量或函数可以安全的从instance
函数提升。
确定反应性的声明不需要反应。
Svelte更新CSS选择器,在必要时向选择器添加.Svelte -xxx
class。
在这一步的最后,Svelte有足够的信息来生成编译后的代码,下一个步骤再看。
可以从这里开始拜读。其中Component
实现在src/compiler/compile/Component.ts。
“Manipulating AST with JavaScript”这个文章里有相关的知识点。
在这一步,Svelte创建了一个Renderer
实例,该实例跟踪生成编译输出所需的必要信息。取决于输出DOM还是SSR代码(参见编译选项中的generate), Svelte分别实例化不同的Renderer
。
一个Block包含代码片段去生成create_fragment
函数。
上下文跟踪一个实例变量列表,并呈现在编译输出的$$.ctx
中。
在renderer中,Svelte从片段树创建了一个渲染树。
渲染树中的每个节点都实现了render函数,该函数生成用于创建和更新该节点的DOM的代码。
SSR渲染器提供了一些帮助来在编译后的输出中生成模板文本,比如add_string(str)
和add_expression(node)
。
Renderer
在源码的哪里可以找到DOM Renderer实现在src/compiler/compile/render_dom/Renderer.ts,SSR Renderer实现在src/compiler/compile/render_ssr/Renderer.ts。
不同的渲染器以不同的方式渲染。
DOM Renderer 遍历渲染树并在此过程中调用每个节点的render
函数。Block
实例被传递到render
函数中,因此每个节点都将代码插入到适当的create_fragment
函数中。
另一方面,SSR Renderer 依赖于不同的节点处理程序将字符串或表达式插入最终模板文字中。
render函数返回js
和css
,分别通过rollup的rollup-plugin-svelte和webpack的svelte-loader用于bundler使用。
为了在编译输出中删除重复的代码,Svelte提供了util函数,可以在src/runtime/internal中找到它,例如:
dom相关的, append
, insert
, detach
调度相关的, schedule_update
, flush
声明周期相关,onMount,
beforeUpdate
动画相关的,create_animation