# 编译器

# complieToFunctions

  • 执行编译函数,得到编译结果
  • 将编译界定符得到的字符串代码通过 new Function(codeStr) 转换成可执行的函数
  • 缓存编译结果
export function compileToFunctions(
  template: string,
  options?: CompilerOptions,
  vm?: Component
): CompiledFunctionResult {
  options = extend({}, options)
  // 日志
  const warn = options.warn || baseWarn
  delete options.warn
  
  if (process.env.NODE_ENV== 'production') {
    // 监测CSP限制
    try {
      new Function('return 1')
    } catch (e) {
      if (e.toString().match(/unsafe-eval|CSP/)) {
        // 模板编译器不能工作在CSP不安全的环境
      }
    }
  }
  
  // 如果有缓存,则跳过编译,直接从缓存中获取上次编译的结果
  const key = options.delimiters
    ? String(options.delimiters) + template
    : template
  if (cache[key]) {
    return cache[key]
  }
  
  // 执行编译函数,得到编译结果
  const compiled = compile(template, options)
  
  // 编译期间产生的error和tip,分别输出到控制台
  if (process.env.NODE_ENV== 'production') {
    if (compiled.errors && compiled.errors.length) {
      if (options.outputSourceRange) {
        compiled.errors.forEach(e => {
          warn(e)
        })
      }
    } else {
      warn()
    }
    if (compiled.tips && compiled.tips.length) {
      if (options.outputSourceRange) {
        compiled.tips.forEach(e => tip(e.msg, vm))
      } else {
        compiled.tips.forEach(msg => tip(msg, vm))
      }
    }
  }
  
  // 转换编译得到的字符串代码为幻术
  const res = {}
  const fnGenErrors = []
  res.render = createFunction(compiled.render, fnGenErrors)
  res.staticRenderFns = compiled.staticRenderFns.map(code => {
    return createFunction(code, fnGenErrors)
  })
  
  return (cache[key] = res)
}

processElement

  • 处理元素节点的key、ref、插槽、自闭和的 slot 标签、 动态组件...
  • 然后再 el 对象上添加如下属性 el.key, el.ref,...
export function processElement(
  element: ASTElement,
  options: ComplierOptions
) {
  // el.key = val
  processKey(element)
  
  // 确定 element 是否需要进行 genData 处理。 > 4.1 生成渲染函数
  element.plain = (
    !element.key &&
    !element.scopedSlots &&
    !element.attrsList.length
  )
  
  // el.ref = val, el.refInFor = boolean
  processRef(element)
  // 处理作为插槽传递给组件的内容,得到 插槽名称、是否为动态插槽、作用域插槽,以及插槽中的所有子元素
  processSlotContent(element)
  // 处理自闭合的 slot 标签,得到插槽名称 el.slotName = xx
  processSlotOutlet(element)
  // 处理动态组件 得到 el.component = compName
  processComponent(element)
  // 省略代码 处理各个平台的 tranformNode 方法
  
  // 处理元素上的所有属性
  // v-bin指令变为 el.attrs 或者 el.dynamicAttrs = [{ name, value, start, end, dynamic }, ...]
  // v-on变为 el.events或者el.nativeEvents = { name: [{ value, start, end, modifiers,... }] }
  // 其他指令: el.directives = [{name, rawName, ....}]
  // 原生属性 el.attrs = [{ name, value }] 或者使用的 props el.props = [[ name, value }]
  processAttrs(element)
  return element
}