vue2 源码解析-双向数据绑定原理

vue源码解析


为减少文章篇幅,代码只保留主要方法,需要更详细的代码文档(已注明代码解释)可使用git拉取:
https://gitcode.com/weixin_44862629/vue-source-code/overview


一、总结

1、vue 2 是通过Object.defineProperty()对组件内的data数据进行递归绑定getter和setter,同时通过Dep进行依赖收集管理
2、vue2 是(通过Object.defineProperty递归遍历)劫持的属性
3、vue3 是(通过proxy代理)劫持的整个data对象

二、vue2双向数据绑定(源码)

在这里插入图片描述

1.1 关键实现方法及步骤

数据劫持:通过Object.defineProperty()拦截对象属性的访问和修改,将属性转化为响应式属性。

observe 、defineReactive(Object.defineProperty、getter、setter)

依赖收集:初始化组件时,Vue解析模板并为每个依赖于响应式属性的地方创建一个Watcher。这些Watcher会被添加到相应属性的Dep中。

Watcher、Dep(addSub、notify、)

视图更新:当数据属性发生变化时,对应的Dep会通知所有相关的Watcher,进而触发视图更新。

Compiler ()

在这里插入图片描述

1.2 vue源码 - Observe

  • observe、defineReactive,观察并创建响应式数据
  • set和del函数,用于在响应式对象上添加或删除属性,实现数据的“响应式”更新。
  • 定义响应式属性和依赖收集(Dep),并在数据变化时自动更新依赖于这些数据的视图。
// 省略依赖引入...
const arrayKeys = Object.getOwnPropertyNames(arrayMethods) // 获取重写后的数组方法名
const NO_INITIAL_VALUE = {} // 用于标记初始值未定义
export let shouldObserve: boolean = true // 全局变量,控制是否应该观察数据
export function toggleObserving(value: boolean) {
  shouldObserve = value  // 切换观察状态
}
// mockDep对象,用于非生产环境或SSR(服务器端渲染)时的依赖管理
const mockDep = {...} as Dep
export class Observer { // Observer类,用于观察数据对象或数组
  dep: Dep
  vmCount: number 
  constructor(public value: any, public shallow = false, public mock = false) {
    this.dep = mock ? mockDep : new Dep() // 初始化依赖管理器
    this.vmCount = 0
    // 在被观察对象上标记Observer实例
    def(value, '__ob__', this)
    if (isArray(value)) {// 根据数据类型进行不同的处理
      if (!mock) { // 对数组进行特殊处理,重写其原型方法或直接在数组上定义新方法
        if (hasProto) {
        ......
        }}
      if (!shallow) {this.observeArray(value)}// 递归观察数组元素
    } else { // 对普通对象,递归观察其属性
      const keys = Object.keys(value)
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        defineReactive(value, key, NO_INITIAL_VALUE, undefined, shallow, mock)
      }
    }
  }
  observeArray(value: any[]) { // 递归观察数组中的每个元素
    for (let i = 0, l = value.length; i < l; i++) {
      observe(value[i], false, this.mock)
    }
  }
}
// observe函数,用于创建Observer实例观察数据
export function observe(
  value: any,
  shallow?: boolean,
  ssrMockReactivity?: boolean
): Observer | void {
  // 检查数据是否已被观察,数据已被观察retun
  if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    return value.__ob__
  }
  if (// 判断是否应该观察该数据
    shouldObserve && ...
  ) {
    return new Observer(value, shallow, ssrMockReactivity)//创建并返回新的Observer实例
  }
}
export function defineReactive( // defineReactive函数,用于定义响应式属性
	...	
) {
  
  const dep = new Dep()// 创建新的依赖管理器
  // 获取属性描述符,检查属性是否可配置
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }
   // 获取getter和setter
  const getter = property && property.get
  const setter = property && property.set
    // 如果没有setter但有getter,或者初始值为NO_INITIAL_VALUE,则获取当前值
  if ((!getter || setter) && (val === NO_INITIAL_VALUE || arguments.length === 2)
  ) {val = obj[key]}
  // 递归观察属性值
  let childOb = shallow ? val && val.__ob__ : observe(val, false, mock)
  // 使用Object.defineProperty定义响应式属性
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        if (__DEV__) {
          ...
          dep.depend({...})// 依赖收集
          ...
        }
        if (childOb) { // 有子内容,递归遍历
          childOb.dep.depend()
          if (isArray(value)) {dependArray(value)}
        }
      }
      return isRef(value) && !shallow ? value.value : value
    },
    set: function reactiveSetter(newVal) {
      const value = getter ? getter.call(obj) : val
      if (!hasChanged(value, newVal)) {return}
      if (__DEV__ && customSetter) {customSetter()}
      // 调用自定义setter或原生setter
      if (setter) {
        setter.call(obj, newVal)
      } else if (getter) {
        return // 对于只有getter没有setter的属性,直接返回
      } else if (!shallow && isRef(value) && !isRef(newVal)) {
        value.value = newVal
        return
      } else {
        val = newVal // 处理ref和普通值的更新
      }
      // 更新依赖并触发通知
      childOb = shallow ? newVal && newVal.__ob__ : observe(newVal, false, mock)
      ...
      dep.notify({...})
      ...
    }
  })
  return dep
}
export function set<T>(array: T[], key: number, value: T): T
export function set<T>(object: object, key: string | number, value: T): T
// set和del函数,用于在响应式对象上添加或删除属性
export function set(
  target: any[] | Record<string, any>,
  key: any,
  val: any
): any {
  if (__DEV__ && (isUndef(target) || isPrimitive(target))) {
    warn( // 不能在未定义、null或原始值上设置响应属性
      `Cannot set reactive property on undefined, null, or primitive value: ${target}`
    )
  }
  // 判断是否为只读
  if (isReadonly(target)) {
    __DEV__ && warn(`Set operation on key "${key}" failed: target is readonly.`)
    return
  }
  //...省略部分判断内容
  defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock)
  // 通知所有订阅者更新
  ...
  ob.dep.notify({...})
  ...
  return val
}
export function del<T>(array: T[], key: number): void
export function del(object: object, key: string | number): void
export function del(target: any[] | object, key: any) {
 // ...省略方法内容,和set类似
}
// 遍历数组,对每个元素进行依赖收集
function dependArray(value: Array<any>) {
  for (let e, i = 0, l = value.length; i < l; i++) {
    e = value[i]
    if (e && e.__ob__) {
      e.__ob__.dep.depend()
    }
    if (isArray(e)) {
      dependArray(e)
    }
  }
}

1.3 vue源码 - Dep(依赖收集)

  • Dep依赖收集系统,用于Vue.js或类似框架中的响应式系统。
  • 它允许对象(Dep实例)被观察,并且当这些对象发生变化时,可以通知所有订阅这些变化的观察者(DepTarget实例)。涉及到依赖收集(depend方法)和通知更新(notify方法)。
  • 提供了用于管理当前正在评估的目标观察者的栈(targetStack),以及清理不再需要的订阅者的机制(cleanupDeps函数和相关逻辑)。
// 引入配置文件
let uid = 0; // 初始化一个用于生成Dep实例唯一标识符的变量,从0开始递增
const pendingCleanupDeps: Dep[] = []; // 定义一个数组,用于存储待清理的Dep实例
export const cleanupDeps = () => { // 定义一个函数,用于清理待清理的Dep实例
  for (let i = 0; i < pendingCleanupDeps.length; i++) {
    const dep = pendingCleanupDeps[i];
    dep.subs = dep.subs.filter(s => s);// 过滤掉null的订阅者
    dep._pending = false;// 重置待清理状态
  }
  pendingCleanupDeps.length = 0;// 清空待清理数组
};
...
// 定义一个Dep类,表示一个可以被多个指令订阅的可观察对象
export default class Dep {
  static target?: DepTarget | null; // 静态属性,用于存储当前正在评估的目标观察者,全局唯一
  id: number; // Dep实例的唯一标识符
  subs: Array<DepTarget | null>; // 存储订阅者的数组
  _pending = false;// 标记是否有待清理的订阅者
  constructor() {
    this.id = uid++; // 分配唯一标识符
    this.subs = []; // 初始化订阅者数组
  }
  
  addSub(sub: DepTarget) {// 添加订阅者
    this.subs.push(sub);
  }
  removeSub(sub: DepTarget) {  // 移除订阅者,将其置为null并标记为待清理
    this.subs[this.subs.indexOf(sub)] = null;
    if (!this._pending) {
      this._pending = true;
      pendingCleanupDeps.push(this); // 将自己添加到待清理数组
    }
  }
  // 依赖收集,当Dep.target存在时,将自己添加到Dep.target的依赖中
  depend(info?: DebuggerEventExtraInfo) {
    if (Dep.target) {
      Dep.target.addDep(this);
     ...
    }
  }
  // 通知所有订阅者更新
  notify(info?: DebuggerEventExtraInfo) {
    const subs = this.subs.filter(s => s) as DepTarget[]; // 稳定订阅者列表,过滤掉null
    if (__DEV__ && !config.async) {
      subs.sort((a, b) => a.id - b.id); // 如果不是异步运行,则对订阅者进行排序以确保正确的触发顺序
    }
    for (let i = 0, l = subs.length; i < l; i++) {
      const sub = subs[i];
      if (__DEV__ && info) {
        sub.onTrigger &&
          sub.onTrigger({
            effect: subs[i],
            ...info
          });
      }
      sub.update(); // 调用订阅者的update方法
    }
  }
}
// 当前正在评估的目标观察者,全局唯一,因为一次只能评估一个观察者
Dep.target = null;
// 定义一个栈,用于存储目标观察者
const targetStack: Array<DepTarget | null | undefined> = [];
// 将目标观察者推入栈中,并设置Dep.target为当前目标
export function pushTarget(target?: DepTarget | null) {
  targetStack.push(target);
  Dep.target = target;
}
// 将目标观察者从栈中弹出,并更新Dep.target为新的栈顶目标
export function popTarget() {
  targetStack.pop();
  Dep.target = targetStack[targetStack.length - 1];
}

1.4 vue源码-Watcher

1.4.1 watcher类的实现

  • 负责监听Vue实例上的数据变化,并在变化时执行指定的回调函数。
  • Watcher类通过收集依赖(即数据变化时会通知watcher的数据对象),并在数据变化时更新自身的值和执行回调,从而实现了响应式的数据绑定。
  • 包含了错误处理、深度监听、懒执行、同步执行等特性,以及用于调试的钩子函数和属性。
...
let uid = 0 // 初始化一个唯一的ID生成器
// 定义Watcher的选项接口,继承自DebuggerOptions
export interface WatcherOptions extends DebuggerOptions {
  deep?: boolean // 是否深度监听
  user?: boolean // 是否是用户定义的watcher
  lazy?: boolean // 是否是懒执行watcher
  sync?: boolean // 是否同步执行
  before?: Function // 执行前的钩子函数
}
// 定义Watcher类,实现DepTarget接口
export default class Watcher implements DepTarget {
 ... 定义类的属性 ...
 ... 定义类的属性 ...
  constructor(
    vm: Component | null,
    expOrFn: string | (() => any),
    cb: Function,
    options?: WatcherOptions | null,
    isRenderWatcher?: boolean
  ) {
    // 记录当前watcher的作用域
    recordEffectScope(
      this,
      //如果激活的效果范围是手动创建的(不是一个组件范围),优先级为它
      activeEffectScope && !activeEffectScope._vm 
      ? activeEffectScope: vm ? vm._scope: undefined
    )
    // 如果是Vue组件实例且是渲染watcher,则将当前watcher设为组件的_watcher
    if ((this.vm = vm) && isRenderWatcher) { vm._watcher = this }
    if (options) {    // 初始化选项
     ...
      if (__DEV__) {
        this.onTrack = options.onTrack
        this.onTrigger = options.onTrigger
      }
    } else {
      this.deep = this.user = this.lazy = this.sync = false
    }
    // 初始化其他属性
  	...
    // 如果是lazy watcher,则不立即求值,否则调用get方法求值
    this.value = this.lazy ? undefined : this.get()
  }
  get() {// 获取当前值并重新收集依赖
    pushTarget(this)  // 将当前watcher设为依赖收集的目标
    let value
    const vm = this.vm
    try {
      value = this.getter.call(vm, vm)  // 执行getter函数获取值
    } catch (e: any) {
      if (this.user) {
        // 用户定义的watcher捕获错误
        handleError(e, vm, `getter for watcher "${this.expression}"`)
      } else {
        throw e // 非用户定义的watcher直接抛出错误
      }
    } finally {
      if (this.deep) { // 如果是深度监听,则遍历获取的值以收集所有依赖
        traverse(value)
      }
      popTarget() // 将当前watcher从依赖收集的目标中移除
      this.cleanupDeps() // 清理依赖
    }
    return value
  }

// 添加依赖
  addDep(dep: Dep) {
    const id = dep.id
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id)
      this.newDeps.push(dep)
      if (!this.depIds.has(id)) {
        dep.addSub(this) // 添加当前watcher为dep的订阅者
      }
    }
  }

//清理依赖
  cleanupDeps() {
    let i = this.deps.length
    while (i--) {
      const dep = this.deps[i]
      if (!this.newDepIds.has(dep.id)) {
        dep.removeSub(this) // 从dep的订阅者列表中移除当前watcher
      }
    }
    // 交换新旧依赖数组和集合,并清空新的集合和数组
    let tmp: any = this.depIds
    this.depIds = this.newDepIds
    this.newDepIds = tmp
    this.newDepIds.clear()
    tmp = this.deps
    this.deps = this.newDeps
    this.newDeps = tmp
    this.newDeps.length = 0
  }

//当依赖变化时调用
  update() {
    if (this.lazy) {// 标记为需要重新求值
      this.dirty = true
    } else if (this.sync) {
      this.run() // 同步执行
    } else {
      queueWatcher(this)  // 异步执行,加入调度队列
    }
  }
  run() {
    if (this.active) {// 检查Watcher是否处于激活状态
      const value = this.get()// 获取当前Watcher所观察的数据的值
      if (// 判断值是否变化,或者值是否为对象/数组(因为对象和数组可能内部变化但引用不变),
      // 或者是否开启了深度观察
      value !== this.value ||isObject(value) ||this.deep
      ) {
        const oldValue = this.value// 更新旧值和新值
        this.value = value
        if (this.user) {// 如果Watcher是用户定义的,则使用带有错误处理的调用方式执行回调
          const info = `callback for watcher "${this.expression}"`
          invokeWithErrorHandling(...)
        } else {// 否则直接调用回调
          this.cb.call(this.vm, value, oldValue)
        }
      }
    }
  }
  evaluate() { // 更新Watcher的值,并标记(即已评估)
    this.value = this.get()
    this.dirty = false
  }

//取决于这个观察者收集的所有深度(依赖)。
  depend() {// 遍历Watcher的所有依赖,并调用它们的depend方法
    let i = this.deps.length
    while (i--) {this.deps[i].depend()}
  }

  //从所有依赖项的订阅者列表中删除自身。
  teardown() {
    // 如果Vue实例存在且未被销毁,则从Vue实例的作用域效果列表中移除当前Watcher
    if (this.vm && !this.vm._isBeingDestroyed) {remove(this.vm._scope.effects, this) }
    // 如果Watcher处于激活状态,则遍历其所有依赖,并从每个依赖的订阅者列表中移除当前Watcher
    if (this.active) {
      let i = this.deps.length
      while (i--) {this.deps[i].removeSub(this)}
      this.active = false // 将Watcher标记为非激活状态
      if (this.onStop) {this.onStop()// 如果定义了onStop回调,则调用它
      }
    }
  }
}

1.4.2 watcher队列管理

  • watcher用于监听Vue组件或数据的变化,并在变化发生时执行相应的回调函数。
  • 该代码通过维护一个队列来批量处理这些变化,以提高性能。同时,它还包含了一些用于处理组件激活和更新钩子的逻辑。

export const MAX_UPDATE_COUNT = 100 // 定义最大更新次数常量,用于检测无限更新循环
const queue: Array<Watcher> = [] // 定义用于存储待执行watcher的队列
const activatedChildren: Array<Component> = [] // 定义用于存储已激活子组件的队列
let has: { [key: number]: true | undefined | null } = {} // 定义一个对象,用于标记已处理的watcher ID
let circular: { [key: number]: number } = {}// 定义一个对象,用于记录循环更新的次数
let waiting = false // 定义一个标志,表示是否正在等待执行队列
let flushing = false // 定义一个标志,表示是否正在刷新队列
let index = 0 // 定义一个索引,用于遍历队列
 
//重置调度器状态
function resetSchedulerState() {
  index = queue.length = activatedChildren.length = 0 // 重置索引和队列长度
  has = {} // 重置has对象
  if (__DEV__) { circular = {}}// 如果是开发模式,则重置circular对象
  waiting = flushing = false // 重置等待和刷新标志
}
export let currentFlushTimestamp = 0 // 定义一个变量,用于存储当前刷新时间戳
let getNow: () => number = Date.now // 定义一个函数,用于获取当前时间戳
if (inBrowser && !isIE) { // 根据浏览器环境选择合适的时间戳获取方式
	// 调用getNow()...
}
// 对watcher队列进行排序
const sortCompareFn = (a: Watcher, b: Watcher): number => {
  if (a.post) {...} // 根据post属性和id进行排序
  return a.id - b.id
}
function flushSchedulerQueue() { //刷新队列并执行watchers
  currentFlushTimestamp = getNow() // 更新当前刷新时间戳
  flushing = true // 设置刷新标志
  let watcher, id
  queue.sort(sortCompareFn)// 对队列进行排序
  // 遍历队列并执行watchers
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index]
    if (watcher.before) {watcher.before()}
    id = watcher.id
    has[id] = null
    watcher.run()
    // 在开发模式下,检查并停止循环更新
    if (__DEV__ && has[id] != null) {
     	...
        break
      }
    }
  }
  // 保存post队列的副本,然后重置状态
  const activatedQueue = activatedChildren.slice()
  const updatedQueue = queue.slice()
  resetSchedulerState()
   // 调用组件的updated和activated钩子
  callActivatedHooks(activatedQueue)
  callUpdatedHooks(updatedQueue)
  cleanupDeps()
   // 触发devtools钩子
  if (devtools && config.devtools) {devtools.emit('flush')}
}

function callUpdatedHooks(queue: Watcher[]) {
  let i = queue.length
  while (i--) {
    const watcher = queue[i]
    const vm = watcher.vm
    // 如果vm存在且watcher是组件的渲染watcher且组件已挂载且未销毁,则调用updated钩子
    if (vm && vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
      callHook(vm, 'updated')
    }
  }
}

//将一个保持活动的组件添加到激活队列中。该队列将在整个树被修补后处理。
export function queueActivatedComponent(vm: Component) {
  // 设置_inactive为false,以便渲染函数可以依赖检查它是否在不活动的树中
  vm._inactive = false
  activatedChildren.push(vm)
}

function callActivatedHooks(queue) {
  // 遍历激活队列,调用组件的activate钩子
  for (let i = 0; i < queue.length; i++) {
    queue[i]._inactive = true
    activateChildComponent(queue[i], true /* true */)
  }
}
//将一个watcher推入watcher队列。具有重复ID的作业将被跳过,除非它是在队列正在刷新时推送的。
export function queueWatcher(watcher: Watcher) {
  const id = watcher.id
  if (has[id] != null) {return}  // 如果已处理过该watcher,则直接返回
  // 如果watcher是当前Dep的target且设置了noRecurse,则直接返回
  if (watcher === Dep.target && watcher.noRecurse) {return}
  has[id] = true // 标记该watcher为已处理
  if (!flushing) { // 如果不在刷新状态,则将watcher添加到队列中
    queue.push(watcher)
  } else {
    // 如果正在刷新,则根据id将watcher插入到合适的位置
    let i = queue.length - 1
    while (i > index && queue[i].id > watcher.id) {i--}
    queue.splice(i + 1, 0, watcher)
  }
  if (!waiting) {  // 队列化刷新操作
    waiting = true
    if (__DEV__ && !config.async) {// 如果是开发模式且未启用异步更新,则直接刷新队列
      flushSchedulerQueue()
      return
    }
    nextTick(flushSchedulerQueue)// 否则,使用nextTick进行异步刷新
  }
}

1.5 Compiler-解析指令

1.5.1 createCompiler函数

  • 使用createCompilerCreator创建一个默认的编译器,createCompilerCreator允许创建使用替代解析器/优化器/代码生成器的编译器
  • 例如,用于服务器端渲染(SSR)优化的编译器
export const createCompiler = createCompilerCreator(function baseCompile(
  template: string, // 模板字符串,Vue组件的模板部分
  options: CompilerOptions // 编译器选项,用于自定义编译行为
): CompiledResult { // 解析模板字符串为AST
  const ast = parse(template.trim(), options)
  // 如果未禁用优化,则对AST进行优化
  if (options.optimize !== false) {optimize(ast, options)  }
  const code = generate(ast, options)// 将优化后的AST转换为渲染函数代码

	// 返回编译结果,包含AST、渲染函数和静态渲染函数数组
 	return {
 	  ast, // 抽象语法树,用于调试或其他目的
 	  render: code.render, // 渲染函数,用于生成和更新虚拟DOM
 	  staticRenderFns: code.staticRenderFns // 静态渲染函数数组,用于渲染不依赖组件状态的静态内容
	};
})

1.5.2 createCompilerCreator-编译器工厂函数

  • 创建编译器工厂函数的实现。Vue的模板编译器负责将模板字符串转换成可执行的渲染函数。
  • 导出一个函数 createCompilerCreator,接收一个编译函数 baseCompile 作为参数,并返回一个新的函数
export function createCompilerCreator(baseCompile: Function): Function {
  return function createCompiler(baseOptions: CompilerOptions) {
    // compile 函数是创建编译器的核心,它接收一个模板字符串 template 和一个可选的编译选项对象 options
    function compile(
      template: string,
      options?: CompilerOptions
    ): CompiledResult {
      // 创建一个新的对象 finalOptions,其原型为 baseOptions,用于存储最终的编译选项
      const finalOptions = Object.create(baseOptions)
      // 初始化一个空数组,用于存储编译过程中的错误信息
      const errors: WarningMessage[] = []
      // 初始化一个空数组,用于存储编译过程中的提示信息
      const tips: WarningMessage[] = []

      // 定义一个 warn 函数,用于在编译过程中记录警告信息或错误信息
      // 它接收一个消息 msg,一个位置范围 range,以及一个可选的提示信息 tip
      let warn = (msg,range,tip) => {
        // 根据是否有 tip 参数,将警告信息推入到对应的数组(errors 或 tips)中
        ;(tip ? tips : errors).push(msg)
      }
      if (options) {
        // 在开发模式下,如果启用了输出源码范围的功能,则进行以下处理
        if (__DEV__ && options.outputSourceRange) {
          // 计算模板字符串开头的空白字符数量
          const leadingSpaceLength = template.match(/^\s*/)![0].length
          // 重新定义 warn 函数,使其能够处理源码范围,并考虑开头的空白字符
          warn = (msg,range,tip) => {
            // 将 msg 转换为 WarningMessage 对象
            const data: WarningMessage = typeof msg === 'string' ? { msg } : msg
            if (range) {
              // 调整 start 和 end 以考虑开头的空白字符
              if (range.start != null) {data.start = range.start + leadingSpaceLength }
              if (range.end != null) { data.end = range.end + leadingSpaceLength }
            }
            // 根据是否有 tip 参数,将警告信息推入到对应的数组(errors 或 tips)中
            ;(tip ? tips : errors).push(data)
          }
        }
        if (options.modules) { // 如果提供了自定义模块,则将它们合并到 finalOptions.modules 中
          finalOptions.modules = (baseOptions.modules || []).concat(options.modules)
        }
       
        if (options.directives) { // 如果提供了自定义指令,则将它们合并到 finalOptions.directives中
          finalOptions.directives = extend(Object.create(baseOptions.directives || null), 
          options.directives
          )
        }
        for (const key in options) { // 复制其他选项到 finalOptions 中
          if (key !== 'modules' && key !== 'directives') {
            finalOptions[key] = options[key as keyof CompilerOptions]
          }
        }
      }
      finalOptions.warn = warn // 将 warn 函数赋值给 finalOptions.warn
      // 调用 baseCompile 函数进行编译,传入处理后的模板字符串和最终的编译选项
      const compiled = baseCompile(template.trim(), finalOptions)
      
      if (__DEV__) {detectErrors(compiled.ast, warn)} // 在开发模式下,检测编译后的 AST 中的错误
      // 将错误信息和提示信息赋值给编译结果对象
      compiled.errors = errors
      compiled.tips = tips
      
      return compiled // 返回编译结果
    }

    // 返回包含 compile 函数和 compileToFunctions 函数的对象
    // compileToFunctions 函数用于将模板编译成可执行的渲染函数
    return {
      compile,
      compileToFunctions: createCompileToFunctionFn(compile)
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值