模板转换 render function

function compileToFunction(
  template: string | HTMLElement,
  options?: CompilerOptions
): RenderFunction {
  // ...

  // 编译模板,生成代码
  const { code } = compile(
    template,
    extend(
      {
        hoistStatic: true,
        onError: __DEV__ ? onError : undefined,
        onWarn: __DEV__ ? e => onError(e, true) : NOOP
      } as CompilerOptions,
      options
    )
  )

  function onError(err: CompilerError, asWarning = false) {
    const message = asWarning
      ? err.message
      : `Template compilation error: ${err.message}`
    const codeFrame =
      err.loc &&
      generateCodeFrame(
        template as string,
        err.loc.start.offset,
        err.loc.end.offset
      )
    warn(codeFrame ? `${message}\n${codeFrame}` : message)
  }

  // The wildcard import results in a huge object with every export
  // with keys that cannot be mangled, and can be quite heavy size-wise.
  // In the global build we know `Vue` is available globally so we can avoid
  // the wildcard object.
  // 生成的代码通过new Function进行包装
  const render = (__GLOBAL__
    ? new Function(code)()
    : new Function('Vue', code)(runtimeDom)) as RenderFunction

  // mark the function as runtime compiled 标记为运行时已编译
  ;(render as InternalRenderFunction)._rc = true

  return (compileCache[key] = render)
}

总结

可以看到最后对生成的代码通过new Function去做了一层包装,并返回了出去,简单看下最终生成的代码:

(function anonymous() {
  const _Vue = Vue
  const { createVNode: _createVNode } = _Vue

  const _hoisted_1 = /*#__PURE__*/_createVNode("div", { id: "suspense" }, "supense组件", -1 /* HOISTED */)
  const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "telport组件", -1 /* HOISTED */)

  return function render(_ctx, _cache) {
    with (_ctx) {
      const {
        toDisplayString as _toDisplayString,
        createVNode as _createVNode,
        vModelText as _vModelText,
        withDirectives as _withDirectives,
        resolveComponent as _resolveComponent,
        renderList as _renderList,
        Fragment as _Fragment,
        openBlock as _openBlock,
        createBlock as _createBlock,
        Suspense as _Suspense,
        withCtx as _withCtx,
        Teleport as _Teleport
      } = _Vue

      const _component_test = _resolveComponent("test")

      return (
        _openBlock(), 
        _createBlock(_Fragment, null, [
          _createVNode("span", {
            class: count % 2 === 0 ? 'red' : 'blue',
            style: 'font-size: 14px; font-weight: bold;'
          }, _toDisplayString(count), 7 /* TEXT, CLASS, STYLE */),
          _withDirectives(_createVNode("input", {
            ref: "inputRef",
            "onUpdate:modelValue": $event => (inputVal = $event)
          }, null, 8 /* PROPS */, ["onUpdate:modelValue"]), [
            [_vModelText, inputVal]
          ]),
          _createVNode("button", {
            onClick: add,
            style: {
                color: 'red'
            }
          }, "增加", 12 /* STYLE, PROPS */, ["onClick"]),
          _createVNode(_component_test, { count: count }, null, 8 /* PROPS */, ["count"]),
          _createVNode("ul", null, [
            (
              _openBlock(true), 
              _createBlock(_Fragment, null, 
              _renderList(10, (item) => {
                // v-for生成的代码
                return (_openBlock(), _createBlock("li", null, _toDisplayString(item), 1 /* TEXT */))
              }), 256 /* UNKEYED_FRAGMENT */))
          ]),
          (_openBlock(), _createBlock(_Suspense, null, {
            default: _withCtx(() => [
              _hoisted_1
            ]),
            _: 1 /* STABLE */
          })),
          (_openBlock(), _createBlock(_Teleport, { to: "body #suspense" }, [
            _hoisted_2
          ])
        )
      ], 64 /* STABLE_FRAGMENT */))
    }
  }
})