本节主要内容
- 编译流程
- 静态提升
- patch流程
ps:再不写出来我就真的快忘了。。。
编译流程
1、app.mount里拿到template
// /packages/runtime-dom/src/index.ts
// 又回到最初的起点
export const createApp = ((...args) => {
const app = ensureRenderer().createApp(...args)
const { mount } = app
// 重写mount方法
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) {
// 在真实mount之前拿到template拿到template
component.template = container.innerHTML
}
// clear content before mounting
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
}) as CreateAppFunction<Element>
2、compileToFunction 编译template
// 这部分又可以拆分为三步:
export function baseCompile(
template: string | RootNode,
options: CompilerOptions = {}
): CodegenResult {
// I:将template解析为抽象语法树
const ast = isString(template) ? baseParse(template, options) : template
const [nodeTransforms, directiveTransforms] =
getBaseTransformPreset(prefixIdentifiers)
//xxxx
// II:对抽象语法树做深加工,方便各个平台打包成各自可用的版本
transform(
ast,
extend({}, options, {
prefixIdentifiers,
nodeTransforms: [
...nodeTransforms,
...(options.nodeTransforms || []) // user transforms
],
directiveTransforms: extend(
{},
directiveTransforms,
options.directiveTransforms || {} // user transforms
)
})
)
return generate(
ast,
extend({}, options, {
prefixIdentifiers
})
)
}
// III:将抽象语法树转换为render函数
const { code } = compile(template, opts) // compile方法就是一个baseCompile的高阶
const render = (
__GLOBAL__ ? new Function(code)() : new Function('Vue', code)(runtimeDom)
) as RenderFunction
那么是在什么编译的呢??
回到第一节我们写的初始化流程,setupComponent部分
setupComponent->setupStatefulComponent->handleSetupResult->finishComponentSetup->!!!compile
以上流程拿到最终编译参数后,去生成render函数
Component.render = compile(template, finalCompilerOptions)
静态提升
- 将静态节点缓存在render函数外面,之后不再重新创建
- 补丁标记和动态属性记录
- 缓存事件处理程序 onClick的属性被处理为箭头函数,缓存生成的箭头函数,之后渲染不会再重新创建箭头函数即不会再重新给属性复制。
- 块block
这里可以运行vue项目的命令:npm run dev-compiler, 这里可以直观的看到抽象语法树的结构,和vue做的静态提升的节点。
patch流程
patchFlags、shapeFlags