• vue3编译器原理


    1.执行代码

    <script src="../../dist/vue.global.js"></script>
    <div id="app">
      <div>vue3 compiler principle</div>
      <div>{{count}}</div>
    </div>
    <script>
      var { createApp } = Vue
      var app = createApp({
        data() {
          return {
            count: 1
          }
        }
      })
      app.mount('#app')
      console.log(app._instance.render);
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    打印出渲染函数render

    1. 静态缓存:_hoisted_1<div>vue3 compiler principle</div>给缓存起来,因为不需要处理
    2. sfc playground
    (function anonymous(
    ) {
    const _Vue = Vue
    const { createElementVNode: _createElementVNode } = _Vue
    
    const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, "vue3 compiler principle", -1 /* HOISTED */)
    
    return function render(_ctx, _cache) {
      with (_ctx) {
        const { createElementVNode: _createElementVNode, toDisplayString: _toDisplayString, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
    
        return (_openBlock(), _createElementBlock(_Fragment, null, [
          _hoisted_1,
          _createElementVNode("div", null, _toDisplayString(count), 1 /* TEXT */)
        ], 64 /* STABLE_FRAGMENT */))
      }
    }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.vue为什么需要编译器

    1. 编译器是将一门语言转换另一门语言
    2. vue是声明式渲染
    3. 编译器会将template编译为render函数( js )
    4. 前端程序员,更加喜欢用html描述视图,开发效率高
    5. 性能优化
      1. 静态分析

    3.vue template 和 react jsx异同?

    1. 异曲同工
      1. 都是为了生成虚拟dom
      2. js、jsx、ts、tsx
      3. 提高前端程序员视图开发效率
      4. jsx:babel转换工具将create函数的调用,最后转换为vdom
      5. template:compile编译模板后生成render函数,在未来某个时间执行生成vdom
    2. 执行时刻
      1. vue
        1. 预编译(版本 和 执行环境) :webpack sfc vue-loader
        2. 运行时(global,browser):template选项,挂载阶段
      2. react
      3. 转译transpile
    3. 性能优化:vue3执行编译期优化,可以静态分析

    4.编译器执行时刻

    1. 预编译:vue版本esm结合打包工具webpack等,结合sfc
    2. 运行时编译
      1. vue版本global、esm-browser、挂载时编译
      2. vue/src/index.ts 的 compileToFunction
      3. 在执行setupComponent
      4. 会执行finishComponentSetup
      5. 进一步会触发compile
      6. 也就是执行了compileToFunction

    最开始备份compileToFunction

    registerRuntimeCompiler(compileToFunction)
    
    • 1
    let compile
    function registerRuntimeCompiler(_compile) {
      compile = _compile // 在这里把compileToFunction 存到 compile
      installWithProxy = i => {
        if (i.render!._rc) {
          i.withProxy = new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers)
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    function compileToFunction(
      template
      options
    ) {
      if (!isString(template)) { // 这种的是 用户直接传入节点
        if (template.nodeType) {
          template = template.innerHTML
        } else {
          return NOOP
        }
      }
      const key = template
      const cached = compileCache[key]
      if (cached) {
        return cached
      }
      if (template[0] === '#') {
        const el = document.querySelector(template)
        template = el ? el.innerHTML : ``
      }
      const { code } = compile( // 把模板给编译一下
        template,
        extend(
          {
            hoistStatic: true
          options
        )
      )
      const render = ( // 使用new 转换上面的code为一个函数
        __GLOBAL__ ? new Function(code)() : new Function('Vue', code)(runtimeDom)
      )
      render._rc = true
      return (compileCache[key] = render)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    执行compile就是执行备份的compileToFunction

    function finishComponentSetup(
      instance,
      isSSR,
      skipOptions
    ) {
    	Component.render = compile(template, finalCompilerOptions)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.编译器是如何运行的

    1. parse: 解析template为AST
    2. transform:AST => AST
    3. generate:AST转换为render函数
    function compileToFunction(template,options) {
      const { code } = compile( template )
    }
    
    • 1
    • 2
    • 3
    export function compile(
      template: string,
      options: CompilerOptions = {}
    ): CodegenResult {
      return baseCompile(
        template,
        extend({}, parserOptions, options, {
          nodeTransforms: [
            ignoreSideEffectTags,
            ...DOMNodeTransforms,
            ...(options.nodeTransforms || [])
          ],
          directiveTransforms: extend(
            {},
            DOMDirectiveTransforms,
            options.directiveTransforms || {}
          ),
          transformHoist: __BROWSER__ ? null : stringifyStatic
        })
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    浅析Linux进程间通信方式之磁盘映射(mmap)
    BioVendor sRAGE抗体解决方案
    完美解决-RuntimeError: CUDA error: device-side assert triggered
    Bug记录:【com.fasterxml.jackson.databind.exc.InvalidDefinitionException】
    js函数变量提升理解
    01_Cookie&WebStorage
    【MicroPython ESP32】machine.Pin类函数以及参数详解
    想考【软考高级】,但不具备计算机基础?“系规”适合你
    Win10禁止应用独占麦克风
    Vue 官方文档2.x教程学习笔记 1 基础 1.7 条件渲染
  • 原文地址:https://blog.csdn.net/formylovetm/article/details/125404236