📘 Vue 3 模板解析器源码精讲(baseParse.ts)

🧩 总体结构概览

这个文件的职责是将模板字符串解析为抽象语法树(AST)。

整体由三层结构组成:

层级 内容 作用
外层定义 类型声明、常量、状态变量 管理解析过程中的全局状态
核心函数组 解析、节点生成、错误处理 负责模板解析逻辑
辅助函数组 工具类,如 getLoccondenseWhitespace 辅助主流程的定位与优化

第一部分:全局状态与初始化逻辑


### 1️⃣ reset()

ini 复制代码
function reset() {
  tokenizer.reset()
  currentOpenTag = null
  currentProp = null
  currentAttrValue = ''
  currentAttrStartIndex = -1
  currentAttrEndIndex = -1
  stack.length = 0
}

📖 功能说明

清空所有解析状态,用于开始一次新的模板解析任务。

🔍 逻辑拆解

步骤 操作 说明
tokenizer.reset() 重置状态机(清空缓冲、位置指针)
清空当前正在解析的标签 (currentOpenTag) 避免上次解析的残留
清空属性状态 (currentPropcurrentAttrValue) 防止多属性串联错误
重置索引标记 用于属性值的精确定位
清空标签栈 重新开始解析树结构

💡 原理

解析器是状态机驱动 的;每次调用 baseParse() 之前必须保证状态干净。

若不清理状态,标签嵌套关系会混乱,导致 AST 错误。


### 2️⃣ baseParse(input, options?)

scss 复制代码
export function baseParse(input: string, options?: ParserOptions): RootNode {
  reset()
  currentInput = input
  currentOptions = extend({}, defaultParserOptions)

  if (options) {
    for (let key in options) {
      if (options[key] != null) currentOptions[key] = options[key]
    }
  }
  ...
  const root = (currentRoot = createRoot([], input))
  tokenizer.parse(currentInput)
  root.loc = getLoc(0, input.length)
  root.children = condenseWhitespace(root.children)
  currentRoot = null
  return root
}

📖 功能说明

baseParse 是整个文件的主函数

负责从模板字符串生成 AST 树的根节点RootNode)。


🔍 逻辑拆解

步骤 描述
① 调用 reset() 清空上一次解析状态
② 保存输入模板 存入 currentInput
③ 合并解析选项 使用 extend 结合用户自定义配置与默认值
④ 初始化解析模式 根据 parseMode 确定 HTML / SFC / Base 模式
⑤ 初始化 tokenizer 设置分隔符、命名空间、XML 模式
⑥ 创建根节点 createRoot([], input)
⑦ 启动解析 tokenizer.parse(currentInput)(核心状态机驱动)
⑧ 修正位置与空白 调用 getLoccondenseWhitespace
⑨ 返回完整的 AST 含子节点、位置信息等

🧠 原理说明

Vue 使用 事件驱动解析模型
tokenizer 扫描模板时,会触发一系列回调(如 onopentagnameontext 等),这些回调逐步组装出 AST 节点。


🧩 拓展示例

xml 复制代码
baseParse('<div v-if="ok">{{ msg }}</div>')

➡ 输出的 RootNode 类似于:

css 复制代码
{
  "type": 0,
  "children": [
    {
      "type": 1,
      "tag": "div",
      "props": [
        { "type": 7, "name": "if", "exp": { "content": "ok" } }
      ],
      "children": [
        { "type": 5, "content": { "content": "msg" } }
      ]
    }
  ]
}

### 3️⃣ emitError()

less 复制代码
function emitError(code: ErrorCodes, index: number, message?: string) {
  currentOptions.onError(
    createCompilerError(code, getLoc(index, index), undefined, message),
  )
}

📖 功能说明

统一的错误上报函数。负责将解析阶段的错误格式化为 CompilerError 对象并交给回调。

🔍 逻辑拆解

步骤 内容
调用 createCompilerError 构造错误对象
使用 getLoc() 精确标出错误发生的位置
调用配置的 onError 回调进行处理(默认:打印警告)

💡 设计思路

通过错误码系统(ErrorCodes),Vue 可以在编译时快速定位语法错误,如:

  • 缺少闭合标签;
  • 不合法的插值表达式;
  • 指令名拼写错误等。

### 4️⃣ getSlice(start, end)

sql 复制代码
function getSlice(start: number, end: number) {
  return currentInput.slice(start, end)
}

📖 功能说明

从源字符串中截取对应区间的内容。

🧩 应用场景

用于生成 AST 节点的 sourceloc.source 信息,保证定位准确。


### 5️⃣ getLoc(start, end?)

sql 复制代码
function getLoc(start: number, end?: number): SourceLocation {
  return {
    start: tokenizer.getPos(start),
    end: end == null ? end : tokenizer.getPos(end),
    source: end == null ? end : getSlice(start, end),
  }
}

📖 功能说明

生成一个 SourceLocation 对象,表示源代码位置范围(用于调试与错误提示)。

💡 原理

tokenizer.getPos() 会将字符偏移量转换为:

yaml 复制代码
{ offset: 10, line: 1, column: 11 }

这样,Vue 编译错误可以指明"出错的行列位置"。


### 6️⃣ setLocEnd()

arduino 复制代码
function setLocEnd(loc: SourceLocation, end: number) {
  loc.end = tokenizer.getPos(end)
  loc.source = getSlice(loc.start.offset, end)
}

📖 功能说明

更新现有位置对象的结束坐标(用于文本合并或标签闭合时)。


### 7️⃣ cloneLoc()

arduino 复制代码
export function cloneLoc(loc: SourceLocation): SourceLocation {
  return getLoc(loc.start.offset, loc.end.offset)
}

📖 功能说明

复制一个 SourceLocation(防止引用同一对象造成修改污染)。


✨ 下一部分预告

上面我们讲完了基础状态管理与定位逻辑。

接下来第二章将进入 标签与文本节点解析函数组,包括:

  • onText()
  • onCloseTag()
  • endOpenTag()
  • addNode()
  • condenseWhitespace()
  • 等一系列高频调用函数。

这些函数负责 AST 的结构构建与白名单清理,是 Vue 模板语法语义识别的核心。

相关推荐
excel5 小时前
Vue 编译器核心模块结构与导出机制详解
前端
excel5 小时前
第二章:标签与文本节点解析函数组详解
前端
excel5 小时前
Vue 3 编译器源码深度解析:codegen.ts 模块详解
前端
一个假的前端男5 小时前
uniapp vue2 三端瀑布流
前端·javascript·uni-app
excel5 小时前
Vue 编译器中 walkIdentifiers 源码深度解析
前端
excel5 小时前
一文看懂 Vue 编译器里的插槽处理逻辑(buildSlots.ts)
前端
excel5 小时前
Vue 编译器源码解析:错误系统(errors.ts)
前端
余道各努力,千里自同风5 小时前
uni-app 请求封装
前端·uni-app
excel5 小时前
Vue 编译器核心 AST 类型系统与节点工厂函数详解
前端