### Configure Async Component Loader
Source: https://v3-migration.vuejs.org/breaking-changes/async-components
Example of the updated configuration object using the loader property.
```javascript
import { defineAsyncComponent } from 'vue'
const asyncModalWithOptions = defineAsyncComponent({
loader: () => import('./Modal.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
```
--------------------------------
### Vue 2 $attrs Example
Source: https://v3-migration.vuejs.org/breaking-changes/listeners-removed
An example of how attributes and listeners might be structured in Vue 2.
```js
{
text: 'this is an attribute',
onClose: () => console.log('close Event triggered')
}
```
--------------------------------
### Install Plugins with app.use()
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Vue 2's global Vue.use() is replaced by the app instance's use() method in Vue 3. Plugins must now be explicitly installed on the app instance.
```javascript
var inBrowser = typeof window !== 'undefined'
/* … */
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
}
```
```javascript
const app = createApp(MyApp)
app.use(VueRouter)
```
--------------------------------
### Vue 3 $attrs Example
Source: https://v3-migration.vuejs.org/breaking-changes/listeners-removed
An example of how attributes and listeners are structured in $attrs in Vue 3.
```js
{
id: 'my-input',
onClose: () => console.log('close Event triggered')
}
```
--------------------------------
### Create App Instance in Vue 3
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Basic example of creating a Vue 3 application instance using `createApp`.
```js
import { createApp } from 'vue'
const app = createApp({})
```
--------------------------------
### Attribute Binding Expressions
Source: https://v3-migration.vuejs.org/breaking-changes/attribute-coercion
Examples of v-bind expressions and their resulting HTML output for normal and enumerated attributes.
```html
:attr="null"
```
```html
:attr="undefined"
```
```html
:attr="true"
```
```html
:attr="false"
```
```html
:attr="0"
```
```html
attr=""
```
```html
attr="foo"
```
```html
attr
```
--------------------------------
### Register Global Component in Vue 2
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Example of registering a global component using `Vue.component` in Vue 2.
```js
Vue.component('button-counter', {
data: () => ({
count: 0
}),
template: ''
})
```
--------------------------------
### Parent listening for component events
Source: https://v3-migration.vuejs.org/breaking-changes/emits-option
Example of a parent component listening for a click event on a child component.
```html
```
--------------------------------
### Vue 3 Root Component Event Listener Setup
Source: https://v3-migration.vuejs.org/breaking-changes/events-api
In Vue 3, root component events can be listened to by passing them as props to `createApp`. This example shows how to listen for an 'expand' event.
```javascript
createApp(App, {
// Listen for the 'expand' event
onExpand() {
console.log('expand')
}
})
```
--------------------------------
### Create App Instance from CDN Build
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Example of creating a Vue 3 application instance when using a CDN build, accessing `createApp` from the global `Vue` object.
```js
const { createApp } = Vue
const app = createApp({})
```
--------------------------------
### Vue 2 Event Bus Implementation
Source: https://v3-migration.vuejs.org/breaking-changes/events-api
In Vue 2, a Vue instance could be used to create an event bus for global event listeners. This example shows the basic setup for an event bus.
```javascript
const eventBus = new Vue()
export default eventBus
```
--------------------------------
### Vue 2 transition-group syntax
Source: https://v3-migration.vuejs.org/breaking-changes/transition-group
Example of using the tag attribute to define a root element in Vue 2.
```html
{{ item }}
```
--------------------------------
### Vue 2 Filter Syntax Example
Source: https://v3-migration.vuejs.org/breaking-changes/filters
In Vue 2, filters were used for text formatting within templates. This example shows a currency filter applied to a balance.
```html
Bank Account Balance
{{ accountBalance | currencyUSD }}
```
--------------------------------
### Vue 2.x Conditional Rendering with Keys
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
In Vue 2.x, it was recommended to use `key`s on `v-if`/`v-else`/`v-else-if` branches. This example shows the Vue 2.x syntax.
```html
Yes
No
```
--------------------------------
### Vue 3 Event Bus with tiny-emitter
Source: https://v3-migration.vuejs.org/breaking-changes/events-api
This example demonstrates replacing the Vue 2 event bus with an external library like tiny-emitter in Vue 3. It provides the same event emitter API ($on, $off, $once, $emit).
```javascript
import emitter from 'tiny-emitter/instance'
export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args)
}
```
--------------------------------
### Vue 2.x Template Loop with v-if on Child and Keys
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
This example shows the Vue 2.x approach for template loops with a `v-if` on a child element, where keys were applied to the child elements.
```html
...
...
```
--------------------------------
### Vue 3 Custom Directive Usage
Source: https://v3-migration.vuejs.org/breaking-changes/custom-directives
Example of a custom directive in Vue 3 using the beforeMount hook.
```html
Highlight this text bright yellow
```
```js
const app = Vue.createApp({})
app.directive('highlight', {
beforeMount(el, binding, vnode) {
el.style.background = binding.value
}
})
```
--------------------------------
### 2.x Inline Template Syntax
Source: https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute
Example of the deprecated inline-template attribute usage in Vue 2.x.
```html
These are compiled as the component's own template.
Not parent's transclusion content.
```
--------------------------------
### Define Mixin Data Merge
Source: https://v3-migration.vuejs.org/breaking-changes/data-option
Example of component and mixin data structures that demonstrate shallow merge behavior.
```javascript
const Mixin = {
data() {
return {
user: {
name: 'Jack',
id: 1
}
}
}
}
const CompA = {
mixins: [Mixin],
data() {
return {
user: {
id: 2
}
}
}
}
```
--------------------------------
### Using Global Filters in Vue 3 Templates
Source: https://v3-migration.vuejs.org/breaking-changes/filters
Access globally registered filters via `$filters` in Vue 3 templates. This example shows how to format a balance using the globally available `currencyUSD` filter.
```html
Bank Account Balance
{{ $filters.currencyUSD(accountBalance) }}
```
--------------------------------
### Vue 2 Custom Directive Usage
Source: https://v3-migration.vuejs.org/breaking-changes/custom-directives
Example of a custom directive in Vue 2 using the bind hook.
```html
Highlight this text bright yellow
```
```js
Vue.directive('highlight', {
bind(el, binding, vnode) {
el.style.background = binding.value
}
})
```
--------------------------------
### Vue 3.x nextTick in Unit Tests
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
This example demonstrates importing `nextTick` as a named export in Vue 3 for use in unit tests. This is crucial for tree-shaking.
```javascript
import { shallowMount } from '@vue/test-utils'
import { MyComponent } from './MyComponent.vue'
import { nextTick } from 'vue'
test('an async feature', async () => {
const wrapper = shallowMount(MyComponent)
// execute some DOM-related tasks
await nextTick()
// run your assertions
})
```
--------------------------------
### Vue 2.x nextTick in Unit Tests
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
This example shows `Vue.nextTick` usage within a unit test in Vue 2. The global API approach prevents tree-shaking.
```javascript
import { shallowMount } from '@vue/test-utils'
import { MyComponent } from './MyComponent.vue'
test('an async feature', async () => {
const wrapper = shallowMount(MyComponent)
// execute some DOM-related tasks
await wrapper.vm.$nextTick()
// run your assertions
})
```
--------------------------------
### Vue 3.x Template Loop with Keys on Template Tag
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
In Vue 3.x, the `key` should be placed on the `` tag when using `v-for`. This example demonstrates the correct placement.
```html
...
...
```
--------------------------------
### Declare Global Directive in Vue 2
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Example of declaring a global directive using `Vue.directive` in Vue 2.
```js
Vue.directive('focus', {
inserted: (el) => el.focus()
})
```
--------------------------------
### Vue 3 transition-group explicit root element
Source: https://v3-migration.vuejs.org/breaking-changes/transition-group
Example of explicitly adding a span tag to maintain previous behavior in Vue 3.
```html
```
--------------------------------
### Re-emitting native events without declaration
Source: https://v3-migration.vuejs.org/breaking-changes/emits-option
Example of a component re-emitting a native event without declaring it in the emits option, which can lead to duplicate event triggers.
```vue
```
--------------------------------
### Vue 3.x Template Loop with v-if on Child
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
In Vue 3.x, when using `` with a child that uses `v-if`, the `key` should be moved up to the `` tag. This example shows the Vue 3.x syntax.
```html
...
...
```
--------------------------------
### Update v-model props and events in Vue.js
Source: https://v3-migration.vuejs.org/breaking-changes/v-model
For `v-model` without arguments, change props to `modelValue` and events to `update:modelValue`. This example shows the expected prop and emit signature in a child component.
```html
```
```javascript
// ChildComponent.vue
export default {
props: {
modelValue: String // previously was `value: String`
},
emits: ['update:modelValue'],
methods: {
changePageTitle(title) {
this.$emit('update:modelValue', title) // previously was `this.$emit('input', title)`
}
}
}
```
--------------------------------
### Vue 3 Computed Property Replacement for Filters
Source: https://v3-migration.vuejs.org/breaking-changes/filters
In Vue 3, filters are replaced by computed properties for data formatting. This example demonstrates converting a balance to USD using a computed property.
```html
Bank Account Balance
{{ accountInUSD }}
```
--------------------------------
### Vue 2 Parent Component Emitting Event
Source: https://v3-migration.vuejs.org/breaking-changes/events-api
Example of a Vue 2 parent component emitting a global custom event using the event bus. This allows child components to listen for and react to the event.
```javascript
import eventBus from './eventBus'
export default {
methods: {
callGlobalCustomEvent() {
eventBus.$emit('custom-event') // if ChildComponent is mounted, we will have a message in the console
}
}
}
```
--------------------------------
### Vue 2 Child Component Event Listener
Source: https://v3-migration.vuejs.org/breaking-changes/events-api
Example of a Vue 2 child component imperatively adding and removing event listeners using the event bus. Listeners are added in `mounted` and removed in `beforeDestroy`.
```javascript
import eventBus from './eventBus'
export default {
mounted() {
// adding eventBus listener
eventBus.$on('custom-event', () => {
console.log('Custom event triggered!')
})
},
beforeDestroy() {
// removing eventBus listener
eventBus.$off('custom-event')
}
}
```
--------------------------------
### Initialize a Vue 3 project with Vite
Source: https://v3-migration.vuejs.org/recommendations
Use this command to scaffold a new Vue 3 project powered by the Vite build tool.
```sh
npm init vue@3
```
--------------------------------
### Mount App Instance
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
The createApp global API initializes an application. Use the returned app instance's mount() method to attach a root component to a DOM element.
```javascript
import { createApp } from 'vue'
import MyApp from './MyApp.vue'
const app = createApp(MyApp)
app.mount('#app')
```
--------------------------------
### Compare Async Component Loader Signatures
Source: https://v3-migration.vuejs.org/breaking-changes/async-components
Comparison between the 2.x callback-based loader and the 3.x Promise-based loader.
```javascript
// 2.x version
const oldAsyncComponent = (resolve, reject) => {
/* ... */
}
// 3.x version
const asyncComponent = defineAsyncComponent(
() =>
new Promise((resolve, reject) => {
/* ... */
})
)
```
--------------------------------
### Local Vue Instance with `createLocalVue` for Testing
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Demonstrates using `createLocalVue` from `@vue/test-utils` to create isolated Vue constructors for testing, preventing global pollution.
```js
import { createLocalVue, mount } from '@vue/test-utils'
// create an extended `Vue` constructor
const localVue = createLocalVue()
// install a plugin “globally” on the “local” Vue constructor
localVue.use(MyPlugin)
// pass the `localVue` to the mount options
mount(Component, { localVue })
```
--------------------------------
### Migration Option 1: Script Tag Template
Source: https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute
Using a script tag with a custom type to define templates without build tools.
```html
```
```js
const MyComp = {
template: '#my-comp-template'
// ...
}
```
--------------------------------
### Provide and Inject Dependencies
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Similar to Vue 2's root instance provide option, Vue 3 app instances can provide dependencies that can be injected by any descendant component.
```javascript
// in the entry
app.provide('guide', 'Vue 3 Guide')
// in a child component
export default {
inject: {
book: {
from: 'guide'
}
},
template: `
{{ book }}
`
}
```
--------------------------------
### Vue 2.x Rendered Output
Source: https://v3-migration.vuejs.org/breaking-changes/mount-changes
Illustrates the HTML output after mounting an application in Vue 2.x, showing the target element being replaced.
```html
Hello Vue!
```
--------------------------------
### Register Components and Directives Globally
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Components and directives can be registered globally on the app instance before mounting. This makes them available to all components within the application without polluting the global environment.
```javascript
const app = createApp(MyApp)
app.component('button-counter', {
data: () => ({
count: 0
}),
template: ''
})
app.directive('focus', {
mounted: (el) => el.focus()
})
// now every application instance mounted with app.mount(), along with its
// component tree, will have the same “button-counter” component
// and “focus” directive without polluting the global environment
app.mount('#app')
```
--------------------------------
### Configure Vue Compat Mode with Vue CLI
Source: https://v3-migration.vuejs.org/migration-build
Configure vue-cli to alias 'vue' to '@vue/compat' and enable compat mode in the Vue loader options.
```js
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.resolve.alias.set('vue', '@vue/compat')
config.module
.rule('vue')
.use('vue-loader')
.tap((options) => {
return {
...options,
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
}
}
```
--------------------------------
### Vue 2.x Transition Class Syntax
Source: https://v3-migration.vuejs.org/breaking-changes/transition
Legacy CSS transition classes used prior to Vue 3.
```css
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
```
--------------------------------
### Enable Vue 3 Behavior Globally
Source: https://v3-migration.vuejs.org/migration-build
Set `MODE: 3` in `configureCompat` to default the entire application to Vue 3 behavior, then selectively enable specific compatibility features if needed. Ensure `vue` is imported.
```js
import { configureCompat } from 'vue'
// default everything to Vue 3 behavior, and only enable compat
// for certain features
configureCompat({
MODE: 3,
FEATURE_ID_A: true,
FEATURE_ID_B: true
})
```
--------------------------------
### Define Async Components in Vue 2.x
Source: https://v3-migration.vuejs.org/breaking-changes/async-components
Legacy syntax for creating async components using simple functions or object configurations.
```javascript
const asyncModal = () => import('./Modal.vue')
```
```javascript
const asyncModal = {
component: () => import('./Modal.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
}
```
--------------------------------
### Replace Vue.extend with createApp
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Vue 2's Vue.extend for creating component constructors is removed in Vue 3. Use createApp to mount components.
```javascript
// before - Vue 2
// create constructor
const Profile = Vue.extend({
template: '
{{firstName}} {{lastName}} aka {{alias}}
',
data() {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// create an instance of Profile and mount it on an element
new Profile().$mount('#mount-point')
```
```javascript
// after - Vue 3
const Profile = {
template: '
{{firstName}} {{lastName}} aka {{alias}}
',
data() {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
}
Vue.createApp(Profile).mount('#mount-point')
```
--------------------------------
### Vue 3.x Transition Class Syntax
Source: https://v3-migration.vuejs.org/breaking-changes/transition
Updated CSS transition classes for Vue 3, using explicit naming for initial states.
```css
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
```
--------------------------------
### Vue 2 Lifecycle Event Syntax
Source: https://v3-migration.vuejs.org/breaking-changes/vnode-lifecycle-events
Uses the 'hook:' prefix to listen for component lifecycle stages in Vue 2.
```html
```
--------------------------------
### Configure Vue Compat Mode with Plain Webpack
Source: https://v3-migration.vuejs.org/migration-build
Configure webpack to alias 'vue' to '@vue/compat' and enable compat mode in the vue-loader options.
```js
// webpack.config.js
module.exports = {
resolve: {
alias: {
vue: '@vue/compat'
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
}
]
}
}
```
--------------------------------
### Vue 2 Custom v-model Prop/Event with `model` Option
Source: https://v3-migration.vuejs.org/breaking-changes/v-model
Vue 2 allowed customization of v-model prop and event names using the `model` option within the component. This example shows how to use `title` as the prop and `change` as the event.
```html
```
```javascript
// ChildComponent.vue
export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// this allows using the `value` prop for a different purpose
value: String,
// use `title` as the prop which take the place of `value`
title: {
type: String,
default: 'Default title'
}
}
}
```
```html
So, `v-model` in this case would be a shorthand to
```
--------------------------------
### Resolve Registered Components
Source: https://v3-migration.vuejs.org/breaking-changes/render-function-api
Demonstrates how to resolve registered components in Vue 3 using 'resolveComponent' instead of string IDs.
```javascript
// 2.x
Vue.component('button-counter', {
data() {
return {
count: 0
}
}
template: `
`
})
export default {
render(h) {
return h('button-counter')
}
}
```
```javascript
// 3.x
import { h, resolveComponent } from 'vue'
export default {
setup() {
const ButtonCounter = resolveComponent('button-counter')
return () => h(ButtonCounter)
}
}
```
--------------------------------
### Configure Per-Component Compatibility
Source: https://v3-migration.vuejs.org/migration-build
Use the `compatConfig` option within a component to opt-in to Vue 3 behavior or enable specific compatibility features for that component only. This option accepts the same configuration as `configureCompat`.
```js
export default {
compatConfig: {
MODE: 3, // opt-in to Vue 3 behavior for this component only
FEATURE_ID_A: true // features can also be toggled at component level
}
// ...
}
```
--------------------------------
### Vue 3.x Mount Application
Source: https://v3-migration.vuejs.org/breaking-changes/mount-changes
In Vue 3.x, `app.mount('#app')` appends the rendered application as a child, replacing the target element's `innerHTML`. This is the standard mounting method in Vue 3.
```js
const app = Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
},
template: `
{{ message }}
`
})
app.mount('#app')
```
--------------------------------
### Vue 3 Lifecycle Event Syntax
Source: https://v3-migration.vuejs.org/breaking-changes/vnode-lifecycle-events
Uses the 'vue:' prefix to listen for component or HTML element lifecycle stages in Vue 3.
```html
```
--------------------------------
### Accessing child components in Vue 2.x
Source: https://v3-migration.vuejs.org/breaking-changes/children
Demonstrates the use of this.$children to access direct child components in a Vue 2.x component.
```vue
Change logo
```
--------------------------------
### Structure VNode Props
Source: https://v3-migration.vuejs.org/breaking-changes/render-function-api
Illustrates the transition from nested VNode props in Vue 2 to a flattened structure in Vue 3.
```javascript
// 2.x
{
staticClass: 'button',
class: {'is-outlined': isOutlined },
staticStyle: { color: '#34495E' },
style: { backgroundColor: buttonColor },
attrs: { id: 'submit' },
domProps: { innerHTML: '' },
on: { click: submitForm },
key: 'submit-button'
}
```
```javascript
// 3.x Syntax
{
class: ['button', { 'is-outlined': isOutlined }],
style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
id: 'submit',
innerHTML: '',
onClick: submitForm,
key: 'submit-button'
}
```
--------------------------------
### Configure Vue Compat Mode with Vite
Source: https://v3-migration.vuejs.org/migration-build
Configure Vite to alias 'vue' to '@vue/compat' and enable compat mode in the vue plugin's compiler options.
```js
// vite.config.js
export default {
resolve: {
alias: {
vue: '@vue/compat'
}
},
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
]
}
```
--------------------------------
### Define Render Function with h
Source: https://v3-migration.vuejs.org/breaking-changes/render-function-api
Compares the Vue 2 approach of receiving 'h' as an argument versus the Vue 3 approach of importing 'h' globally.
```javascript
// Vue 2 Render Function Example
export default {
render(h) {
return h('div')
}
}
```
```javascript
// Vue 3 Render Function Example
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
```
--------------------------------
### Accessing Component Instance in Directives
Source: https://v3-migration.vuejs.org/breaking-changes/custom-directives
Comparison of how to access the component instance within a directive between Vue 2 and Vue 3.
```js
bind(el, binding, vnode) {
const vm = vnode.context
}
```
```js
mounted(el, binding, vnode) {
const vm = binding.instance
}
```
--------------------------------
### Vue 2.x Mount with $mount
Source: https://v3-migration.vuejs.org/breaking-changes/mount-changes
Similar to the `el` option, using `$mount` in Vue 2.x replaces the target element. This method is also changed in Vue 3.
```js
const app = new Vue({
data() {
return {
message: 'Hello Vue!'
}
},
template: `
{{ message }}
`
})
app.$mount('#app')
```
--------------------------------
### Define Async Components in Vue 3
Source: https://v3-migration.vuejs.org/breaking-changes/async-components
Current syntax using the defineAsyncComponent helper to wrap async component definitions.
```javascript
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// Async component without options
const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))
// Async component with options
const asyncModalWithOptions = defineAsyncComponent({
loader: () => import('./Modal.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
```
--------------------------------
### Migration Option 2: Default Slot Refactoring
Source: https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute
Refactoring inline-template components to use default slots for explicit data scoping.
```html
{{ msg }} {{ childState }}
{{ parentMsg }} {{ childState }}
```
```html
```
--------------------------------
### Vue 3: Passing Props with `createApp`
Source: https://v3-migration.vuejs.org/breaking-changes/props-data
In Vue 3, pass props to the root component by providing them as the second argument to the `createApp` function. This replaces the functionality of the removed `propsData` option.
```javascript
const app = createApp(
{
props: ['username'],
template: '
{{ username }}
'
},
{ username: 'Evan' }
)
```
--------------------------------
### Vue 3.x Rendered Output
Source: https://v3-migration.vuejs.org/breaking-changes/mount-changes
Shows the HTML output when mounting an application in Vue 3.x, where the new content is nested within the original target element.
```html
Hello Vue!
```
--------------------------------
### Vue 2.x Template Loop with Keys on Children
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
In Vue 2.x, a `` tag could not have a `key`. Keys were placed on each of its children.
```html
...
...
```
--------------------------------
### Update package.json for Vue 3 Migration
Source: https://v3-migration.vuejs.org/migration-build
Update your package.json to include Vue 3 and the compat build, and replace the Vue template compiler.
```diff
"dependencies": {
- "vue": "^2.6.12",
+ "vue": "^3.1.0",
+ "@vue/compat": "^3.1.0"
...
},
"devDependencies": {
- "vue-template-compiler": "^2.6.12"
+ "@vue/compiler-sfc": "^3.1.0"
}
```
--------------------------------
### Replace Vue.prototype with config.globalProperties
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
In Vue 2, Vue.prototype was used to add global properties. In Vue 3, use config.globalProperties on the app instance.
```javascript
// before - Vue 2
Vue.prototype.$http = () => {}
```
```javascript
// after - Vue 3
const app = createApp({})
app.config.globalProperties.$http = () => {}
```
--------------------------------
### Vue 2: Transition as Root Component
Source: https://v3-migration.vuejs.org/breaking-changes/transition-as-root
In Vue 2, a `` component could be used as the root of a modal component, and toggling its visibility externally would trigger transitions. This behavior was unintentional.
```html
```
```html
hello
```
--------------------------------
### Vue 3.x Conditional Rendering with Unique Keys
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
If manually providing `key`s in Vue 3.x, each branch must use a unique `key`. This is an alternate solution to removing keys entirely.
```html
Yes
No
```
--------------------------------
### Watch array with deep option
Source: https://v3-migration.vuejs.org/breaking-changes/watch
Use the deep option to trigger the watcher on array mutations. Note the version-specific syntax for deep configuration.
```javascript
watch: {
bookList: {
handler(val, oldVal) {
console.log('book list changed')
},
deep: 1 // Vue 3.5+
// deep: true // Vue 3.0 - 3.4
},
}
```
--------------------------------
### Vue 2.x Mount with el
Source: https://v3-migration.vuejs.org/breaking-changes/mount-changes
In Vue 2.x, the `el` option replaces the target element with the rendered application content. This syntax is deprecated in Vue 3.
```js
new Vue({
el: '#app',
data() {
return {
message: 'Hello Vue!'
}
},
template: `
{{ message }}
`
})
```
--------------------------------
### Define Vue 2.x Data Option
Source: https://v3-migration.vuejs.org/breaking-changes/data-option
Shows the legacy support for both object and function declarations in Vue 2.x.
```html
```
--------------------------------
### Share Configurations Among Apps with Factory Function
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
A factory function can create and configure multiple Vue app instances, allowing shared configurations like directives across different mounts.
```javascript
import { createApp } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const createMyApp = (options) => {
const app = createApp(options)
app.directive('focus' /* ... */)
return app
}
createMyApp(Foo).mount('#foo')
createMyApp(Bar).mount('#bar')
```
--------------------------------
### Vue 2 Component Usage and Rendered HTML
Source: https://v3-migration.vuejs.org/breaking-changes/attrs-includes-class-style
Demonstrates how a Vue 2 component with 'inheritAttrs: false' renders when passed 'id' and 'class' attributes. The 'class' is applied to the root label, while 'id' is applied to the input.
```html
```
```html
```
--------------------------------
### Define Vue 3.x Data Option
Source: https://v3-migration.vuejs.org/breaking-changes/data-option
Demonstrates the standardized function-only declaration for data in Vue 3.
```html
```
--------------------------------
### Vue 2: Passing Props with `propsData`
Source: https://v3-migration.vuejs.org/breaking-changes/props-data
In Vue 2, the `propsData` option was used to pass initial props to a Vue instance upon creation. This method is no longer supported in Vue 3.
```javascript
const Comp = Vue.extend({
props: ['username'],
template: '
{{ username }}
'
})
new Comp({
propsData: {
username: 'Evan'
}
})
```
--------------------------------
### Configure Autonomous Custom Elements in Vue 3 (On-the-fly)
Source: https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop
For on-the-fly template compilation in Vue 3, configure custom elements by passing the `isCustomElement` option via `app.config.compilerOptions.isCustomElement`. This affects runtime template compilation only.
```javascript
const app = Vue.createApp({})
app.config.compilerOptions.isCustomElement = tag => tag === 'plastic-button'
```
--------------------------------
### Vue 3: Migration Strategy for Transition as Root
Source: https://v3-migration.vuejs.org/breaking-changes/transition-as-root
To achieve a similar effect in Vue 3, pass a prop to the component to control its conditional rendering and trigger transitions. This is the intended way to manage transitions.
```vue
```
```html
hello
```
--------------------------------
### Vue 3.x Internal Helpers for Tree-shaking
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
Vue 3 exports internal helpers like `h`, `Transition`, `withDirectives`, and `vShow` as named exports. This allows the compiler to import only necessary features, improving tree-shaking.
```javascript
import { h, Transition, withDirectives, vShow } from 'vue'
export function render() {
return h(Transition, [withDirectives(h('div', 'hello'), [[vShow, this.ok]])])
}
```
--------------------------------
### Registering Global Filters in Vue 3
Source: https://v3-migration.vuejs.org/breaking-changes/filters
For globally registered filters in Vue 3, use `globalProperties` in `main.js` to make them available across all components.
```javascript
// main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
currencyUSD(value) {
return '$' + value
}
}
```
--------------------------------
### Migrate Vue 2.x Plugin to Vue 3
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
Updates a plugin to use explicit imports instead of relying on the global Vue object.
```javascript
const plugin = {
install: Vue => {
Vue.nextTick(() => {
// ...
})
}
}
```
```javascript
import { nextTick } from 'vue'
const plugin = {
install: app => {
nextTick(() => {
// ...
})
}
}
```
--------------------------------
### Disable Vue 2 Compatibility Features Globally
Source: https://v3-migration.vuejs.org/migration-build
Use `configureCompat` to disable specific Vue 2 compatibility features, enforcing Vue 3 behavior for those features. Ensure `vue` is imported.
```js
import { configureCompat } from 'vue'
// disable compat for certain features
configureCompat({
FEATURE_ID_A: false,
FEATURE_ID_B: false
})
```
--------------------------------
### Configure Bundlers for External Vue Dependency
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
Prevents bundling Vue into the plugin by marking it as an external dependency.
```javascript
// webpack.config.js
module.exports = {
/*...*/
externals: {
vue: 'Vue'
}
}
```
```javascript
// rollup.config.js
export default {
/*...*/
external: ['vue']
}
```
--------------------------------
### Configure `isCustomElement` in Vue 3
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Migrates the Vue 2 `config.ignoredElements` to Vue 3's `app.config.compilerOptions.isCustomElement`, allowing for more flexible custom element detection.
```js
// before
Vue.config.ignoredElements = ['my-el', /^ion-/]
// after
const app = createApp({})
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('ion-')
```
--------------------------------
### Vue 2.x Scoped Slot Reference
Source: https://v3-migration.vuejs.org/breaking-changes/slots-unification
Scoped slots in Vue 2.x were referenced directly via `this.$scopedSlots`.
```javascript
// 2.x Syntax
this.$scopedSlots.header
```
--------------------------------
### Vue 3.x Multi-Root Component Structure
Source: https://v3-migration.vuejs.org/new/fragments
Vue 3 supports multiple root nodes, requiring explicit attribute binding using $attrs for fallthrough attributes.
```html
......
```
--------------------------------
### Configure Autonomous Custom Elements in Vue 3 (Build Step)
Source: https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop
In Vue 3.0, custom element configuration is done during template compilation. When using a build step with vue-loader, pass the `isCustomElement` option to the Vue template compiler via `vue-loader`'s `compilerOptions`.
```javascript
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
options: {
compilerOptions: {
isCustomElement: tag => tag === 'plastic-button'
}
}
}
// ...
]
```
--------------------------------
### Vue 3 v-model with Arguments for Custom Names
Source: https://v3-migration.vuejs.org/breaking-changes/v-model
Vue 3 allows specifying custom prop and event names for v-model by using arguments. This replaces the need for the `model` option and the `.sync` modifier.
```html
```
--------------------------------
### Vue 2.x Single-Root Component Structure
Source: https://v3-migration.vuejs.org/new/fragments
Components in Vue 2.x required a single root element, often resulting in unnecessary wrapper divs.
```html
......
```
--------------------------------
### Vue 3 Custom Directive API
Source: https://v3-migration.vuejs.org/breaking-changes/custom-directives
The unified lifecycle hook API for custom directives in Vue 3.
```js
const MyDirective = {
created(el, binding, vnode, prevVnode) {}, // new
beforeMount() {},
mounted() {},
beforeUpdate() {}, // new
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
```
--------------------------------
### Vue 3.x Conditional Rendering without Keys
Source: https://v3-migration.vuejs.org/breaking-changes/key-attribute
In Vue 3.x, unique `key`s are automatically generated for conditional branches if not provided. This is the recommended approach.
```html
Yes
No
```
--------------------------------
### Global Mixin Affecting Multiple Root Instances in Vue 2
Source: https://v3-migration.vuejs.org/breaking-changes/global-api
Illustrates how a global mixin applied via `Vue.mixin` in Vue 2 affects all subsequently created root instances.
```js
// this affects both root instances
Vue.mixin({
/* ... */
})
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
```
--------------------------------
### Vue 2.x Global nextTick Usage
Source: https://v3-migration.vuejs.org/breaking-changes/global-api-treeshaking
In Vue 2, `Vue.nextTick` was a global API. This pattern is not tree-shakeable and will be included in the bundle even if unused.
```javascript
import Vue from 'vue'
Vue.nextTick(() => {
// something DOM-related
})
```
--------------------------------
### Vue 3 Multiple v-model Bindings with Arguments
Source: https://v3-migration.vuejs.org/breaking-changes/v-model
Vue 3 supports multiple v-model bindings on a single component by using arguments for each v-model. This allows for managing several pieces of two-way bound data independently.
```html
```
--------------------------------
### Vue 2 v-model on Custom Component
Source: https://v3-migration.vuejs.org/breaking-changes/v-model
In Vue 2, v-model on a custom component was a shorthand for passing a `value` prop and listening for an `input` event.
```html
```
--------------------------------
### Define a Vue 3 functional component
Source: https://v3-migration.vuejs.org/breaking-changes/functional-components
Creates a functional component using a plain function and imported h function.
```javascript
import { h } from 'vue'
const DynamicHeading = (props, context) => {
return h(`h${props.level}`, context.attrs, context.slots)
}
DynamicHeading.props = ['level']
export default DynamicHeading
```
--------------------------------
### Define a Vue 2 functional component
Source: https://v3-migration.vuejs.org/breaking-changes/functional-components
Uses the functional option and render function to create a dynamic heading component.
```javascript
// Vue 2 Functional Component Example
export default {
functional: true,
props: ['level'],
render(h, { props, data, children }) {
return h(`h${props.level}`, data, children)
}
}
```
--------------------------------
### TypeScript Module Declaration for Vue Compat
Source: https://v3-migration.vuejs.org/migration-build
Augment Vue's types in TypeScript to expose the default export for compat mode. Ensure this file has at least one other top-level import or export.
```ts
declare module 'vue' {
import { CompatVue } from '@vue/runtime-dom'
const Vue: CompatVue
export default Vue
export * from '@vue/runtime-dom'
const { configureCompat } = Vue
export { configureCompat }
}
```
--------------------------------
### Vue 3 Key Modifiers
Source: https://v3-migration.vuejs.org/breaking-changes/keycode-modifiers
Vue 3 recommends using kebab-case key names for v-on modifiers instead of numeric keyCodes. This approach is more aligned with the deprecated `KeyboardEvent.keyCode`.
```html
```