Vue 3 Migration Guide

repository·main·Indexed 42 days ago

https://github.com/vuejs/v3-migration-guide

Official documentation for migrating from Vue 2 to Vue 3. Covers breaking changes including the use of defineAsyncComponent for async components, updated attribute coercion behavior, the inclusion of class and style in $attrs, the removal of $children in favor of template refs, and renamed custom directive lifecycle hooks.

Tokens
21.3K
Snippets
72
Records
115
Agent score
52%

What's inside Vue

  1. Overview of Vue 3 Breaking Changes

    main

    When migrating from Vue 2 to Vue 3, several core areas of the framework have undergone breaking changes. These changes are categorized into Global API, Template Directives, Components, Render Functions, Custom Elements, and various lifecycle or API removals.

    Key areas of impact include:

    • Global API: Transition from a global Vue constructor to an application instance model.
    • Template Directives: Changes to v-model, v-if/v-for precedence, and the removal of .native modifiers.
    • Components: New requirements for async components (defineAsyncComponent), declaration of events (emits), and changes to functional components.
    • Render Function: Unification of slots and changes to how $attrs and $listeners behave.
    • Removed APIs: Removal of Filters, $on/$off/$once, and the $children property.
  2. Overview of the Vue 3 Migration Guide

    main

    The Vue 3 Migration Guide is designed for developers with Vue 2 experience who need to understand the differences between versions. It is not intended to be read linearly; instead, it serves as a reference for specific changes. For general learning, the official Vue documentation is the recommended starting point.

    Important Note: Vue 2 support ended on December 31st, 2023. If upgrading to Vue 3 is not immediately feasible, refer to the Vue 2 Extended LTS documentation.

  3. Summary of new Vue 3 framework-level recommendations

    main

    When migrating to or starting a new Vue 3 project, the following library recommendations apply:

    • Build Toolchain: Use Vite instead of Vue CLI.
    • State Management: Use Pinia instead of Vuex (though Vuex 4 is available for legacy support).
    • Router: Use Vue Router 4.0.
    • IDE Support: Use Volar instead of Vetur.
    • TypeScript: Use vue-tsc for command-line type-checking of SFCs.
    • Static Site Generator: Use VitePress instead of VuePress.
    • JSX: Use @vue/babel-plugin-jsx instead of @vue/babel-preset-jsx.
  4. What is the Vue 3 Migration Build (@vue/compat)?

    main
    @vue/compat (the migration build) is a version of Vue 3 that provides configurable Vue 2 compatibility. It runs in Vue 2 mode by default, meaning most public APIs behave like Vue 2, but it emits runtime warnings for features that have changed or been deprecated in Vue 3. This allows you to upgrade an application incrementally by enabling or disabling specific compatibility features.
  5. Global API changes in Vue 3

    main

    The Global Vue API has been replaced by an application instance model. Instead of using the global Vue constructor for most configurations, you should now create an application instance using createApp.

    Additionally, global and internal APIs have been restructured to be tree-shakable, allowing for better bundle optimization.

  6. Component API breaking changes

    main

    Significant changes have been made to how components are defined and used:

    • Functional Components: Can now only be created using a plain function. The functional attribute on SFC <template> and the functional component option are deprecated.
    • Async Components: Now require the defineAsyncComponent method for creation.
    • Component Events: Events should now be explicitly declared using the emits option.
  7. Accessing props and injected values in props default functions

    main

    In Vue 3, factory functions used for props.default no longer have access to the component instance via this.

    To achieve the same functionality, you must use the following patterns:

    1. Accessing Prop Values: The raw values of the props received by the component are passed as the first argument to the default function. Note that these are the raw values before any type or default coercions are applied.
    2. Accessing Injected Dependencies: You can use the inject API directly inside the default function to access properties provided via dependency injection.
    import { inject } from 'vue'
    
    export default {
      props: {
        theme: {
          default (props) {
            // `props` is the raw values passed to the component,
            // before any type / default coercions
            // can also use `inject` to access injected properties
            return inject('theme', 'default-theme')
          }
        }
      }
    }
  8. Lifecycle and Minor API changes

    main

    Several minor but important changes affect component lifecycles and reactivity:

    • Lifecycle Renaming:
      • destroyed $\rightarrow$ unmounted
      • beforeDestroy $\rightarrow$ beforeUnmount
    • Data Option: The data option should always be declared as a function. Note that data option from mixins is now merged shallowly.
    • Props Default: The default factory function for props no longer has access to the this context.
    • Watchers: When watching an array, the callback only triggers when the array is replaced. To trigger on mutation, you must use the deep: true option.
    • Transition Group: <TransitionGroup> now renders no wrapper element by default.
    • Custom Directives: The API has changed to align with the component lifecycle, and binding.expression has been removed.
  9. Render Function and Slot changes

    main

    The render function API and how components handle slots and attributes have changed:

    • Slots: The $scopedSlots property is removed. All slots are now exposed via $slots as functions.
    • Listeners and Attributes: $listeners has been removed and its functionality is merged into $attrs.
    • $attrs: Now includes class and style attributes.
    • Render Function API: The core API for render functions has changed.
  10. How the `is` attribute behaves in Vue 3

    main

    Vue 3 restricts the special behavior of the is attribute to the reserved <component> tag to allow for native HTML 'Customized Built-in Elements'.

    • On <component>: Behaves exactly like Vue 2 (renders the component specified by is).
    • On normal components: Behaves like a standard attribute. For example, <foo is="bar" /> will render the foo component and pass is="bar" as a prop.
    • On plain HTML elements: Behaves as a native attribute. For example, <button is="plastic-button"> will result in a native button being created via document.createElement('button', { is: 'plastic-button' }).
  11. Update Render Function Slot Syntax for Vue 3

    main

    When using render functions (h), the way slots are defined has changed from using a slot data property on child nodes to passing an object of slot functions as the third argument to h.

    // 2.x Syntax: Using the 'slot' data property
    h(LayoutComponent, [
      h('div', { slot: 'header' }, this.header),
      h('div', { slot: 'content' }, this.content)
    ])
    
    // 3.x Syntax: Passing slots as an object of functions
    h(LayoutComponent, {}, {
      header: () => h('div', this.header),
      content: () => h('div', this.content)
    })