# Generate

  • Vue的编译器将组件的<template>的html解析成 AST 对象
  • AST 生成运行渲染函数,即 render() ,包括 staticRenderFns 数组, 里面存放了所有静态节点的渲染函数

# createCompilerCreator

  • 就是处理为使用render(h) {}属性写出的Vnode
export function createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: ComplierOptions
): CompiledResult {
  // 将模板解析为 AST, 每个
  const ast = parse(template.trim(), options)
  // 优化,遍历AST,为每个节点做静态标记
  // 标记每个节点是否为静态节点,然后进一步标记处静态根节点 在后续更新中可以跳过静态节点
  
  if (options.optimize !== false) {
    optimize(ast, options)
  }
  // 代码生成, 将 ast 转换成可执行的 render 函数的字符串形式
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})

# generate

export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
): CodegenResult {
  // 实例化 CodegenState 对象
  const state = new CodegenState(options)
  // 生成字符串格式的代码,比如 _c(tag, data, children, normalizationType)
  // 类似 render 的 h(tag, data, children, ...)
  // 不只是_c 如果是函数式组价 结果为_m(0)
  const code = ast ? genElement(ast, state) : '_c("div")'
  return {
    render: `with(this){return ${code}}`,
    staticRenderFns: state.staticRenderFns
  }
}

# genElemenet

  • 处理元素上的各种 v-ifv-for...
export function genElement (el: ASTElement, state: CodegenState): string {
  // 处理 v-pre, v-pre 指令会跳过当前元素的处理
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }
  if (el.staticRoot && !el.staticProcessed) {
    /**
     * 当前节点为静态根节点且未被 genStatic 处理过
     * 1. 将当前静态节点的渲染函数放到 staticRenderFns 数组中
     * 2. 返回一个可执行函数 _m(idx, true or '')
    */
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    /**
     * 当前节点带有 v-once 指令的节点
     * 1. 当前节点存在 v-if 指令,得到一个三元表达式, condition ? render1 : render2
     * 2. 当前节点是一个包含在 v-for 指令内部的静态节点,得到`_o(_c(tag, data, children), number, key)`
     * 3. 单纯的一个 v-once 节点。 得到`_m(idsx true or '')`
    */
    return genOnce(el, state)
  } else if (el.if && !el.ifProcessed) {
    // 处理带有 v-if 的节点
    return genIf(el, state)
  } else if (el.for && el.forProcessed) {
    // 返回 `_l(exp, funciton(alias, iterator1, iterator2){return _c(tag,data,children)})`
    return genFor(el, state)
  } else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
    // 当前节点是 template 但却不是插槽的 使用 template 做 v-if 或者 v-for的
    return genChildren(el, state) || 'void 0'
  } else if (el.tag === 'slot') {
    // 插槽 `_t(slotName, children, attrs, bind)`
    return genSlot(el, state) // 6. 插槽里
  } else {
    // 处理动态组件和普通元素
    let code
    if (el.component) {
      // 处理动态组件,得到`_c(compName, data, children)`
      code = genComponent(el.component, el, state)
    } else {
      // 自定义组件和原生标签
      let data
      if (!el.plain || (el.pre && state.maybeComponent(el))) {
        // 返回 JSON 类型的 data: { key: a, ref: b, props: c, ... }
        data = genData(el, state)
      }
      
      // 处理子节点,得到多有子节点字符串格式的代码组成的数组
      // [_c(tag, data, children), ...]
      const children = el.inlineTemplate ? null : genChildren(el, state, true)
      code = `_c('${el.tag}'${data ? `,${data}` : ''}
      ${children ? `,${children}` : ''})`
    }
    // 如果提供了 transformCode 方法
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }
    return code
  }
}

# genChildren

export function genChildren (
  el: ASTElement,
  state: CodegenState,
  checkSkip?: boolean,
  altGenElement?: Function,
  altGenNode?: Function
): string | void {
  const children = el.children
  if (children.length) {
    const el = children[0]
    // 省略代码 优化
    const normalizationType = checkSkip
      ? getNormalizationType(children, state.maybeComponent)
      : 0
    const gen = altGenNode || genNode
    // 返回 children 数组 
    // `[_c(tag, data, children, normalizationType), ....]`
    // 递归 通过 genElement 处理 children
    return `[${children.map(c => gen(c, state)).join(',')}]${normalizationType ? `,${normalizationType}` : ''}`
  }
}

# genNode

function genNode(node: ASTNode, state: CodegenState): string {
  // 递归 genElement 
  if (node.type === 1) {
    return genElement(node, state)
  } else if (node.type === 3 && node.isComment) {
    // `_e(${JSON.string(comment.text)})`
    return genComment(node)
  } else {
    // `_v(${text.type === 2 ? text.expression : transformSpecialNewlines(JSON.stringify(text.text))})`
    return genText(node)
  }
}

# genData

  • 处理自定义组件,常态标签上的属性 组成 JSON。 类似 { key: a, ref: b, attrs: {}, ... }
export function genData(el: ASTElement, state: CodegenState): string {
  let data = '{'
  // 首先处理指令, 因为指令可能在生成其他属性之前改变这些属性
  // 返回 directives: [{ name, rawname, value, arg, modifiers }, ...]
  const dirs = genDirectives(el, state)
  if (dirs) data += dirs + ','
  if (el.key) data += `key:${el.key},`
  if (el.ref) data += `ref:${el.ref},`
  if (el.refInFor) data += `refInFor: true,`
  if (el.pre) data += `pre: true,`
  // 动态组件
  if (el.component) data += `tag: "${el.tag}",`
  // 获得节点的 staiticClass、class、staticStyle、style
  for (let i = 0; i < state.dataGenFns.length; i++) {
    data += state.dataGenFns[i](el)
  }
  
  // 其他属性
  if (el.attrs) data += `attrs:${genProps(el.attrs)},`
  // domProps
  if (el.props) data += `domProps: ${genProps(el.props)},`
  // 自定义事件
  if (el.events) data += `${genHandlers(el.events, false)},`
  
  // 处理 .native 修饰符事件
  if (el.nativeEvents) data += `${genHandlers(el.nativeEvents, true)},`
  // 非作用域插槽
  if (el.slotTarget && !el.slotScope) data += `slot:${el.slotTarget},`
  // 作用域插槽 在6 插槽里 生成 _u() 函数
  if (el.scopedSlots) data += `${genScopedSlots(el, el.scopedSlots, state)},`
  if (el.model) data += `model:{value:${el.model.value},callback:${el.model.callback},expression:${el.model.expression}},`
  if (el.inlineTemplate) {
    const inlineTemplate = genInlineTemplate(el, state)
    if (inlineTemplate) data += `${inlineTemplate},`
  }
  data = data.replace(/,$/, '') + '}'
  if (el.dynamicAttrs) {
    // 存在动态属性
    data = `_b(${data}),"${el.tag}",${genProps(el.dynamicAttrs)}`
  }
  if (el.wrapData) {
    data = el.wrapData(data)
  }
  if (el.wrapListeners) {
    data = el.wrapListenters(data)
  }
  return data
}

# genDirectives

  • 处理 指令: directives:[{ name: '', value: '', ... }]
function genDirectives(el: ASTElement, state: CodegenState): string | void {
    // 获取指令数组
  const dirs = el.directives
  if (!dirs) return
  let res = 'directives:['
  // 标记,用于标记指令是否需要在运行时完成的任务, 比如 v-model 的 input 事件
  let hasRuntime = false
  let i, l, dir, needRuntime
  for (i = 0, l = dirs.length; i < l; i++) {
    dir = dirs[i]
    needRuntime = true
    // 获取当前指令的处理方法 v-html...
    const gen: DirectiveFunction = state.directives[dir.name]
    if (gen) {
      // 指令编译方法, 如果需要运行时完成一部分任务 则返回 true
      needRuntime == !!gen(el, dir, state.warn)
    }
    if (needRuntime) {
      hasRuntime = true
      res += `{name:"${dir.name}",rawName:"${dir.rawName}"
      ${dir.value ?`,value:(${dir.value}),expression:${JSON.stringify(dir.value)}` : ''}
      ${dir.arg ? `,arg:${dir.isDynamicArg ? dir.arg : `"${dir.arg}"`}` : ''}
      ${dir.modifiers ? `${,modifiers:${JSON.sttingify(dir.modifiers)}}` : ''}
      },`
    }
  }
  if (hasRuntime) {
    // 只有存在运行时任务 才会返回 res
    return res.sloce(0, -1) + ']'
  }
}

# genProps

function genProps(props: Array<ASTAttr>): string {
  // 静态属性
  let staticProps = ``
  // 动态属性
  let dynamicProps = ``
  // 遍历属性数组
  for (let i = 0; i< props.length; i++) {
    const porp = props[i]
    const value = __WEEX__ 
      ? generateValue(prop.value)
      : transformSpeciaNewlines(prop.value)
    if (prop.dynamic) {
      dynamicProps += `${prop.name},${value},`
    } else {
      staticProps += `"${prop.name}":${value}`
    }
    // 去掉静态属性最后的逗号
    staticProps = `{${staticProps.slice(0, -1)}}`
    if (dynamicProps) {
      // 如果存在动态属性 则返回 _d(静态属性字符串,动态属性字符串)
      return `_d(${staticProps},[${dynamicProps.slice(0, -1)}])`
    } else {
      // JSON 格式的对象
      return staticProps
    }
  }
}

# genHandlers

  • 处理方法的 { on: { ... }, nativeOn: { ... } }
export function genHandlers (
    events: ASTElementHandlers,
    isNative: boolean
): string {
    const prefix = isNative ? 'nativeOn' : 'on:'
    let staticHandlers = ``
    let dynamicHandlers = ``
    for (const name in events) {
      // 获取回调函数的函数名, 即 this.methodName 或者 [this.methodName1, ...]
      const handlerCode = genHandler(events[name])
      if (events[name] && events[name].dynamic) {
        dynamicHandlers += `${name},${handlerCode}`
      } else {
          // 静态
        staticHandlers += `"${name}":${handlerCode},`
      }
    }
    staticHandlers = `{staticHanlders.slice(0, -1)}`
    if (dynamicHandlers) {
        return prefix + `_d(${staticHandlers},[${dynamicHandlers.slice(0, -1)}])`
    } else {
        return prefix + staticHandlers
    }
}

# genStatic

  • 使用<template>标签生成的会做的优化,如果是自己写的render(h) {}是没有这种优化的
  • renderStatic
// 生成静态节点的渲染函数,将当前静态节点的渲染函数放到 staticRenderFns 数组中
function genStatic(el: ASTElement, state: CodegenState): string {
  // 标记当前静态节点已经被处理过了
  el.staticProcessed = true
  const originalPreState = state.pre
  if (el.pre) {
    state.pre = el.pre
  }
  // 将静态根节点的渲染函数 push 到 staticRenderFns 数组中
  state.staticRenderFns.push(`with(this){return ${genElement(el, state)}}`)
  state.pre = originalPreState
  // 返回一个可执行函数:_m(idx, true or '')
  // idx = 当前静态节点的渲染函数在 staticRenderFns 数组中的下标
  return `_m(${state.staticRenderFns.length - 1}${el.staticInFor} ? ',true' : '')`
}

# genOnce

function genOnce(el, state) {
  // 标记当前节点已经被处理过
  el.onceProcessed = true
  if (el.if && !el.ifProcessed) {
    // 带有 v-if 指令但是没有被 genIf 处理过
    return genIf(el, state)
  } else if (el.staticInFor) {
    let key = ''
    let parent = el.parent
    while (parent) {
      if (parent.for) {
        key = parent.key
        break
      }
      parent = parent.parent
    }
    // key 不存在则给出提示, v-once 只能用于带有 key 的 v-for 节点内部
    if (!key) {
      warn()
      return genElement(el, state)
    }
    // 生成 `_o(_c(tag, data, children), number, key)`
    return `_o(${genElement(el, state)},${state.onceId++},${key})`
  } else {
    return genStatic(el, state)
  }
}

# genFor


















 





export function genFor(
  el: any,
  state:CodegenState,
  altGen?: Function
  altHelper?: string
): string {
  // v-for="(item, i) in arr"
  // { for: arr, alias: item, iterator1: i, iterator2: '' }
  // el.for 可以理解为 "item in arr" 这个字符串
  const exp = el.for
  const alias = el.alias
  const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
  
  // 表示已经被 genFor 处理过
  el.forProcessed = true
  // 得到`_l(exp, (alias, iterator1, iterator2) { return _c(tag, data, children) })`
  return `${altHelper || '_l'}((${exp})),` + 
  `function(${alias}${iteratior1}${iterator2}){` +
  `return ${(altGen || genElement)}(el, state)}` +
  '})'
}

# genIf

  • 生成三元表达式
export function genIf(
  el: any,
  state: CodegenState,
  altGen?: Function
  altEmpty?: string
): string {
  el.ifProcessed = true
  return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)
}

function genIfConditions(
  conditions,
  state,
  altGen,
  altEmpty
) {
  if (!conditions.length) {
    return altEmpty || '_e()'
  }
  const condition = conditions.shift()
  if (condition.exp) {
    // 如果 condition.exp 条件成立, 则得到一个三元表达式
    // 如果条件不成立 则递归的方式一直将单元写到条件成立的位置
    return `(${condition.exp})?${genTernaryExp(condition.block)
    }:${genIfConditions(conditions, state, altGen, altEmpty)}`
  } else {
    return `${genTernaryExp(condition.block)}`
  }
}

function genTernaryExp(el) {
  return el.once ? genOnce(el.state) : genElement(el, state)
}

# genComponent






 



function genComponent(
  componentName,
  el,
  state
) {
  const children = el.inlineTemplate ? null : genChildren(el, state, true)
  return `_c(${componentName},${genData(el, state)},${children ? `,${children}` : ''})`
}