文章地址:https://jaufey.notion.site/Static-hoisting-85e751cf04694a47a1b8d9f9f04cfb35
在 JS 中,有一个术语叫做 Hoisting,指在编译期将变量、函数、类的声明提升至作用域顶端。
本篇文章所讲的 Static hoisting 与 Hoisting 有一点相似,但相关性不大。Static hoisting 是 Vue3 在模板编译阶段的一种优化手段,恰好有一个提升的操作,所以名字中包含 hoisting,同时,Static 则表示 hoisting 的对象是静态的。
我是如何感知到 “静态提升” 的?答案是:某项目从 Vue2 升级到 Vue3 后,出现了 “副作用被 cache” 的问题。
$el.appendChild(circle)
,这算是框架内的 UB,只管拉不管擦的脏写。在线示例:https://demo-0814-test.vercel.app/
代码:https://github.com/N-index/demo-0814
经过排查与请教,发现是 “静态提升” 这个构建期的优化手段导致了这个问题。
解决方案为以下任意一种:
在构建阶段,关闭静态提升的功能: https://github.com/vuejs/core/issues/5256#issuecomment-1173723516
在副作用的父容器上添加 ref 属性,使得静态提升越过这个静态节点。
具体参考:ref 和 key 的编译示例
一句话描述 “静态提升” :在模板编译阶段生成渲染函数的过程中,对于静态内容,Vue 将其对应的 vnode 结果 hoist 到了渲染函数外部,而不是每次都渲染都重新生成 vnode。(示例:编译期间的静态提升)
Vue3 基于这样一个假设,才有了这个优化策略: 静态内容不会被改动,每次都会渲染出一样的 DOM,所以直接缓存起来就可以了。