Open xinglie opened 3 years ago
编译转换是一个大工程,把夹杂着逻辑控制语法的html片断翻译成需要的虚拟dom,不但要识别出模板中使用了哪些根变量(用于数据生成),还要识别哪些html片断可共用同一个虚拟dom对象,以及绑定事件优化,html静态、动态节点优化等一系列的问题。一个人做这些事件需要拆分、归类,然后逐一去解决,这样才能把整个的工作心智压力降低。
逻辑控制
html
dom
根变量
html转换成最终使用的js对象,经历了以下阶段。
为了确保生成的代码无问题,会对html内容片断做一次字符检查,确保不包含某些特殊字符,通常html内容片断也不应包含一些不可见的特殊字符,此举是为了防止万一出现好排查问题
为了方便后期处理一些特殊的情况,在开始编译html内容片断前会调用一次compileTmplStart钩子函数,让外部有机会在编译前处理一次html内容片断
compileTmplStart
该过程会检查用户书写的如{{if {{each等是否正确嵌套、闭合,因为不正确的嵌套和闭合是无法生成正确的js代码的,因此该过程必不可少。在检查的过程中,当不合法时,会提示在哪个文件,哪一行的哪一条语句有什么样的问题。
{{if
{{each
js
考虑这样的代码片断
<div> {{if expr}} <span></span> {{/if}} </div>
对于html来讲{{if expr}}就是普通的文本节点,如果我们最终生成虚拟dom时,{{if expr}}其实是一个语句块,我们需要对这样的命令做处理,把文本变成节点,这样在虚拟dom结构生成时会方便些。
{{if expr}}
转换后伪代码
<div> <qk:cmd qk:expr="expr"> <span></span> </qk:cmd> </div>
该过程还会处理其它一些后续需要的信息,比如某些命令的参数,在源文件哪一行等。
该阶段会对剩余的{{if expr}}翻译成<% if(expr){ %> (这里有一个历史原因:早期使用<% %>格式的模板,所以为了尽可能的复用之前的代码,会翻译成早期的格式)
<% if(expr){ %>
<% %>
这时会对{{each list as item}}这种补齐开发者省略的参数。
{{each list as item}}
经以上处理后,html内容片断需要翻译的命令语句块等都变成了合法的html标签。在html检查这个过程中,会对html的标签嵌套结构做检查,避免错误闭合等问题。
html检查
该过程同样是确保前面的{{if expr}}翻译成的占位节点结构是正确的,如果某些情况翻译错误,可以在该过程中被检查出来。该过程仅在开发阶段存在。
该过程会处理<mx-frame *params="">及<mx-gallery>中定义的组件,翻译成相应的如<div mx-view="path/to/view" *params="">这样的节点。
<mx-frame *params="">
<mx-gallery>
<div mx-view="path/to/view" *params="">
此举是方便开发者使用更语义化的标签来进行结构组织,背后由该阶段进行翻译成统一格式的节点
该过程需要对接外挂的组件体系,需要考虑的情形非常多,技术难度不高,但费心力。
前一个阶段处理自定义标签有可能再次引入{{if这样的命令语句,需要再处理一次
处理自定义标签
同样,也需要再翻译一次,不过这2次的处理会检查内容是否变化,只有变化后才进入
在处理自定义标签时,会引入新的html片断和翻译后的新标签,这里会再检查一次,确保整个过程无任何问题
该阶段会对事件中的内容做处理,以及移除一些空命令,减少后续的分析工作量
该阶段是重中之重 之前曾写过一个详细的过程:https://github.com/thx/magix-combine/issues/18
该阶段会识别出模板中使用了哪些变量,局部变量如何与全局变量对应。会识别出view刷新需要哪些数据,双向绑定如何追踪到根变量等一系列问题,从2015年至今一直在努力该阶段。
通过钩子函数compileTmplEnd通知外部编译结束,此时外部可进行简易加工,不能再进行复杂的结构变动。
compileTmplEnd
该过程会对参数属性、事件属性做处理,参数合并到相应的属性里,事件属性会添加相应的前缀等一系列最后运行时需要的信息
该过程会对模板中哪些节点是静态的,哪些是局部静态,哪些可以与其它共享同一个虚拟dom对象等节点,并添加上相应的信息,以供下一步的识别处理
开发中非常耗时的地方
该过程会对前面处理后的html片段进行转换成相应的虚拟dom,详情可参考: https://github.com/xinglie/xinglie.github.io/issues/54
该过程技术难度高,同时我的目标是生成手工级别优化的代码,大到dom节点,小到一个for循环的变量生成,都需要长时间持续的投入。
for
经过以上这些阶段,才完成了模板翻译,也正是拆分成各个阶段,才能静下心来逐个击破,来完成更复杂的magix-composer
html转换成最终使用的js对象,经历了以下阶段。
文件识别
内容检查
为了确保生成的代码无问题,会对
html
内容片断做一次字符检查,确保不包含某些特殊字符,通常html
内容片断也不应包含一些不可见的特殊字符,此举是为了防止万一出现好排查问题通知编译开始
为了方便后期处理一些特殊的情况,在开始编译
html
内容片断前会调用一次compileTmplStart
钩子函数,让外部有机会在编译前处理一次html
内容片断命令语法检查
该过程会检查用户书写的如
{{if
{{each
等是否正确嵌套、闭合,因为不正确的嵌套和闭合是无法生成正确的js
代码的,因此该过程必不可少。在检查的过程中,当不合法时,会提示在哪个文件,哪一行的哪一条语句有什么样的问题。命令预处理
考虑这样的代码片断
对于
html
来讲{{if expr}}
就是普通的文本节点,如果我们最终生成虚拟dom时,{{if expr}}
其实是一个语句块,我们需要对这样的命令做处理,把文本变成节点,这样在虚拟dom结构生成时会方便些。转换后伪代码
翻译命令
该阶段会对剩余的
{{if expr}}
翻译成<% if(expr){ %>
(这里有一个历史原因:早期使用<% %>
格式的模板,所以为了尽可能的复用之前的代码,会翻译成早期的格式)这时会对
{{each list as item}}
这种补齐开发者省略的参数。html检查
经以上处理后,
html
内容片断需要翻译的命令语句块等都变成了合法的html
标签。在html检查
这个过程中,会对html
的标签嵌套结构做检查,避免错误闭合等问题。处理自定义标签
该过程会处理
<mx-frame *params="">
及<mx-gallery>
中定义的组件,翻译成相应的如<div mx-view="path/to/view" *params="">
这样的节点。此举是方便开发者使用更语义化的标签来进行结构组织,背后由该阶段进行翻译成统一格式的节点
命令预处理
前一个阶段
处理自定义标签
有可能再次引入{{if
这样的命令语句,需要再处理一次翻译命令
同样,也需要再翻译一次,不过这2次的处理会检查内容是否变化,只有变化后才进入
html检查
在处理自定义标签时,会引入新的
html
片断和翻译后的新标签,这里会再检查一次,确保整个过程无任何问题命令编译
该阶段会对事件中的内容做处理,以及移除一些空命令,减少后续的分析工作量
变量处理
该阶段会识别出模板中使用了哪些变量,局部变量如何与全局变量对应。会识别出view刷新需要哪些数据,双向绑定如何追踪到根变量等一系列问题,从2015年至今一直在努力该阶段。
通知编译结束
通过钩子函数
compileTmplEnd
通知外部编译结束,此时外部可进行简易加工,不能再进行复杂的结构变动。属性处理
该过程会对参数属性、事件属性做处理,参数合并到相应的属性里,事件属性会添加相应的前缀等一系列最后运行时需要的信息
静态化识别
该过程会对模板中哪些节点是静态的,哪些是局部静态,哪些可以与其它共享同一个虚拟dom对象等节点,并添加上相应的信息,以供下一步的识别处理
生成虚拟dom
该过程会对前面处理后的
html
片段进行转换成相应的虚拟dom,详情可参考: https://github.com/xinglie/xinglie.github.io/issues/54该过程技术难度高,同时我的目标是生成手工级别优化的代码,大到dom节点,小到一个
for
循环的变量生成,都需要长时间持续的投入。经过以上这些阶段,才完成了模板翻译,也正是拆分成各个阶段,才能静下心来逐个击破,来完成更复杂的magix-composer