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 3beforeCreate -> setupcreated -> setupbeforeMount -> onBeforeMountmounted -> onMountedbeforeUpdate -> onBeforeUpdateupdated -> onUpdatedbeforeDestroy -> onBeforeUnmountdestroyed -> onUnmountedactivated -> onActivateddeactivated -> onDeactivatederrorCaptured -> onErrorCapturedrenderTracked -> onRenderTrackedrenderTriggered -> onRenderTriggeredThe 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.