vue源码(十二) compileToFunctions

开启compile

在分析完响应式原理后,让我们接着vue源码八()链接继续分析,上次说到,在$mount内部,在没有render函数的情况下,会将template进行一系列操作后,最后对这个template执行compileToFunctions操作,因此我们从compileToFunctions开始分析,

compileToFunctions的查找

这是来自src\platforms\web\entry-runtime-with-compiler.js Vue.prototype.$mount内部的

// 这里对拿到的template进行编译
if (template) {
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    mark('compile')
  }
  // 如果是模板字符串,需要编译器去编译  也就是进入compileToFunctions这个函数
  // 可以通过这个函数查看编译器的工作机制,也就是把template转换为render
  const { render, staticRenderFns } = compileToFunctions(template, {
    outputSourceRange: process.env.NODE_ENV !== 'production',
    shouldDecodeNewlines,
    shouldDecodeNewlinesForHref,
    delimiters: options.delimiters,
    comments: options.comments
  }, this)
  // 赋值给当前选项的render
  options.render = render
  options.staticRenderFns = staticRenderFns
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    mark('compile end')
    measure(`vue ${this._name} compile`, 'compile', 'compile end')
  }
}

可以看到这里执行了compileToFunctions,传入的参数为template和一个对象

createCompileToFunctionFn

因此来分析compileToFunctions,经过一系列文件跳转查找(这里就是看引入和ctrl+左键),来到了src\compiler\to-function.js

export function createCompileToFunctionFn (compile: Function): Function {
  // 创建一个空对象
  const cache = Object.create(null)
  
  // compileToFunctions中传入的options:
  // template,  
  //  {
  //   outputSourceRange: process.env.NODE_ENV !== 'production',
  //   shouldDecodeNewlines,
  //   shouldDecodeNewlinesForHref,
  //   delimiters: options.delimiters,
  //   comments: options.comments
  //  }, 
  // this
  return function compileToFunctions (
    template: string, // 字符串模板 template 也就是经过那些操作获取之后的template
    options?: CompilerOptions, // 参数
    vm?: Component // 虚拟dom
  ): CompiledFunctionResult {
    // 把options和空对象混合,也就是获取options,相当于浅拷贝一份options
    options = extend({}, options)
    // 获取警告
    const warn = options.warn || baseWarn
    // 删除options.warn属性
    delete options.warn

    /* istanbul ignore if */
    // 忽略
    if (process.env.NODE_ENV !== 'production') {
      // detect possible CSP restriction
      try {
        new Function('return 1')
      } catch (e) {
        if (e.toString().match(/unsafe-eval|CSP/)) {
          warn(
            'It seems you are using the standalone build of Vue.js in an ' +
            'environment with Content Security Policy that prohibits unsafe-eval. ' +
            'The template compiler cannot work in this environment. Consider ' +
            'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
            'templates into render functions.'
          )
        }
      }
    }

    // check cache

    // options中是否有delimiters 一般的delimiters都是delimiters: ['${', '}']这种
    const key = options.delimiters
      // 如果有delimiters  String(['${', '}'])返回 '${,}' + template
      ? String(options.delimiters) + template
      // 如果没有delimiters
      : template
    // 如果cache对象中有此key属性,直接返回
    if (cache[key]) {
      return cache[key]
    }

    // compile  路径:src\compiler\create-compiler.js
    // 执行compiled  传入template和options参数
    const compiled = compile(template, options)

    // 忽略 
  }
}

options和extend

将options与空对象混合,形成新的options

options = extend({}, options)

此时的options是$mount中传入的一个对象

{
    outputSourceRange: process.env.NODE_ENV !== 'production',
    shouldDecodeNewlines,
    shouldDecodeNewlinesForHref,
    delimiters: options.delimiters,
    comments: options.comments
}

其中涉及到extend 路径:src\shared\util.js

/**
 * Mix properties into target object.
 * 将属性混合到目标对象中。
 */
export function extend (to: Object, _from: ?Object): Object {
  // 把from中的所有枚举属性添加到to对象中,混合
  for (const key in _from) {
    to[key] = _from[key]
  }
  return to
}

获取warn并删除options.warn属性

// 获取警告
const warn = options.warn || baseWarn
// 删除options.warn属性
delete options.warn

检测options中是否有delimeters

// options中是否有delimiters 一般的delimiters都是delimiters: ['${', '}']这种
const key = options.delimiters
  // 如果有delimiters  String(['${', '}'])返回 '${,}' + template
  ? String(options.delimiters) + template
  // 如果没有delimiters
  : template
// 如果cache对象中有此key属性,直接返回
if (cache[key]) {
  return cache[key]
}

这是随着vm.options.delimeters传过来的,也就是vue中的options:delimeters,其功能是:改变纯文本插入分隔符。

示例:

new Vue({
  delimiters: ['${', '}']
})

因此这一步就是对delimiter进行判断,是否传入了delimeters。传入了就执行String()这个操作,String([’ , ] ) {', '}'])返回 ' {,}’ + template,否则就返回原始的template

执行compile

此时执行compile,compile是一个函数参数,来自src\compiler\create-compiler.js

// compile  路径:src\compiler\create-compiler.js
// 执行compiled  传入template和options参数
const compiled = compile(template, options)

总结

下一期分析compile

猜你喜欢

转载自blog.csdn.net/qq_46299172/article/details/108073333