Skip to content

Vue源码解析(二)compileToFunctions、createCompiler、createCompilerCreator #14

@jmx164491960

Description

@jmx164491960

前言

在学习Vue源码的时候,经常会被compileToFunctions、createCompiler、createCompilerCreator几个方法给弄晕。今天一文来彻底把这几个关系搞清楚。
下面源码将会用vue 2.5.17讲解

渲染的入口

src\platforms\web\entry-runtime-with-compiler.js里,Vue的mount方法在此定义。

代码第65行:

    const { render, staticRenderFns } = compileToFunctions(template, {
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      options.render = render
      options.staticRenderFns = staticRenderFns

这里作用是把我们写的template转换成render函数。假如我们没有用template,则不会执行这个。

compileToFunctions的定义

路径:src\platforms\web\compiler\index.js,由createCompiler生成,根据控制baseOptions去定义不同环境(浏览器、服务器)下的compileToFunctions。

const { compile, compileToFunctions } = createCompiler(baseOptions)

export { compile, compileToFunctions }

createCompiler的定义

路径:src\compiler\index.js

import { createCompilerCreator } from './create-compiler'

// `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
  }
})

执行了createCompilerCreator方法,传参方法baseCompile。这么做的目的是为了重复不同compiler的公共部分。baseComile在具体使用场景定义。
这里baseCompile主要做的是根据template生成ast,ast是Vue模板渲染很重要的部门,下一篇是独立讲解。我们来看createCompilerCreator的定义:

**createCompilerCreator **

路径:src\compiler\create-compiler.js

export function createCompilerCreator (baseCompile: Function): Function {
  return function createCompiler (baseOptions: CompilerOptions) {
    function compile (
      template: string,
      options?: CompilerOptions
    ): CompiledResult {
      const finalOptions = Object.create(baseOptions)
      const errors = []
      const tips = []
      finalOptions.warn = (msg, tip) => {
        (tip ? tips : errors).push(msg)
      }

      if (options) {
        // merge custom modules
        if (options.modules) {
          finalOptions.modules =
            (baseOptions.modules || []).concat(options.modules)
        }
        // merge custom directives
        if (options.directives) {
          finalOptions.directives = extend(
            Object.create(baseOptions.directives || null),
            options.directives
          )
        }
        // copy other options
        for (const key in options) {
          if (key !== 'modules' && key !== 'directives') {
            finalOptions[key] = options[key]
          }
        }
      }

      const compiled = baseCompile(template, finalOptions)
      if (process.env.NODE_ENV !== 'production') {
        errors.push.apply(errors, detectErrors(compiled.ast))
      }
      compiled.errors = errors
      compiled.tips = tips
      return compiled
    }

    return {
      compile,
      compileToFunctions: createCompileToFunctionFn(compile)
    }
  }
}

先对传入的options和默认的配置做一下合并。
然后调用传入的baseComplie方法生成compileToFunctions。

表面上比较绕,但其实这么做的目的就是把baseCompile解耦,Vue希望通过传入不同的baseCompile来适配不同平台

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions