Vue源码解析,深入剖析vue源码

  Vue源码解析,深入剖析vue源码

  今天,我们将从Vue的入口文件开始,看看声明Vue的单个文件是如何被编译核心模块编译成渲染函数的。下面小编讲解并附上代码分析在文章中展示。感兴趣的朋友不要错过奥地利。

  前言:

  Vue3发布很久了。最近我也有机会在公司的项目中使用Vue3 TypeScript Vite的技术栈,所以我在业余时间抽空看了一下Vue3的源代码。本着好记性胜过烂文笔的想法,我在看源代码的时候记录了一些笔记。也希望能争取写一些源代码的读书笔记,帮助每一个想读源代码但可能有困难的同学降低理解成本。

  我也对Vue2.x的源代码进行了一些简单的阅读自从Vue3重构之后,Vue项目的目录结构发生了很大的变化。每个功能模块都放入了packages目录中,职责更加明确,通过目录名一目了然。今天,我们将从Vue的入口文件开始,看看声明Vue的单个文件是如何被编译核心模块编译成渲染函数的。

  为了方便大家阅读,也为了控制文章长度,我会在阅读源代码的时候把不需要关心的逻辑折叠起来,或者通过注释/*忽略逻辑*/来忽略。

  我个人不喜欢在看源代码分析文章的时候拿出一大段代码,容易让没看过的同学有点迷茫。所以在这一系列文章中,我会尽力画出关键代码的流程图。目的是帮助你降低理解成本,同时让学生在接下来的自主阅读中有一个可供参考的流程图。

  

1、解读Vue 入口文件

  我们将从一个Vue对象的入口开始我们的源码读取,packages/vue/index.ts,这个入口文件的代码比较简单,只有一个compileToFunction函数,但是函数体中的内容比较关键,所以先看一张图了解一下函数体完成了什么。

  看完流程图,我们一起来看代码。相信大部分同学此时可能已经对分发图中的代码有了清晰的概念。

  直接跳过所有代码,看文件的最后35行,调用registerRuntiomcompiler函数,将compileToFunction函数作为参数传入。这行代码对应流程图的开头,通过依赖注入的方式将编译函数注入到运行时。依赖注入是一种聪明的解耦方法。此时在运行时调用编译函数就是调用当前的compileToFunction。

  看代码中的第17行,调用compile-dom库提供的编译函数,从返回值中解构代码变量。是编译器执行后生成的编译结果,code是编译结果的参数之一,是一个代码串。例如

  模板

  差异

  你好世界

  /div

  /模板

  这个简单的模板,在经过编译后,code 返回的字符串为

  const _Vue=Vue返回函数render(_ctx,_ cache){ with(_ CTX){ const { open block:_openBlock,createBlock: _createBlock }=_Vue返回(_ open block(),_createBlock(div ,null, Hello World )} }

  后面我会详细解释这个神奇的编译功能的内在秘密。

  得到这个代码串的结果后,我们再往下看代码。第25行声明了一个呈现变量,并将生成的代码字符串code作为参数传递给新的函数构造函数。这是流程图的倒数第二步,生成渲染函数。你可以把我放在上面的代码串格式化,可以发现render函数是一个科林斯函数,它返回一个函数,函数内部用with扩展了作用域链。

  最后,导入文件返回渲染变量,并方便地缓存渲染函数。

  在源代码的第一行,我们看到导入文件创建了一个compileCache对象来缓存compileToFunction函数生成的渲染函数。模板参数作为缓存的键,在第11行的位置有一个if分支来判断缓存。如果模板之前已经缓存了,就不编译了,直接返回缓存中的render函数,这样可以提高性能。

  至此,package/vue/index.ts的入口文件已经解释完毕。相信大家都能看到,最有趣的部分是调用编译函数来编译代码串,所以接下来我会继续说编译函数。编译函数包括两个模块,编译域和编译核心。在本文中,我将只解释关键过程。细节分析的话会放在后续文章里。让我们来看看compile的运行过程:

  

2、compile 的运行流程

  compile函数直接返回baseCompile函数的结果,baseCompile函数在执行过程中生成AST抽象语法树,调用transform处理每个AST节点,如转换vOn、v-if、v-for等指令。最后,经过处理的AST抽象语法树通过generate函数生成前面提到的代码串,并返回编译结果。至此,编译功能完成。了解了大致流程后,我们再来看源代码。

  Compile函数的源代码路径是packages/compiler-DOM/src/index . ts,我们可以看到baseCompile的处理结果直接在compile的函数体中返回。而baseCompile的源路径是packages/compiler-core/src/compile . ts.为什么会有baseCompile这样的名字?因为compile-core是编译的核心模块,它接受外部参数按照规则完成编译,而compile-dom则专用于浏览器场景下的编译。该模块下导出的编译函数是导入文件实际接收的编译函数。compile-dom中的compile函数也是比baseCompile更高阶的编译器。例如,当Vue在weex中的iOS或Android等原生App中工作时,compile-dom可能会被相关的移动编译器库所取代。

  顺着往下一起看一下 baseCompile 函数:

  从函数声明上看,baseCompile接收上级高级编译器处理模板template和option编译选项,最终返回CodegenResult类型的编译结果。

  导出接口代码生成结果{

  代码:字符串

  序言:字符串

  ast:根节点

  地图?原始源地图

  }

  通过CodegenResult的接口声明,可以清楚的看到返回的结果中有代码串,有处理过的AST抽象语法树,有sourceMap。

  看上面源代码的第12行,判断模板template是不是字符串。如果是,将解析字符串,否则,模板将直接用作AST。其实我们平时写的单文件vue代码都是以字符串的形式传入的。

  接下来源代码调用16行的transform函数,引入指令转换、节点转换等工具函数来转换模板生成的AST。

  在最后的32行位置,我们将转换后的AST传递给generate,以生成CodegenResult类型的返回结果。

  在编译核心模块中,AST解析、transform、codegen、compile和parse都是单一的小模块,其内部实现非常微妙。在编译器的后续文章中,会一一介绍。

  本文从入口文件解释编译的一般过程,希望能帮助你在阅读编译器这个模块的代码时对过程有一个清晰的概念,有了流程图吃起来更美味。

  关于Vue3编译过程的这篇文章到此为止——源代码分析。有关Vue3编译过程的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: