DEV Community

Per Enström
Per Enström

Posted on

Migrating a Vue 2 project to Vue 3

In September of 2020 Evan You announced the stable release of Vue 3. The official blog post stated that it comes with

improved performance, smaller bundle sizes, better TypeScript integration, new APIs for tackling large scale use cases, and a solid foundation for long-term future iterations of the framework.

But should you take the plunge immediately and migrate all your Vue 2 projects to Vue 3? Well, it depends. For many of you, the answer is probably ‘not yet’, for others it’s a wholehearted ‘yes’.

Vue 3 doesn’t introduce anything revolutionary that you can’t already do in some fashion in Vue 2. But some features might be sufficiently attractive to upgrade. Let’s go through the four main features of Vue 3, and then you can make an informed decision yourself.

First a disclaimer. Coming from a React background, Vue is still quite new to me, and one of the reasons for embarking on the migration journey was to learn more about the inner workings. So don’t expect any deep analysis of advanced new features, and take everything with a grain of salt.

New features

Layered internal modules

This is basically a fancy way of saying that they’ve reduced tight coupling between internal parts of Vue, making them more modular and swappable. This can also result in a smaller final bundle size, since parts of the Vue runtime may be completely or partly removed during tree shaking.

These new modules also expose some of their internal APIs, which makes it possible to do some advanced solutions. One example of this is to write a custom renderer (in the blog post they mention Native or integrated systems), and the normal DOM renderer is also using these APIs.

Performance improvements

According to their own blog post, Vue 3 is up to 41% smaller, renders up to 55% faster, updates up to 133% faster and uses up to 54% less memory. However, in the migration of our product we found negligible bundle size decreases, and in some cases increases. We did not perform any speed performance testing, but my general standpoint is to trust the developers. Our project is so small from the beginning, so perhaps there wasn’t room for much savings.

Improved TypeScript integration

Vue 3 has been written completely in TypeScript, this means that all internal methods have type definitions bundled. For us developers, this means mainly that you will get some better autocompletion in VS Code, but also that moving your project to Typescript will be easier.

Composition API

Perhaps the largest change is the Composition API, which makes it possible to couple related data, methods, watches, and computations together instead of splitting the concerns over multiple parts of the component. This can make for a more elegant code base, as well as interesting possibilities for reusing parts of the logic in multiple components. See the introduction article in the Vue documentation for more information. But basically, it means we can go from this:

A Vue component with mixed concerns in data, computed and methods

to this:

A Vue component using setup, with concerns next to each other

and then refactored to this:

The same Vue component refactored to be brief

Migration pattern

The complexity in migrating an existing Vue 2 project to Vue 3 entirely depends on what external plugins and libraries you are using, and how well they support Vue 3. Vue provides a migration build to ease the process, allowing you to migrate in steps while keeping some backwards compatibility. They also provide nice step-by-step instructions on how to migrate. I won’t go through it in detail here but will mention some pain points I encountered when migrating.

Notable breaking changes

Global API changes

Where you could previously access the global Vue object to, for example, add some global variables to Vue.prototype, you now have to do add it to the config object of the actual Vue instance you’re using, i.e. app.config.globalProperties.

V-model on custom components

When using v-model on custom components, the incoming data and emitted events have been changed. They can now be accessed on modelValue and update:modelValue. This opens up for custom components to have multiple v-model bindings.

Functional components

Functional components are now only created via a plain function and the functional attribute on single-file components have been deprecated. Where you previously used functional components to gain some performance increases, this gain is now negligible and the recommended way is to move all components to stateful components.

Render function changes

If you’re using the render function in any of your components instead of normal template components. The syntax for this has now changed.

Migration steps

The steps to complete migration can be found in the documentation, but mainly consists of:

  1. Update Vue and add compatibility package

  2. Fix warnings exposed by the compatibility package

  3. Update mounting of your app

  4. Upgrade vuex, vue-router, and any other Vue plugins you’re using

  5. When all warnings are fixed, uninstall the compatibility package

Overall the migration is easy to follow, and all official plugins (vuex, vue-router, etc) have good migration guides as well. We noted that we used node-sass, which has been deprecated and replaced by sass, but that was an easy swap. We couldn’t go past v10 of sass-loader, since it requires Webpack 5, which is a migration for another day.

One package we used for automatic formatting of input fields, vue-mask, seemed abandoned when we migrated, but seems to be updated to Vue 3 now. But keep an eye out for packages that doesn’t support Vue 3.

Why is it not @latest?

If you’ve looked into Vue 3, you might have found that (at the time of writing) the @latest tag on NPM still points to Vue 2, with Vue 3 being relegated to @next still. Even though Vue 3 was released in 2020, they are holding up on pointing everyone to the latest version until more plugins have been migrated to support Vue 3. Since Vue 3 contains a number of breaking changes, if you rely on a plugin that hasn’t migrated, you’re still stuck on Vue 2.

The communication from Vue on this subject could be more transparent, however. Their roadmaps and blogposts are at this point quite outdated.


Should you take the plunge?

It depends. If you’re not using any of the deprecated features extensively, then I would absolutely recommend upgrading. Especially if you’re looking to moving to Typescript, the process will be easier if you’re on Vue 3. All official packages and dev tools support Vue 3, so if you use a fairly vanilla setup, the process will probably be smooth.

If you use some packages that don’t support Vue 3, and you can’t find alternatives (as we did), you will have to stay on Vue 2. That being said, if you didn’t feel like any of the new features seem interesting to you, you’re fine being on Vue 2.

But as with all projects, staying up to date has its perks. As time goes on, more and more packages will migrate to Vue 3, and eventually drop support for Vue 2, at which point you’re forced to upgrade for the same reason as you were forced to wait before.

Top comments (3)

perenstrom profile image
Per Enström

Interesting! I find composition API code to much more readable. But as it often is, what is readable to you is highly subjective.

Could you elaborate on you SFC comment? What kind of config and dependencies are they requiring today?

karlenkhachaturyan profile image
Karlen Khachaturyan

Very interesting article, thank you!

perenstrom profile image
Per Enström

Thank you!