我的主页我的主页
主页
教程
Vue3源码解析
主页
教程
Vue3源码解析
  • Vue3核心知识

    • Vue3核心知识点总览
    • Vue3架构设计详解
    • Vue3响应式系统详解
    • Vue3虚拟DOM系统详解
    • Vue3编译器系统详解
    • Vue3组件系统详解
    • Vue3性能优化详解

Vue3编译器系统详解

🎯 编译器概述

Vue3的编译器系统是框架的核心优化引擎,它将模板编译成高效的渲染函数,实现了编译时优化和运行时性能提升。

编译器架构图

┌─────────────────────────────────────┐
│        模板层 (Template Layer)      │
│  <template> | 字符串模板 | JSX      │
├─────────────────────────────────────┤
│        解析层 (Parse Layer)         │
│  词法分析 | 语法分析 | AST生成      │
├─────────────────────────────────────┤
│        转换层 (Transform Layer)     │
│  静态提升 | 补丁标志 | 块级优化     │
├─────────────────────────────────────┤
│        生成层 (Codegen Layer)       │
│  渲染函数 | 优化代码 | 源码映射     │
└─────────────────────────────────────┘

🔍 解析阶段 (Parse)

1. 词法分析 (Lexical Analysis)

// 词法分析器状态
export enum State {
  Text = 1, // 文本状态
  InterpolationOpen, // 插值开始
  Interpolation, // 插值内容
  InterpolationClose, // 插值结束
  BeforeTagName, // 标签名前
  InTagName, // 标签名中
  InSelfClosingTag, // 自闭合标签
  BeforeClosingTagName, // 结束标签名前
  InClosingTagName, // 结束标签名中
  AfterClosingTagName, // 结束标签名后
  BeforeAttrName, // 属性名前
  InAttrName, // 属性名中
  InDirName, // 指令名中
  InDirArg, // 指令参数中
  InDirDynamicArg, // 动态指令参数中
  InDirModifier, // 指令修饰符中
  AfterAttrName, // 属性名后
  BeforeAttrValue, // 属性值前
  InAttrValueDq, // 双引号属性值
  InAttrValueSq, // 单引号属性值
  InAttrValueNq, // 无引号属性值
  BeforeDeclaration, // 声明前
  InDeclaration, // 声明中
  BeforeComment, // 注释前
  InComment, // 注释中
  BeforeSpecialS, // 特殊标签前
  BeforeSpecialT, // 特殊标签前
  InRCDATA, // RCDATA中
  InEntity, // 实体中
}

// 词法分析器
export function baseParse(
  content: string,
  options: ParserOptions = {},
): RootNode {
  const context = createParserContext(content, options)
  const start = getCursor(context)
  return createRoot(
    parseChildren(context, TextModes.DATA, []),
    getSelection(context, start),
  )
}

2. 语法分析 (Syntax Analysis)

// 解析子节点
function parseChildren(
  context: ParserContext,
  mode: TextModes,
  ancestors: ElementNode[],
): TemplateChildNode[] {
  const parent = last(ancestors)
  const ns = parent ? parent.ns : Namespaces.HTML
  const nodes: TemplateChildNode[] = []

  while (!isEnd(context, mode, ancestors)) {
    const s = context.source
    let node: TemplateChildNode | TemplateChildNode[] | undefined = undefined

    if (mode === TextModes.DATA || mode === TextModes.RCDATA) {
      if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {
        // 解析插值
        node = parseInterpolation(context, mode)
      } else if (mode === TextModes.DATA && s[0] === '<') {
        // 解析标签
        if (s.length === 1) {
          emitError(context, ErrorCodes.EOF_IN_TAG)
        } else if (s[1] === '!') {
          // 解析注释或DOCTYPE
          if (startsWith(s, '<!--')) {
            node = parseComment(context)
          } else if (startsWith(s, '<!DOCTYPE')) {
            node = parseBogusComment(context)
          } else if (startsWith(s, '<![CDATA[')) {
            if (ns !== Namespaces.HTML) {
              node = parseCDATA(context, ancestors)
            } else {
              emitError(context, ErrorCodes.CDATA_IN_HTML_CONTENT)
              node = parseBogusComment(context)
            }
          } else {
            emitError(context, ErrorCodes.INCORRECTLY_OPENED_COMMENT)
            node = parseBogusComment(context)
          }
        } else if (s[1] === '/') {
          // 解析结束标签
          if (/[a-z]/i.test(s[2])) {
            parseTag(context, TagType.End, parent)
            continue
          } else {
            emitError(context, ErrorCodes.INVALID_FIRST_CHARACTER_OF_TAG_NAME)
            node = parseBogusComment(context)
          }
        } else if (/[a-z]/i.test(s[1])) {
          // 解析开始标签
          node = parseElement(context, ancestors)
        } else if (s[1] === '?') {
          emitError(
            context,
            ErrorCodes.UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME,
          )
          node = parseBogusComment(context)
        } else {
          emitError(context, ErrorCodes.INVALID_FIRST_CHARACTER_OF_TAG_NAME)
        }
      }
    }

    if (!node) {
      // 解析文本
      node = parseText(context, mode)
    }

    if (isArray(node)) {
      for (let i = 0; i < node.length; i++) {
        pushNode(nodes, node[i])
      }
    } else {
      pushNode(nodes, node)
    }
  }

  return nodes
}

3. AST节点类型

export enum NodeTypes {
  ROOT, // 根节点
  ELEMENT, // 元素节点
  TEXT, // 文本节点
  COMMENT, // 注释节点
  SIMPLE_EXPRESSION, // 简单表达式
  INTERPOLATION, // 插值表达式
  ATTRIBUTE, // 属性节点
  DIRECTIVE, // 指令节点
  COMPOUND_EXPRESSION, // 复合表达式
  IF, // 条件节点
  IF_BRANCH, // 条件分支
  FOR, // 循环节点
  TEXT_CALL, // 文本调用
  VNODE_CALL, // VNode调用
  JS_CALL_EXPRESSION, // JS调用表达式
  JS_OBJECT_EXPRESSION, // JS对象表达式
  JS_PROPERTY, // JS属性
  JS_ARRAY_EXPRESSION, // JS数组表达式
  JS_FUNCTION_EXPRESSION, // JS函数表达式
  JS_CONDITIONAL_EXPRESSION, // JS条件表达式
  JS_CACHE_EXPRESSION, // JS缓存表达式
  JS_BLOCK_STATEMENT, // JS块语句
  JS_TEMPLATE_LITERAL, // JS模板字面量
  JS_IF_STATEMENT, // JS if语句
  JS_ASSIGNMENT_EXPRESSION, // JS赋值表达式
  JS_SEQUENCE_EXPRESSION, // JS序列表达式
  JS_RETURN_STATEMENT, // JS返回语句
}

// AST节点接口
export interface Node {
  type: NodeTypes
  loc: SourceLocation
}

export interface ElementNode extends Node {
  type: NodeTypes.ELEMENT
  ns: Namespaces
  tag: string
  tagType: ElementTypes
  isSelfClosing: boolean
  props: Array<AttributeNode | DirectiveNode>
  children: TemplateChildNode[]
}

export interface InterpolationNode extends Node {
  type: NodeTypes.INTERPOLATION
  content: ExpressionNode
}

export interface SimpleExpressionNode extends Node {
  type: NodeTypes.SIMPLE_EXPRESSION
  content: string
  isStatic: boolean
  constType: ConstantTypes
  hoisted?: JSChildNode
  isIdentifier?: boolean
}

🔄 转换阶段 (Transform)

1. 转换器架构

// 转换上下文
export interface TransformContext {
  root: RootNode
  helpers: Map<symbol, number>
  helper<T extends keyof typeof import('./runtimeHelpers')>(name: T): string
  helperString(name: string): string
  replaceNode(node: TemplateChildNode): void
  removeNode(node?: TemplateChildNode): void
  onNodeRemoved(): void
  addIdentifiers(exp: ExpressionNode | string): void
  removeIdentifiers(exp: ExpressionNode | string): void
  hoist(exp: string | JSChildNode | Array<string | JSChildNode>): string
  cache<T extends Node>(exp: T, isVNode?: boolean): string | T
  constantCache: Map<TemplateChildNode, string>
  filters?: Set<string>
  prefixIdentifiers?: boolean
  preTransformNode(node: ElementNode): ElementNode | void
  postTransformNode?: (node: ElementNode) => void | (() => void)
  onError: (error: CompilerError) => void
}

// 节点转换器
export type NodeTransform = (
  node: RootNode | TemplateChildNode,
  context: TransformContext,
) => void | (() => void) | (() => void)[]

// 指令转换器
export type DirectiveTransform = (
  dir: DirectiveNode,
  node: ElementNode,
  context: TransformContext,
  augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult,
) => DirectiveTransformResult

2. 静态提升 (Static Hoisting)

// 静态提升转换器
export const transformHoist: NodeTransform = (node, context) => {
  if (
    node.type === NodeTypes.ELEMENT &&
    node.tagType === ElementTypes.ELEMENT
  ) {
    const { constantCache } = context

    // 检查是否为静态节点
    const hoisted = getHoistedNode(node, context)
    if (hoisted) {
      // 提升静态节点
      context.hoist(hoisted)
      // 替换为静态引用
      context.replaceNode(
        createSimpleExpression(
          context.helperString(HoistType.HOISTED),
          false,
          node.loc,
        ),
      )
    }
  }
}

// 获取可提升的节点
function getHoistedNode(
  node: ElementNode,
  context: TransformContext,
): string | undefined {
  const { constantCache } = context

  // 检查是否已经缓存
  if (constantCache.has(node)) {
    return constantCache.get(node)
  }

  // 检查是否为静态节点
  if (isStaticNode(node)) {
    const hoisted = generateStaticNode(node, context)
    constantCache.set(node, hoisted)
    return hoisted
  }

  return undefined
}

// 检查静态节点
function isStaticNode(node: ElementNode): boolean {
  // 检查属性是否静态
  for (const prop of node.props) {
    if (prop.type === NodeTypes.DIRECTIVE) {
      return false
    }
    if (prop.type === NodeTypes.ATTRIBUTE) {
      if (prop.value && !isStaticExp(prop.value)) {
        return false
      }
    }
  }

  // 检查子节点是否静态
  for (const child of node.children) {
    if (!isStaticChild(child)) {
      return false
    }
  }

  return true
}

3. 补丁标志 (Patch Flags)

// 补丁标志转换器
export const transformElement: NodeTransform = (node, context) => {
  if (node.type !== NodeTypes.ELEMENT) {
    return
  }

  const { tag, props } = node
  const isComponent = isComponentTag(tag)

  // 处理组件
  if (isComponent) {
    return transformComponent(node, context)
  }

  // 处理元素
  const vnodeTag = `"${tag}"`
  const vnodeProps = buildProps(node, context)
  const vnodeChildren = node.children.length
    ? buildChildren(node, context)
    : undefined

  // 生成补丁标志
  const patchFlag = getPatchFlag(node, context)

  // 生成动态属性
  const dynamicProps = getDynamicProps(node, context)

  // 创建VNode调用
  context.replaceNode(
    createVNodeCall(
      context,
      vnodeTag,
      vnodeProps,
      vnodeChildren,
      patchFlag,
      dynamicProps,
    ),
  )
}

// 获取补丁标志
function getPatchFlag(node: ElementNode, context: TransformContext): number {
  let patchFlag = 0

  // 检查动态属性
  for (const prop of node.props) {
    if (prop.type === NodeTypes.DIRECTIVE) {
      const dir = prop
      if (dir.name === 'bind') {
        patchFlag |= PatchFlags.PROPS
      } else if (dir.name === 'on') {
        patchFlag |= PatchFlags.HYDRATE_EVENTS
      }
    } else if (prop.type === NodeTypes.ATTRIBUTE) {
      if (prop.name === 'class') {
        patchFlag |= PatchFlags.CLASS
      } else if (prop.name === 'style') {
        patchFlag |= PatchFlags.STYLE
      }
    }
  }

  // 检查动态子节点
  for (const child of node.children) {
    if (child.type === NodeTypes.INTERPOLATION) {
      patchFlag |= PatchFlags.TEXT
    }
  }

  return patchFlag
}

4. 块级优化 (Block Optimization)

// 块级优化转换器
export const transformBlock: NodeTransform = (node, context) => {
  if (node.type !== NodeTypes.ELEMENT) {
    return
  }

  // 检查是否为块级节点
  if (hasDynamicChildren(node)) {
    // 标记为块级节点
    context.replaceNode(createBlock(node, context))
  }
}

// 检查是否有动态子节点
function hasDynamicChildren(node: ElementNode): boolean {
  for (const child of node.children) {
    if (child.type === NodeTypes.INTERPOLATION) {
      return true
    }
    if (child.type === NodeTypes.ELEMENT) {
      if (hasDynamicProps(child)) {
        return true
      }
      if (hasDynamicChildren(child)) {
        return true
      }
    }
  }
  return false
}

// 创建块级节点
function createBlock(node: ElementNode, context: TransformContext): VNodeCall {
  const { tag, props, children } = node

  return createVNodeCall(
    context,
    `"${tag}"`,
    buildProps(node, context),
    buildChildren(node, context),
    getPatchFlag(node, context),
    getDynamicProps(node, context),
    true, // isBlock
  )
}

🎨 代码生成 (Codegen)

1. 代码生成器

// 代码生成上下文
export interface CodegenContext {
  source: string
  code: string
  line: number
  column: number
  offset: number
  indentLevel: number
  push(code: string, node?: Node): void
  indent(): void
  deindent(withoutNewLine?: boolean): void
  newline(): void
}

// 代码生成结果
export interface CodegenResult {
  code: string
  preamble: string
  ast: RootNode
  map?: RawSourceMap
}

// 生成代码
export function generate(
  ast: RootNode,
  options: CodegenOptions = {},
): CodegenResult {
  const context = createCodegenContext(ast, options)

  const { mode, push, prefixIdentifiers } = context
  const helpers = Array.from(ast.helpers)
  const hasHelpers = helpers.length > 0

  // 生成前导代码
  if (mode === 'module') {
    genModulePreamble(ast, context, genScopeId(ast, context))
  } else {
    genFunctionPreamble(ast, context)
  }

  // 生成渲染函数
  if (!prefixIdentifiers && mode === 'module') {
    push('function render(')
    genFunctionArguments(ast, context)
    push(') {\n')
  } else {
    push('function render(')
    genFunctionArguments(ast, context)
    push(') {\n')
  }

  // 生成函数体
  genIndent(context)
  push('return ')
  if (ast.codegenNode) {
    genNode(ast.codegenNode, context)
  } else {
    push('null')
  }

  // 结束函数
  context.deindent()
  push('\n}')

  return {
    code: context.code,
    preamble: context.preamble,
    ast,
    map: context.map ? context.map.toJSON() : undefined,
  }
}

2. 节点代码生成

// 生成节点代码
function genNode(node: CodegenNode, context: CodegenContext) {
  if (isString(node)) {
    context.push(node)
    return
  }

  switch (node.type) {
    case NodeTypes.ELEMENT:
    case NodeTypes.IF:
    case NodeTypes.FOR:
      genNode(node.codegenNode!, context)
      break
    case NodeTypes.TEXT:
      genText(node, context)
      break
    case NodeTypes.SIMPLE_EXPRESSION:
      genExpression(node, context)
      break
    case NodeTypes.INTERPOLATION:
      genInterpolation(node, context)
      break
    case NodeTypes.TEXT_CALL:
      genTextCall(node, context)
      break
    case NodeTypes.COMPOUND_EXPRESSION:
      genCompoundExpression(node, context)
      break
    case NodeTypes.COMMENT:
      genComment(node, context)
      break
    case NodeTypes.VNODE_CALL:
      genVNodeCall(node, context)
      break
    case NodeTypes.JS_CALL_EXPRESSION:
      genCallExpression(node, context)
      break
    case NodeTypes.JS_OBJECT_EXPRESSION:
      genObjectExpression(node, context)
      break
    case NodeTypes.JS_PROPERTY:
      genProperty(node, context)
      break
    case NodeTypes.JS_ARRAY_EXPRESSION:
      genArrayExpression(node, context)
      break
    case NodeTypes.JS_FUNCTION_EXPRESSION:
      genFunctionExpression(node, context)
      break
    case NodeTypes.JS_CONDITIONAL_EXPRESSION:
      genConditionalExpression(node, context)
      break
    case NodeTypes.JS_CACHE_EXPRESSION:
      genCacheExpression(node, context)
      break
    case NodeTypes.JS_BLOCK_STATEMENT:
      genBlockStatement(node, context)
      break
    case NodeTypes.JS_TEMPLATE_LITERAL:
      genTemplateLiteral(node, context)
      break
    case NodeTypes.JS_IF_STATEMENT:
      genIfStatement(node, context)
      break
    case NodeTypes.JS_ASSIGNMENT_EXPRESSION:
      genAssignmentExpression(node, context)
      break
    case NodeTypes.JS_SEQUENCE_EXPRESSION:
      genSequenceExpression(node, context)
      break
    case NodeTypes.JS_RETURN_STATEMENT:
      genReturnStatement(node, context)
      break
  }
}

// 生成VNode调用
function genVNodeCall(node: VNodeCall, context: CodegenContext) {
  const { push, helper, pure } = context
  const {
    tag,
    props,
    children,
    patchFlag,
    dynamicProps,
    directives,
    isBlock,
    disableTracking,
    isComponent,
  } = node

  if (directives) {
    push(helper(WITH_DIRECTIVES) + '(')
  }

  if (isBlock) {
    push(`(${helper(OPEN_BLOCK)}(${disableTracking ? 'true' : ''}), `)
  }

  if (pure) {
    push(PURE_ANNOTATION)
  }

  if (isComponent) {
    push(helper(RESOLVE_COMPONENT) + `(${tag})`)
  } else {
    push(helper(CREATE_ELEMENT_VNODE) + `(${tag}`)
  }

  if (props) {
    push(', ')
    genNode(props, context)
  } else {
    push(', null')
  }

  if (children) {
    push(', ')
    if (isArray(children)) {
      genNodeList(children, context)
    } else {
      genNode(children, context)
    }
  } else if (patchFlag !== undefined) {
    push(', null')
  }

  if (patchFlag !== undefined) {
    push(', ' + String(patchFlag))
    if (dynamicProps) {
      push(', ' + JSON.stringify(dynamicProps))
    }
  }

  push(')')

  if (isBlock) {
    push(')')
  }

  if (directives) {
    push(', ')
    genNode(directives, context)
    push(')')
  }
}

3. 优化代码生成

// 生成优化代码
function genOptimizedCode(ast: RootNode, context: CodegenContext) {
  // 生成静态提升
  if (ast.hoists.length) {
    context.push('const ')
    for (let i = 0; i < ast.hoists.length; i++) {
      if (i > 0) context.push(', ')
      context.push(`_hoisted_${i + 1}`)
    }
    context.push(' = ')
    for (let i = 0; i < ast.hoists.length; i++) {
      if (i > 0) context.push(', ')
      genNode(ast.hoists[i], context)
    }
    context.push('\n')
  }

  // 生成缓存
  if (ast.cached.length) {
    context.push('const ')
    for (let i = 0; i < ast.cached.length; i++) {
      if (i > 0) context.push(', ')
      context.push(`_cached_${i + 1}`)
    }
    context.push(' = ')
    for (let i = 0; i < ast.cached.length; i++) {
      if (i > 0) context.push(', ')
      context.push(helper(CACHE) + `(${i + 1}, `)
      genNode(ast.cached[i], context)
      context.push(')')
    }
    context.push('\n')
  }
}

🔧 编译器优化

1. 编译时优化

// 编译器选项
export interface CompilerOptions {
  mode?: 'module' | 'function' // 编译模式
  prefixIdentifiers?: boolean // 前缀标识符
  hoistStatic?: boolean // 静态提升
  cacheHandlers?: boolean // 缓存处理器
  scopeId?: string // 作用域ID
  slotted?: boolean // 插槽
  ssr?: boolean // 服务端渲染
  isNativeTag?: (tag: string) => boolean // 原生标签检查
  isBuiltInComponent?: (tag: string) => symbol | void // 内置组件检查
  delimiters?: [string, string] // 分隔符
  comments?: boolean // 保留注释
  whitespace?: 'preserve' | 'condense' // 空白处理
  bindingMetadata?: BindingMetadata // 绑定元数据
}

// 编译优化
export function compile(
  source: string | RootNode,
  options: CompilerOptions = {},
): CodegenResult {
  const ast = isString(source) ? baseParse(source, options) : source

  // 应用转换
  const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(
    options.prefixIdentifiers,
  )

  transform(ast, {
    ...options,
    nodeTransforms: [...nodeTransforms, ...(options.nodeTransforms || [])],
    directiveTransforms: {
      ...directiveTransforms,
      ...(options.directiveTransforms || {}),
    },
  })

  // 生成代码
  return generate(ast, {
    ...options,
    mode: options.mode || 'function',
  })
}

2. 运行时优化

// 运行时优化标志
export const enum RuntimeFlags {
  OPEN_BLOCK = 1 << 0,
  CREATE_ELEMENT_VNODE = 1 << 1,
  CREATE_VNODE = 1 << 2,
  CREATE_COMMENT = 1 << 3,
  CREATE_TEXT = 1 << 4,
  CREATE_STATIC = 1 << 5,
  RESOLVE_COMPONENT = 1 << 6,
  RESOLVE_DIRECTIVE = 1 << 7,
  WITH_DIRECTIVES = 1 << 8,
  RENDER_LIST = 1 << 9,
  RENDER_SLOT = 1 << 10,
  TO_STRING = 1 << 11,
  TO_DISPLAY_STRING = 1 << 12,
  INTERPOLATE = 1 << 13,
  SET_BLOCK_TRACKING = 1 << 14,
  PUSH_SCOPE_ID = 1 << 15,
  POP_SCOPE_ID = 1 << 16,
  WITH_CTX = 1 << 17,
  UNREF = 1 << 18,
  IS_REF = 1 << 19,
  WITH_MEMO = 1 << 20,
  IS_MEMO_SAME = 1 << 21,
}

// 运行时助手
export const helperNameMap: Record<symbol, string> = {
  [OPEN_BLOCK]: 'openBlock',
  [CREATE_ELEMENT_VNODE]: 'createElementVNode',
  [CREATE_VNODE]: 'createVNode',
  [CREATE_COMMENT]: 'createCommentVNode',
  [CREATE_TEXT]: 'createTextVNode',
  [CREATE_STATIC]: 'createStaticVNode',
  [RESOLVE_COMPONENT]: 'resolveComponent',
  [RESOLVE_DIRECTIVE]: 'resolveDirective',
  [WITH_DIRECTIVES]: 'withDirectives',
  [RENDER_LIST]: 'renderList',
  [RENDER_SLOT]: 'renderSlot',
  [TO_STRING]: 'toString',
  [TO_DISPLAY_STRING]: 'toDisplayString',
  [INTERPOLATE]: 'interpolate',
  [SET_BLOCK_TRACKING]: 'setBlockTracking',
  [PUSH_SCOPE_ID]: 'pushScopeId',
  [POP_SCOPE_ID]: 'popScopeId',
  [WITH_CTX]: 'withCtx',
  [UNREF]: 'unref',
  [IS_REF]: 'isRef',
  [WITH_MEMO]: 'withMemo',
  [IS_MEMO_SAME]: 'isMemoSame',
}

📊 性能优化

1. 编译时优化策略

// 静态提升优化
const hoisted = /*#__PURE__*/ createVNode('div', { class: 'static' })

// 补丁标志优化
const patchFlag = PatchFlags.CLASS | PatchFlags.STYLE

// 块级优化
const dynamicChildren = [dynamicVNode1, dynamicVNode2]

// 缓存优化
const cached = _cache(1, () => expensiveComputation())

2. 运行时优化策略

// 快速路径检查
if (patchFlag > 0) {
  // 有补丁标志,进行优化更新
  if (patchFlag & PatchFlags.CLASS) {
    // 只更新类名
  }
  if (patchFlag & PatchFlags.STYLE) {
    // 只更新样式
  }
} else {
  // 无补丁标志,全量更新
}

// 块级更新
if (dynamicChildren) {
  // 只更新动态子节点
  for (let i = 0; i < dynamicChildren.length; i++) {
    patch(dynamicChildren[i], newDynamicChildren[i])
  }
}

🎯 总结

Vue3的编译器系统展现了现代前端框架的设计精髓:

  1. 高效解析 - 词法分析 + 语法分析 + AST生成
  2. 智能转换 - 静态提升 + 补丁标志 + 块级优化
  3. 优化生成 - 渲染函数 + 优化代码 + 源码映射
  4. 编译时优化 - 多种优化策略组合
  5. 运行时优化 - 快速路径 + 块级更新
  6. 跨平台支持 - 模块化 + 可扩展

这套编译器系统不仅为Vue3提供了高效的编译能力,也为其他前端项目提供了优秀的设计参考。

最近更新:: 2025/8/7 11:48
Prev
Vue3虚拟DOM系统详解
Next
Vue3组件系统详解