第六章 Vue框架的编译器

152 阅读2分钟

编译器的核心技术

模板编译器

  • 模板:特定结构的字符串、
  • 编译器:一段将源代码翻译成目标代码的程序
  • 完整的编译流程如下 编译流程.jpeg

Vue模板编译器

  • 源代码:VUe组件模板
  • 目标代码:js渲染函数
  • Vue作为DSL,其编译流程会有所简化,如下所示 Vue编译流程.jpeg

编译器的实现

  • 通过parser解析器将模板转为AST,
  • 通过transformer转换器将AST转换为JavaScript AST,
  • 通过generator生成器将JavaScript AST生成渲染函数

Parser解析器

  • 原理:通过有限状态自动机,按照一定的规则将字符串切割为一个个的token

  • 有限状态自动机:自定义有限个状态,通过程序控制不断改变状态

  • token:词法标记,用于标记识别到的不同元素

    • 模板字符串:“<p>Vue</p>”
    • 自定义状态:tagOpen,tagName,text,tagEnd,tagEndName
    • 自动改变状态:不断遍历模板字符串,若遇到'<'状态为tagOpen,遇到'p'状态为text等
    • 切割为token:每次改变状态前,都将这一状态伴随的所有字符按状态类型整理为一个token
    • tokens:[{type: 'tag', name: 'p'},{type: 'text', content: 'Vue'},{type: 'tagEnd', name: 'p'}]
  • AST:根据tokens构造AST

    • 编译器的AST构造使用递归下降算法
    • Vue的模板是用于描述HTML的,本身就互相嵌套,形成父子关系,天然的树形结构。AST正是抽象语法树,与其结构非常相似
    • 遍历tokens,维护一个父级元素栈,为tokens的每项形成父子关系,构建出一个AST对象
    • AST:
    {
          type: "root",
          children:[
              {
                  type: 'Element',
                  tag: "p",
                  children:[
                      {
                          type: "Text",
                          content: "Vue"
                      }
                  ]
              }
         ]
    }

Transformer转换器

  • 本质:将AST转换为JS AST,AST是对Vue模板的描述,JS AST是对javascript渲染函数的描述
  • 原理:为了描述渲染函数,我们深度遍历AST的每个节点,根据节点类型生成对应的h函数的描述
  • 分类:FunctionDecl,ReturnStatement,CallExpression,StringLiteral,ArrayExpression
  • 实现:根据AST的类型将其转换为以上分类对应类型,转换后的结果存储在AST节点的JSNode属性下
  • 理解:并不需要重新建立父子关系,只需要将每个节点转换为渲染的函数,并存储即可

Generator生成器

  • 原理:从AST获取JS AST,遍历每个JS AST节点,根据节点的类型生成对应的字符串,最后拼接起来。
  • 分类:genFunctionDecl,genReturnStatement,gencallExpression,genStringLiteral,genArrayExpression
  • 实现:如果是functionDecl,则拼接为 function(参数节点){} 此类形式即可
  • 最终得到如下字符串:'function render(){return h('div',[h('p','vue')])}'