编译

const { render, staticRenderFns } =  compileToFunctions(template, {
    shouldDecodeNewlines,
    shouldDecodeNewlinesForHref,
    delimiters: options.delimiters,
    comments: options.comments
  }, this)
options.render = render
options.staticRenderFns = staticRenderFns
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
): CompiledResult {
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    optimize(ast, options)
  }
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})

此编译过程中的依赖的配置 baseOptions 会有所不同。而编译过程会多次执行,但这同一个平台下每一次的编译过程配置又是相同的,为了不让这些配置在每次编译过程都通过参数传入,Vue.js 利用了函数柯里化的技巧很好的实现了 baseOptions 的参数保留。同样,Vue.js 也是利用函数柯里化技巧把基础的编译过程函数抽出来,通过 createCompilerCreator(baseCompile) 的方式把真正编译的过程和其它逻辑如对编译配置处理、缓存处理等剥离开,这样的设计还是非常巧妙的。

同一个组件,多个地方用,就会多次编译啊,不过会缓存结果,直接从缓存里拿即可

浏览器处理p标签之内的div 是直接提取出来, vue 跟他保持一致

parse

编译过程首先就是对模板做解析,生成 AST,它是一种抽象语法树,是对源代码的抽象语法结构的树状表现形式。

AST 元素节点总共有 3 种类型,type 为 1 表示是普通元素,为 2 表示是表达式,为 3 表示是纯文本。其实这里我觉得源码写的不够友好,这种是典型的魔术数字,如果转换成用常量表达会更利于源码阅读。

总结: parse 的目标是把 template 模板解析 ast 树,

整个parse 过程就是利用正则表达式顺序解析模板, 对不同的标签和节点有不同的处理过程,直到模板解析完毕。

optimize

markStatic(root) 标记静态节点 ,markStaticRoots(root, false) 标记静态根。

解析子节点是不是static 只要有一个不是的话就跳出

这个是对 if else 做个判断

总结:

  • optimize 的目标是通过标记静态根的方式, 优化重新渲染过程中对静态节点的处理逻辑

  • optimize的过程就是深度遍历这个ast 树, 先标记静态节点, 在标记静态根。

make static 就是为了后续 make static root make static root 会在渲染过程中生成一个静态子 tree,也就是给 vnode 标记 isStatic,这样在 patchVnode 过程中就可以判断并跳过子树的对比。

codegen

会进行三种情况的判断

实际上就是把 render 代码串通过 new Function 的方式转换成可执行的函数,赋值给 vm.options.render,这样当组件通过 vm._render 的时候,就会执行这个 render 函数。那么接下来我们就重点关注一下这个 render 代码串的生成过程。

总结: codegen 的目标是把 ast 树转换成代码字符串,就是render 函数代码。然后再通过 new Function 转换成 render 函数,render 函数会返回一个 VNode 树,然后再 patch 过程中生成 DOM 树渲染到页面

整个 codegen 过程就是深度遍历 ast 树根据不同条件生成不同代码的过程。

我们平时写的 .vue 文件的时候写是template, 这个编译是发生在webpack 编译阶段, vue-loader 负责编译的。

最后更新于

这有帮助吗?