coverPiccoverPic

Vue 模板编译总览(v2)

前言

使用 Vue 的时候,我们会用<template>...<template>来编写组件的 HTML 结构,<template>...<template>模板中的字符串会被编译成虚拟 DOM。

graph LR
A[template 模板] --> B[虚拟 DOM]

Vue 有 2 个版本,一个是运行时 vue.runtime.min.js,可以创建 Vue 实例、渲染并处理虚拟 DOM,但是不能编译模板,另一个版本是完整版 vue.min.js,包含编译模板的功能。日常基于 Webpack、Vite 等的开发用到的都是运行时版本,模板编译是由相应的插件进行的。下面基于完整版的 Vue,调试 Vue 源码(见另一篇博客:调试 Vue 源码),看看总体的流程。

流程总览

举个栗子:

html
  1. <script src="../../dist/vue.js"></script>
  2. <div id="demo"></div>
  3. <script type="text/x-template" id="template">
  4. <div>
  5. <div v-for="(item, index) in arr" @click="clickHandler">
  6. Current Value is {{ item }}
  7. </div>
  8. </div>
  9. </script>
  10. <script>
  11. const { ref } = Vue
  12. new Vue({
  13. name: 'Test',
  14. template: '#template',
  15. setup(props) {
  16. const arr = ref([1, 1, 4, 5, 1, 4])
  17. const clickHandler = () => {}
  18. return {
  19. arr, clickHandler
  20. }
  21. }
  22. }).$mount('#demo')
  23. </script>

这里使用完整版的 Vue,调用$mount方法时就开始进行模板解析,整合了各种配置之后,调用baseCompile开始模板编译:

graph LR
Vue.prototype.$mount --> A[compileToFunctions]
createCompilerCreator\nargs:baseCompile --> createCompiler -->A

A --> baseCompile --> render

直接来看位于 /src/compiler/create-compiler.ts 的createCompilerCreator的核心代码:

ts
  1. export function createCompilerCreator(baseCompile: Function): Function {
  2. return function createCompiler(baseOptions: CompilerOptions) {
  3. function compile(
  4. template: string,
  5. options?: CompilerOptions
  6. ): CompiledResult {
  7. const finalOptions = Object.create(baseOptions)
  8. // ... 合并配置的操作
  9. const compiled = baseCompile(template.trim(), finalOptions)
  10. return compiled
  11. }
  12. return {
  13. compile,
  14. compileToFunctions: createCompileToFunctionFn(compile)
  15. }
  16. }
  17. }

template是传入的模板字符串,compiled就是编译完的内容,实际上调用了传入的baseCompile进行编译。createCompileToFunctionFn中,做的主要是执行compile函数编译模板,以及返回编译后的render函数。核心代码在于baseCompile,在
src/compiler/index.ts。

ts
  1. export const createCompiler = createCompilerCreator(function baseCompile(
  2. template: string,
  3. options: CompilerOptions
  4. ): CompiledResult {
  5. const ast = parse(template.trim(), options)
  6. if (options.optimize !== false) {
  7. optimize(ast, options)
  8. }
  9. const code = generate(ast, options)
  10. return {
  11. ast,
  12. render: code.render,
  13. staticRenderFns: code.staticRenderFns
  14. }
  15. })

parse负责把模板转化为ast抽象语法树,optimize对语法树进行优化(例如标记静态节点),generate则生成返回对应虚拟 DOM 的render函数。

也就是说,以下就是模板编译的大致流程:

graph LR
template模板-->parse-->optimize-->generate-->render-->a[虚拟 DOM]
0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run