Vue3编译过程分析

191 阅读1分钟

1.app.mount获取template

javascript
复制代码
    const { mount } = app;
    app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
        const container = normalizeContainer(containerOrSelector);
        if (!container) return;

        const component = app._component;
        if (
            !isFunction(component) &&
            !component.render &&
            !component.template
        ) {
            component.template = container.innerHTML;
            // 2.x compat check
            if (__COMPAT__ && __DEV__) {
              ...
             // 省略非核心流程
              ...
            }
        }

        // 这里获取template
        container.innerHTML = "";
        const proxy = mount(container, false, container instanceof SVGElement);
        if (container instanceof Element) {
            container.removeAttribute("v-cloak");
            container.setAttribute("data-v-app", "");
        }
        return proxy;
    };

    return app;

2.compile

compile将传入的template编译成render函数,其实执行的是baseCompile

javascript
复制代码
export function compile(
    template: string,
    options: CompilerOptions = {}
): CodegenResult {
  	// 其实执行的是baseCompile
    return baseCompile(
        template,
        extend({}, parserOptions, options, {
            nodeTransforms: [
                // ignore <script> and <tag>
                // this is not put inside DOMNodeTransforms because that list is used
                // by compiler-ssr to generate vnode fallback branches
                ignoreSideEffectTags,
                ...DOMNodeTransforms,
                ...(options.nodeTransforms || []),
            ],
            directiveTransforms: extend(
                {},
                DOMDirectiveTransforms,
                options.directiveTransforms || {}
            ),
            transformHoist: __BROWSER__ ? null : stringifyStatic,
        })
    );
}

3.通过parse获取AST

接着往下看baseCompile

javascript
复制代码
export function baseCompile(
  template: string | RootNode,
  options: CompilerOptions = {}
): CodegenResult {
	...
	// 获取AST
  const ast = isString(template) ? baseParse(template, options) : template
  const [nodeTransforms, directiveTransforms] =
    getBaseTransformPreset(prefixIdentifiers)
	...
}

4.transfom

解析AST中的属性,样式,指令等。完善抽象语法树

javascript
复制代码
export function baseCompile(
  template: string | RootNode,
  options: CompilerOptions = {}
): CodegenResult {
	...
	// 获取AST
  const ast = isString(template) ? baseParse(template, options) : template
  const [nodeTransforms, directiveTransforms] =
    getBaseTransformPreset(prefixIdentifiers)
  // 解析AST中的属性,样式,指令等。完善抽象语法树
  transform(
    ast,
    extend({}, options, {
      prefixIdentifiers,
      nodeTransforms: [
        ...nodeTransforms,
        ...(options.nodeTransforms || []) // user transforms
      ],
      directiveTransforms: extend(
        {},
        directiveTransforms,
        options.directiveTransforms || {} // user transforms
      )
    })
  )
  // 最后一步通过generate生成渲染函数
  return generate(
    ast,
    extend({}, options, {
      prefixIdentifiers
    })
  )
}

5.generate

最后一步通过generate生成渲染函数。我们在test.html中写的template最终被编译成了成了下边的渲染函数被返回。

javascript
复制代码
return function render(_ctx, _cache) {
  with (_ctx) {
    const { toDisplayString: _toDisplayString } = _Vue
    return _toDisplayString(msg)
  }
}

6.总结

整个编译过程概括就是template=>ast=>transform=>ast=>generate=>render。这次我们已经基本了解整个编译过程。

作者:胖茶夫斯基
链接:juejin.cn/post/704659…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。