xinglie / xinglie.github.io

blog
https://xinglie.github.io
153 stars 22 forks source link

magix-composer模板编译阶段分析 #76

Open xinglie opened 3 years ago

xinglie commented 3 years ago

编译转换是一个大工程,把夹杂着逻辑控制语法的html片断翻译成需要的虚拟dom,不但要识别出模板中使用了哪些根变量(用于数据生成),还要识别哪些html片断可共用同一个虚拟dom对象,以及绑定事件优化,html静态、动态节点优化等一系列的问题。一个人做这些事件需要拆分、归类,然后逐一去解决,这样才能把整个的工作心智压力降低。

html转换成最终使用的js对象,经历了以下阶段。

文件识别

  1. 识别出是单文件(.mx)还是普通的文件(.html)
  2. 不同的文件采用不同的方式读取到具体的文件内容

内容检查

为了确保生成的代码无问题,会对html内容片断做一次字符检查,确保不包含某些特殊字符,通常html内容片断也不应包含一些不可见的特殊字符,此举是为了防止万一出现好排查问题

通知编译开始

为了方便后期处理一些特殊的情况,在开始编译html内容片断前会调用一次compileTmplStart钩子函数,让外部有机会在编译前处理一次html内容片断

命令语法检查

该过程会检查用户书写的如{{if {{each等是否正确嵌套、闭合,因为不正确的嵌套和闭合是无法生成正确的js代码的,因此该过程必不可少。在检查的过程中,当不合法时,会提示在哪个文件,哪一行的哪一条语句有什么样的问题。

命令预处理

考虑这样的代码片断

<div>
    {{if expr}}
        <span></span>
    {{/if}}
</div>

对于html来讲{{if expr}}就是普通的文本节点,如果我们最终生成虚拟dom时,{{if expr}}其实是一个语句块,我们需要对这样的命令做处理,把文本变成节点,这样在虚拟dom结构生成时会方便些。

转换后伪代码

<div>
    <qk:cmd qk:expr="expr">
        <span></span>
    </qk:cmd>
</div>

该过程还会处理其它一些后续需要的信息,比如某些命令的参数,在源文件哪一行等。

翻译命令

该阶段会对剩余的{{if expr}}翻译成<% if(expr){ %> (这里有一个历史原因:早期使用<% %>格式的模板,所以为了尽可能的复用之前的代码,会翻译成早期的格式)

这时会对{{each list as item}}这种补齐开发者省略的参数。

html检查

经以上处理后,html内容片断需要翻译的命令语句块等都变成了合法的html标签。在html检查这个过程中,会对html的标签嵌套结构做检查,避免错误闭合等问题。

该过程同样是确保前面的{{if expr}}翻译成的占位节点结构是正确的,如果某些情况翻译错误,可以在该过程中被检查出来。该过程仅在开发阶段存在。

处理自定义标签

该过程会处理<mx-frame *params=""><mx-gallery>中定义的组件,翻译成相应的如<div mx-view="path/to/view" *params="">这样的节点。

此举是方便开发者使用更语义化的标签来进行结构组织,背后由该阶段进行翻译成统一格式的节点

该过程需要对接外挂的组件体系,需要考虑的情形非常多,技术难度不高,但费心力。

命令预处理

前一个阶段处理自定义标签有可能再次引入{{if这样的命令语句,需要再处理一次

翻译命令

同样,也需要再翻译一次,不过这2次的处理会检查内容是否变化,只有变化后才进入

html检查

在处理自定义标签时,会引入新的html片断和翻译后的新标签,这里会再检查一次,确保整个过程无任何问题

命令编译

该阶段会对事件中的内容做处理,以及移除一些空命令,减少后续的分析工作量

变量处理

该阶段是重中之重 之前曾写过一个详细的过程:https://github.com/thx/magix-combine/issues/18

该阶段会识别出模板中使用了哪些变量,局部变量如何与全局变量对应。会识别出view刷新需要哪些数据,双向绑定如何追踪到根变量等一系列问题,从2015年至今一直在努力该阶段。

通知编译结束

通过钩子函数compileTmplEnd通知外部编译结束,此时外部可进行简易加工,不能再进行复杂的结构变动。

属性处理

该过程会对参数属性、事件属性做处理,参数合并到相应的属性里,事件属性会添加相应的前缀等一系列最后运行时需要的信息

静态化识别

该过程会对模板中哪些节点是静态的,哪些是局部静态,哪些可以与其它共享同一个虚拟dom对象等节点,并添加上相应的信息,以供下一步的识别处理

生成虚拟dom

开发中非常耗时的地方

该过程会对前面处理后的html片段进行转换成相应的虚拟dom,详情可参考: https://github.com/xinglie/xinglie.github.io/issues/54

该过程技术难度高,同时我的目标是生成手工级别优化的代码,大到dom节点,小到一个for循环的变量生成,都需要长时间持续的投入。

经过以上这些阶段,才完成了模板翻译,也正是拆分成各个阶段,才能静下心来逐个击破,来完成更复杂的magix-composer