The announcement of Vue 3.5 includes exciting features with new performance optimizations and improvements. This version introduces innovations such as reactivity system enhancements, SSR (Server-Side Rendering) improvements, and new features like custom elements and deferred teleport. Let's take a detailed look at the key features of Vue 3.5 with examples:
1. Reactivity System Enhancements
The performance updates made to the reactivity system in Vue 3.5 deliver significant speed improvements, especially for large data sets.
With optimizations in Vue’s reactivity structure, better memory usage (around 56% savings) and faster reactive processes are achieved. This results in up to a 10x speed increase, particularly in handling large data sets.
This example allows for faster response times when updating complex data lists or tracking computed values.
<script setup>
import { reactive, computed } from 'vue';
const state = reactive({
items: Array.from({ length: 10000 }, (_, i) => ({ id: i, value: Math.random() }))
});
const totalValue = computed(() => {
return state.items.reduce((sum, item) => sum + item.value, 0);
});
</script>
<template>
<p>Total Value: {{ totalValue }}</p>
</template>
In the example, if you have a list of 10,000 items, you'll observe a faster computation and update process with Vue 3.5.
2. Reactive Props Destructure
In Vue 3.5, defining prop variables reactively with defineProps
has become much more streamlined. Now, default values can be assigned to props using JavaScript’s built-in features.
This allows us to assign default values to props with a cleaner syntax.
<script setup>
const { count = 0, msg = 'hello' } = defineProps<{
count?: number;
msg?: string;
}>();
</script>
<template>
<p>Count: {{ count }}</p>
<p>Message: {{ msg }}</p>
</template>
This usage allows default values to be assigned to the count
and msg
variables without needing helper functions like withDefaults
.
3. SSR Improvements
Vue 3.5 introduces features like Lazy Hydration for Server-Side Rendering (SSR). This enables you to create components that load only when visible to the user.
Additionally, APIs like useId()
generate unique IDs that ensure client-server matching, and the data-allow-mismatch
attribute prevents error warnings for non-matching client data.
a. Lazy Hydration
With Lazy Hydration, support is provided for components that load only when they become visible.
import { defineAsyncComponent, hydrateOnVisible } from 'vue';
const LazyComponent = defineAsyncComponent({
loader: () => import('./MyComponent.vue'),
hydrate: hydrateOnVisible()
});
This feature improves performance by loading components only when displayed, instead of loading the entire page.
b. useId()
useId()
creates unique IDs across components in Vue, ensuring consistency on both the client and server sides. This is crucial when IDs are needed, such as for form elements or accessibility purposes.
For instance, if you need a unique ID for each input field in a form, you can dynamically generate these IDs using useId()
.
<script setup>
import { useId } from 'vue';
const id = useId(); // Generates a unique and consistent ID
</script>
<template>
<form>
<label :for="id">Name:</label>
<input :id="id" type="text" />
</form>
</template>
c. data-allow-mismatch
data-allow-mismatch
prevents unnecessary warnings in the client console when data on the server and client sides may naturally mismatch. For example, when using dynamic data like date or time, slight differences might occur between the client and server. This feature suppresses warnings, providing a cleaner experience for the user.
<template>
<span data-allow-mismatch="text">{{ new Date().toLocaleString() }}</span>
</template>
In this example, using data-allow-mismatch="text"
enables the display of date and time. data-allow-mismatch
prevents data differences between the client and server from being perceived as errors and only suppresses mismatches of type "text." Additionally, specific values like text
, children
, class
, style
, and attribute
can be used for data-allow-mismatch
.
4. Custom Elements Enhancements
The defineCustomElement
API provides more options for creating custom HTML elements even without Shadow DOM. New APIs like useHost()
and useShadowRoot()
also allow access to the shadow root.
a. Accessing Element and Shadow Root with useHost
and useShadowRoot
With Vue 3.5’s useHost
and useShadowRoot
APIs, you can access and manage the properties of your custom component via the shadow root.
import { defineCustomElement, useHost, useShadowRoot } from 'vue';
export default defineCustomElement({
setup() {
const host = useHost(); // Access to the main root of the element
const shadowRoot = useShadowRoot(); // Access to the Shadow DOM root
// Custom operations can be performed using the shadow root
return { host, shadowRoot };
}
});
With these features, you can manage specific operations tied to the custom element via host
or shadowRoot
, allowing the component to run smoothly even in systems outside of Vue.
b. Creating a Basic Custom Element with defineCustomElement
In Vue, you can use the defineCustomElement
API to register a component as a custom HTML element. For example, let’s create a component called “CustomButton”:
// CustomButton.ce.vue
<script setup>
const handleClick = () => {
alert('Button clicked!');
};
</script>
<template>
<button @click="handleClick">Click Me!</button>
</template>
Let's define our component as a custom element using defineCustomElement
:
// main.js
import { defineCustomElement } from 'vue';
import CustomButton from './CustomButton.ce.vue';
const CustomButtonElement = defineCustomElement(CustomButton);
customElements.define('custom-button', CustomButtonElement);
In this example, the CustomButton
component becomes usable with the <custom-button>
tag. This custom element can now be integrated into another application and function as an independent component.
c. Using Shadow DOM
In Vue 3.5, you can add an option within defineCustomElement
to enable or disable the Shadow DOM. The Shadow DOM encapsulates the component’s styles and DOM structure, preventing conflicts with other styles.
With these features, you can create custom HTML elements in Vue and enable broad usage without requiring the Shadow DOM.
import { defineCustomElement } from 'vue';
import CustomButton from './CustomButton.ce.vue';
const CustomButtonElement = defineCustomElement(CustomButton, { shadow: true });
customElements.define('custom-shadow-button', CustomButtonElement);
In this example, the shadow: true
setting allows the component to operate within the Shadow DOM. To disable the Shadow DOM, you can set it to shadow: false
.
5. useTemplateRef()
Vue 3.5 introduces the useTemplateRef()
API, allowing you to define dynamic references easily. With this feature, you can manage refs based on variable IDs rather than being static.
<script setup>
import { useTemplateRef } from 'vue';
const inputRef = useTemplateRef('input');
</script>
<template>
<input ref="input">
</template>
useTemplateRef
provides easier usage for elements with dynamically changing IDs.
6. Deferred Teleport
In Vue 3.5, the defer
attribute added to the <Teleport>
component allows content to move before the DOM is fully ready. This is especially useful for transferring late-loading content to target elements within Vue.
<Teleport defer to="#target">
<div>Content teleported to #target after mount</div>
</Teleport>
<div id="target"></div>
This example demonstrates that you can transfer content even when the target element is not yet present in the DOM.
7. onWatcherCleanup()
With Vue 3.5, onWatcherCleanup()
more effectively manages cleanup operations within watchers.
import { watch, onWatcherCleanup } from 'vue';
watch(id, (newId) => {
const controller = new AbortController();
fetch(`/api/${newId}`, { signal: controller.signal });
onWatcherCleanup(() => {
controller.abort(); // Stops the operation when the watcher is stopped
});
});
In this example, onWatcherCleanup
prevents unnecessary network traffic by canceling outdated requests.
These are the highlighted features in the Vue 3.5 announcement. For more details and additional examples, you can check out the official blog post.
Happy coding! 🚀