Let’s Talk about Vue 3 and Change

Published Sunday, February 13th 2022 · 7min read

I’ve just started a new personal project—more on that in a future post, I hope 😉—and since Vue 3 just replaced Vue 2 as the “recommended” (i.e. default) version on NPM, I figured I’d give the new workflow a shot.

A New Recommended Way

For years now, the recommended way to scaffold a new Vue project was to use the vue-cli package, which greatly simplified the bootstrapping-process. Things like state management, router and even PWA integrations, not to mention linting and CSS pre-processors could be selected when creating the new project and thus cut down on post-initialisation work. I’ve been using that workflow for so long now that it became second nature and even allowed me to finally make some sense of the black hole that is webpack.

The new way does no longer use webpack, though. Instead, it is built around vite. New projects can now be initialised with a simple npm init vue@latest, which somewhat mirrors the interface of vue-cli, but is much more limited. For example, it no longer asks what CSS pre-processor I’d like to use, and while it asks whether or not I want to use ESLint, it doesn’t allow me to select a style-guide like vue-cli did. I’m also sorely missing the PWA integration—there seems to be a plugin for vite, but it doesn’t look as official as the one installed by vue-cli did, although that might just be my subjective impression.

In addition to that, the default state management library is no longer vuex, but pinia, which brings me to my next point.

A Lot of New Stuff to Learn

Vue 3 introduced the Composition API, a new way of creating components that supposedly is faster and cleaner, because it allows for more explicit and cleaner re-usability of commonly used functions. It makes use of a setup() function that explicitly returns the properties that should be accessible within the component template and requires the developer to manually specify which properties should be reactive by using wrapper functions such as ref() and reactive().

Despite stating multiple times that the traditional Options API, where components where created by exporting an object with various standardised properties, wouldn’t go anywhere anytime soon, it feels like usage of the Composition API is strongly suggested—in fact the Options API is implemented on top of the Composition API!

Pinia, the new default state management library, is implemented on top of the Composition API as well and at least to me it seems like using Pinia without also using the Composition API would make things unnecessarily more complicated.

So not only do I have to adjust to the changes between Vue 2 and Vue 3, but also learn an entirely new way of defining components, a new state management library, and a new build-tool with its associated plugins. That is a lot of change for someone who has written Vue code nearly daily for years now.

I still remember migrating to Vue 2 when it was first released and how much effort I had to put into re-training my muscle memory. I’m very happy for the incredible amount of effort that goes into the development of Vue and some of the improvements of Vue 3 are great, but these paradigm shifts between major releases are starting to annoy me a little.

Despite that, Vue puts a lot of attention and care into their migration guides and documentation, which are arguably one of the best features of the framework. The transition could be a lot worse, but that doesn’t mean I have to enjoy every part of it.

Thoughts on…


There’s no denying that vite is fast. Really fast. Where even for a small project I’d have to wait a couple of seconds until the dev server was running, with vite it takes about 200ms on my machine at the moment. There also seems to be a reasonably large plugin-ecosystem and so far I haven’t missed webpack. But why, why does the new default port for the dev server have to be 3000 instead of 8080? That seems like such an unnecessary change to me that may easily be fixed, but requires editing the package.json file after initialising the project. On a more positive note, at least we’re back to npm run dev instead of npm run serve which I could never quite get used to!


After using it for a little bit, Pinia seems to be greatly simplified compared to Vuex and I like the ability to have multiple stores out of the box without having to resort to modules. I haven’t used it much yet, but it does feel wrong to directly mutate my state instead of having dedicated mutation functions (even if those were painful to set up sometimes). I guess I could always resort to using actions even for simple mutations, but maybe I just have to get used to this new way.

Composition API

Thanks to Vue’s excellent documentation, I was able to grasp the basic concepts of the Composition API reasonably quickly and even wrote my first Composable soon thereafter. The <script setup></script> section of Vue’s Single File Components makes it really hassle-free to write setup() functions, but I’m not quite sure whether I like this approach yet.

For one, having to remember and write many more imports feels unnecessarily more verbose, even if it is more explicit than working with an opaque and almost magical this. I also miss the structural guidance of the Options API: there I would simply include all the options in alphabetical order and thus have each of my components structured in the same way.

The setup() function on the other hand is completely free-form and makes me instinctively write code like I would in a normal script: imports, variable definitions, function definitions, other statements. However, as far as I understood it, using the Composition API is supposed to be a way to logically group related parts of the code, which would require a different structure. I’ll have to use the Composition API more to find out whether ultimately I like it or not, but I think one of Vue’s greatest strengths is its ease of use. The Options API makes sense even to inexperienced developers and the Composition API does not, in my opinion. It is a lot less intuitive.

What I do find quite annoying and error-prone is having to remember to access the values of reactive properties using variable.value—which isn’t the case when using them in the component template. Somehow, that’s confusing to me and I regularly forget it. I also find it more cumbersome to define computed getters and watchers, since I have to remember when to pass a getter function to them instead of just a variable and other little details like that.

The concept of reusable Composables seems better than the use of Mixins, but I’m not quite used to the convention of calling them useXYZ and having to remember to initialise them in ever component instance that makes use of them. That’s probably just because I haven’t used them much yet, though.


This one isn’t directly Vue’s fault, but with the new versions of ESLint, I have lost the ability to get linting errors in my editor of choice: Atom. I don’t want to switch to VS Code like the Vue Docs recommend, because that would only be yet another tool to get used to (and besides, I don’t like the look and feel of VS Code). So now I have to remember to run npm run lint periodically to make sure I haven’t forgotten a semicolon or inserted too much whitespace here and there.

It also seems like the default files that vue-create generates are incompatible with the AirBnB coding style-guide, which means I have to manually update nearly all the boilerplate files after scaffolding a project, which seems unnecessary. Which also reminds me that it seems like there are a lot more example files to delete after initialising a new Vue project with npm init vue@latest than when using vue-cli. That might just be a subjective impression though.


All in all, I’ve had much less trouble using this new way of developing Vue projects so far than I initially anticipated. There are plenty of things that annoy me here and there, but they are usually easily worked around or just things that I have to get used to again. I’m also sure that the tooling will continue to improve over time, I just hope Vue 4 won’t be yet another paradigm shift when it does finally release. 😅

I’m curious to see how the integration of PWA features will go when I get to it and might follow-up this article with one specifically around that topic if I run into any unexpected troubles or annoyances.

As always, thank you for reading! If you have any questions or comments, feel free to reach out over on Twitter, I’d be curious to hear your experiences on switching to this new way of developing Vue apps. Have a great weekend! 😊