The design goals of Vue 3.0
can be summarized as smaller size, faster speed, enhanced TypeScript
support, improved API
design consistency, increased maintainability, and more open underlying features.
A detailed comparison of some important aspects from Vue 2
to Vue 3
.
Vue 2 -> Vue 3
beforeCreate -> setup
created -> setup
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
renderTracked -> onRenderTracked
renderTriggered -> onRenderTriggered
The main change here is the addition of the setup
lifecycle, while the other lifecycles are called in the form of API
. In fact, with the introduction of the Composition API
, the way we access these hooks has changed. All of our lifecycles should be written in setup
, which should be implemented in most component codes and handle reactivity and lifecycle hook functions.
Vue 2
achieves reactivity through data interception, with the core method being Object.defineProperty()
to intercept properties. This method allows precise addition or modification of object properties using property descriptors with getter
and setter
access descriptors to achieve interception. The reason why Vue 2
can only be compatible with IE8
is mainly because defineProperty
is not compatible with IE8
, and there are also slight compatibility issues with other browsers.
Vue3
uses Proxy
to achieve data interception. Object.defineProperty
can only monitor properties, while Proxy
can monitor the entire object. By calling new Proxy()
, a proxy can be created to replace another object known as the target. This proxy virtually represents the target object, so the proxy and the target object can be treated as the same object. The proxy allows intercepting low-level operations on the target object, which was originally an internal capability of the JavaScript engine. The interception behavior uses a function that can respond to specific operations. After a object is proxied through Proxy
, we will have an object that is almost identical to the original object. We can fully monitor this object at a low level. The Proxy
object is a new feature introduced in ES6. Vue3
has abandoned the use of Object.defineProperty
in favor of the faster native Proxy
, which leans more towards modern browsers in terms of compatibility.
The foundation of the diff
algorithm is the Virtual DOM
. The Virtual DOM
is a tree based on JavaScript objects, with each node called a VNode
, using object properties to describe the nodes. In practice, it is an abstraction of the real DOM, which can ultimately be rendered to the real environment through rendering operations. In simple terms, the Virtual DOM
is a JavaScript object used to describe the entire document.
In Vue2
, the framework traverses the new and old virtual DOM trees through deep recursion and compares each attribute on each node to determine which parts of the actual DOM need to be updated. Due to advanced optimizations performed by modern JavaScript engines, this somewhat brute force algorithm is usually very fast. However, DOM updates still involve many unnecessary CPU work.
In the words of Evan You, in order to achieve this, the compiler and runtime need to work together: the compiler analyzes the template and generates code with optimization hints, and the runtime tries to obtain these hints as much as possible and adopts the fast path. There are three main optimizations here:
v-if
and v-for
), the node structure remains completely static. If we divide a template into nested blocks separated by these structural directives, the node structure in each block will once again be completely static. When we update nodes in a block, we no longer need to recursively traverse the DOM tree. Dynamic bindings within the block can be tracked in a flat array. This optimization reduces the amount of tree traversal needed by an order of magnitude, thus mitigating much of the overhead of the virtual DOM.In Vue2
, only JavaScript is used, and it does not have the concept of a type system. Nowadays, TypeScript
is extremely popular. For large-scale projects, the lack of type declarations makes maintenance and code reading a headache. Although it is actually possible to use TS
in Vue2
, the support is not particularly perfect. Additionally, Vue2
's source code also uses Facebook
's Flow
for type checking.
Ultimately, Vue3
drew inspiration from React Hook
to create a more flexible programming style, and introduced the Composition API
, which does not require defining components through a long list of options, but allows users to freely express, combine, and reuse stateful component logic just like writing functions, while providing excellent TypeScript support.
The official documentation of Vue2
stated that the runtime package was 23k
, but that was only when there were no dependencies installed. As more dependencies and framework features were added, sometimes unnecessary and unused code files were still being included in the package. Therefore, as the project grew larger, the packaged files would become numerous and large.
In Vue3
, this was addressed by moving most of the global API
and internal helpers to the module.exports
property in JavaScript
. This allowed modern mode module bundlers
to statically analyze module dependencies and remove code related to unused module.exports
properties. The template compiler also generated code optimized for Tree Shaking
, meaning that helper functions for a feature were only imported when the feature was actually used in the template. Despite the addition of many new features, the baseline size of compressed Vue3
was approximately 10KB
, which was less than half the size of Vue2
.
The non-compatible changes in Vue3
compared to Vue2
can be summarized, for details please refer to Vue 3 Migration Guide.
Vue API
has been changed to use the application instance.API
have been refactored to be tree-shakable
.v-model
on components has been changed to replace v-bind.sync
.key
on <template v-for>
and non-v-for
nodes has been changed.v-if
and v-for
used on the same element has been changed.v-bind="object"
is now order-sensitive.v-on:event.native
modifier has been removed.ref
in v-for
no longer registers a ref
array.functional
attribute in SFC single-file components <template>
and functional
component options has been deprecated.defineAsyncComponent
method for creation.emits
option.$scopedSlots property
has been removed, and all slots are exposed as functions through $slots
.$listeners
have been removed or integrated into $attrs
.$attrs
now includes class and style attribute
.is prop
are now limited to the reserved <component>
tag.destroyed
lifecycle option has been renamed to unmounted
.beforeDestroy
lifecycle option has been renamed to beforeUnmount
.default prop
factory function can no longer access the this
context.API
has been changed to be consistent with component lifecycle.data
option should always be declared as a function.data
options from mixins are now shallow merged.Attribute
coercion strategy has been changed.class
have been renamed.<TransitionGroup>
no longer defaults to rendering the wrapping element.deep
option needs to be specified.v-if/else-if/else
, v-for
, v-slot
on <template>
are now treated as normal elements and will generate native <template>
elements, rather than rendering their internal content.Vue2
, the outerHTML
of the root container of the application will be replaced by the root component's template. If the root component does not have a template/render option, it will ultimately compile into a template. In Vue3
, the innerHTML
of the application container is now used, which means the container itself is no longer considered part of the template.keyCode
support as a modifier for v-on
.$on
, $off
, and $once
instance methods.attribute
.$children
instance property
.$destroy
instance method, users should no longer manually manage the lifecycle of individual Vue
components.A simple example of a Vue3
component can be viewed in the online example at CodeSandbox.