什么是静态提升
Vue3 尚未发布正式版本前,尤大在一次关于 Vue3 的分享中提及了静态提升,当时笔者就对这个亮点产生了好奇,所以在源码阅读时,静态提升也是笔者的一个重点阅读点。
那么什么是静态提升呢?当 Vue 的编译器在编译过程中,发现了一些不会变的节点或者属性,就会给这些节点打上标记。然后编译器在生成代码字符串的过程中,会发现这些静态的节点,并提升它们,将他们序列化成字符串,以此减少编译及渲染成本。有时可以跳过一整棵树。
<div>
<span class="foo">
Static
</span>
<span>
{
{ dynamic }}
</span>
</div>
例如这段模板代码,毫无疑问,我们能看出来 <span class="foo"> 这个节点,不论 dynamic 表达式如何变,它都不会再改变了。对于这样的节点,就可以打上标记进行静态提升。
而 Vue3 也可以对 props 属性进行静态提升。
<div id="foo" class="bar">
{
{ text }}
</div>
例如这段模板代码,Vue3 会跳过节点,仅仅将将不再会变动的 id="foo"
和 class="bar"
进行提升。
编译后的代码字符串
上面的例子我们只是简单的分析了一些模板,现在我们通过一个例子,来了解静态提升前后的变化。
<div>
<div>
<span class="foo"></span>
<span class="foo"></span>
<span class="foo"></span>
<span class="foo"></span>
<span class="foo"></span>
</div>
</div>
来看这样一个模板,符合静态提升的条件,但是如果没有静态提升的机制,它会被编译成如下代码:
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", null, [
_createVNode("div", null, [
_createVNode("span", { class: "foo" }),
_createVNode("span", { class: "foo" }),
_createVNode("span", { class: "foo" }),
_createVNode("span", { class: "foo" }),
_createVNode("span", { class: "foo" })
])
]))
}
编译后生成的 render 函数很清晰,是一个柯里化的函数,返回一个函数,创建一个根节点的 div,children 里有再创建一个 div 元素,最后在最里面的 div 节点里创建五个 span 子元素。
如果进行静态提升,那么它会被编译成这样:
const { createVNode: _createVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createBlock: _createBlock } = Vue
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<div><span class=\"foo\"></span><span class=\"foo\"><