vue 编译

vue-loader 的编译过程

输入是一个 vue 单文件,最终输出的结果是可以被直接执行的 js 代码。

细化一下这中间的步骤,vue-loadervue 文件编译到输出 bundle.js 的过程主要是调用了下面的四个小 loader, 它们分别是:

  1. selector
  2. style-compiler
  3. template-compiler
  4. babel-loader

以上四个 loader,除了 babel-loader 是外部的 package,其他三个都存在于 vue-loader 的内部

1. JS 部分

首先分析 script 部分

/* script */
import __vue_script__ from "!!babel-loader!../../lib/selector?type=script&index=0&bustCache!./basic.vue";

从做右到左,也就是 basic.vue 被先后被 selectorbabel-loader 处理过了。

selector(参数 type=script) 的处理结果是将 basic.vue 中的 javaScript 抽出来之后交给 babel-loader去处理,最后生成可用的 javaScript

2. Template

再来分析 template 部分

/* template */
import __vue_template__ from '!!../../lib/template-compiler/index?{"id":"data-v-793be54c","hasScoped":false,"buble":{"transforms":{}}}!../../lib/selector?type=template&index=0&bustCache!./basic.vue';

同样的,从左到右,basic.vue 先后被 selectortemplate-compiler 处理过了。 selector (参数 type=template) 的处理结果是将 basic.vue 中的 template 抽出来之后交给 template-compiler 处理,最终输出成可用的 HTML。

3. Style 部分

/* styles */
import __vue_styles__ from '!!vue-style-loader!css-loader!../../lib/style-compiler/index?{"vue":true,"id":"data-v-793be54c","scoped":false,"hasInlineConfig":false}!../../lib/selector?type=styles&index=0&bustCache!./basic.vue';

style 涉及的 loader 较多,一个一个来分析, 从上代码可知,basic.vue 先后要被 selector, style-compiler, css-loader 以及 vue-style-loader 处理。 selector (参数 type=style) 的处理结果是将 basic.vue 中的 css 抽出来之后交给 style-compiler 处理成 css, 然后交给 css-loader 处理生成 module, 最后通过 vue-style-loader 将 css 放在 <style> 里面,然后注入到 HTML 里。

vue 模板编译过程

在使用 Vue 开发的过程中,基本都是使用模板的方式。Vue 会通过编译器将模板通过几个阶段最终编译为 render 函数,然后通过执行 render 函数生成 Virtual DOM 最终映射为真实 DOM。

这个过程又分为三个阶段,分别为:

  1. parse 过程: 将 template 利用正则转化成 AST 抽象语法树。
  2. optimize 过程: 优化 AST,标记静态节点,后 diff 过程跳过静态节点,提升性能。
  3. generate 过程: 将 AST 转换为 render 函数

在第一个阶段中,最主要的事情还是通过各种各样的正则表达式去匹配模板中的内容,然后将内容提取出来做各种逻辑操作,接下来会生成一个最基本的 AST 对象

{
    // 类型
    type: 1,
    // 标签
    tag,
    // 属性列表
    attrsList: attrs,
    // 属性映射
    attrsMap: makeAttrsMap(attrs),
    // 父节点
    parent,
    // 子节点
    children: []
}

然后会根据这个最基本的 AST 对象中的属性,进一步扩展 AST。

当然在这一阶段中,还会进行其他的一些判断逻辑。比如说对比前后开闭标签是否一致,判断根组件是否只存在一个,判断是否符合 HTML5 规范等等问题。

接下来就是优化 AST 的阶段。在当前版本下,Vue 进行的优化内容其实还是不多的。只是对节点进行了静态内容提取,也就是将永远不会变动的节点提取了出来,实现复用 Virtual DOM,跳过对比算法的功能。在下一个大版本中,Vue 会在优化 AST 的阶段继续发力,实现更多的优化功能,尽可能的在编译阶段压榨更多的性能,比如说提取静态的属性等等优化行为。

最后一个阶段就是通过 AST 生成 render 函数了。其实这一阶段虽然分支有很多,但是最主要的目的就是遍历整个 AST,根据不同的条件生成不同的代码罢了。

Last Updated:
Contributors: yiliang114