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>

打印出渲染函数render

  1. 静态缓存:_hoisted_1
    vue3 compiler principle
    给缓存起来,因为不需要处理
  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 */))
  }
}
})

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)
let compile
function registerRuntimeCompiler(_compile) {
  compile = _compile // 在这里把compileToFunction 存到 compile
  installWithProxy = i => {
    if (i.render!._rc) {
      i.withProxy = new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers)
    }
  }
}
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)
}

执行compile就是执行备份的compileToFunction

function finishComponentSetup(
  instance,
  isSSR,
  skipOptions
) {
	Component.render = compile(template, finalCompilerOptions)
}

5.编译器是如何运行的

  1. parse: 解析template为AST
  2. transform:AST => AST
  3. generate:AST转换为render函数
function compileToFunction(template,options) {
  const { code } = compile( template )
}
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
    })
  )
}

你可能感兴趣的:(vue3相关文档,javascript,webpack,前端)