Introduction
At Studyportals, we have around 20 microservices running on Vue.js (commonly known as Vue). Ever since we started working with Vue, we have been using version 2. Vue 3 has been out for a while now. This year, in 2022, we decided that we would pick up the migration of most of our microservices to Vue 3.
Up till this moment, all our Vue 2 applications ran without problems. So, why did we decide to migrate any of them? Although we are not in dire need of any of the new features Vue 3 offers at this moment, we still decided to migrate most of our applications.
The reason for that is that we want to ensure our codebase stays maintainable and, with that in mind, it's important to not lag behind on older versions. This way we can make sure that we can optimally keep benefiting from our good page speed, and overall development efficiency. Vue 3 is the latest stable version, fully built with Typescript at its core, allowing us to build even more performant and high-quality applications.
In this blogpost, I would like to share what our approach is to this challenge of upgrading tens of thousands lines of code across hundreds of components spread over about twenty microservices.
Our infrastructure in a nutshell
Several years back we decided to utilise new reactive JS frameworks for new applications that we build. There are plenty of good frameworks out there, but we chose to build our applications in Vue. Vue came across as a fast, light-weight, reliable, and easy-to-use framework that would be around for many years to come.
We opted for a microservice infrastructure, as migrating all of our old code to Vue would not be worth the effort. This means that the foundation of our websites is still in place, running on the older architecture we have had for many years. The newer applications inside the websites that we build are able to run stand-alone and can be injected onto any page.
An example of one of our pages, on which multiple microservices can be identified.
We use a service called Bob, which is our page compositing and lay-out service. It helps to integrate microservices on our websites in a structured way. Additionally, Bob ensures that, when multiple microservices run on one page, shared dependencies are only loaded in once. The same goes for the core Vue code that is the same for every microservice.
Making a plan of approach
In the last months of 2021, we started to look ahead to the next year and consider which technical challenges would fit nicely if picked up as part of our strategy for 2022. After all, we strongly believe that, at all times, a bit of time should be dedicated to constant maintenance and innovation. It is necessary to make sure we stay in control of the applications we build.
Vue 3 was one of the topics that was on our radar. Since it had first come out, we had kept an eye on developments surrounding this new version. The core packages necessary to use Vue 3 had been published and were out of beta at this point. This meant that it was a good moment to dedicate time for the transition to Vue 3.
We knew that a migration in some shape or form was coming up. And so, we used Q4 of 2021 to do the necessary research that would allow us to formulate a plan for this big change.
Like any plan, our Vue 3 migration plan was soon defined as a couple of high-level steps:
- Research
- Deciding on strategy
- Take care of migration
- Clean-up
Research first
We read more about Vue 3 so that we could discover any opportunities or limitations that we had to be aware of.
Additionally, we took a closer look at each of our applications and pinpointed details such as the pages on which they run, the Vue syntax used for components, the Webpack setup used for deployment, and additional dependencies we had to be aware of. We made an overview that allowed us to compare all of our microservices.
The overview that allowed us to compare our microservices to support decision making.
Deciding on strategy
We took all of the information we had gathered and discussed it. We made sure that at least one representative of each scrum team was included in the discussion.
This way, we could easily agree on some important decisions, such as which products should be migrated, and in what order to ensure that the impact on page performance would be minimal.
The main decisions made were the following:
One-page and internal microservices first
Microservices running on just one page would be migrated first, along with some microservices that only our internal users and clients use. But, why did it make sense to tackle those first?
Our Personality Test is a simple microservice and runs only on one page; therefore it was picked up first.
There are no overlapping dependencies that can be shared between Vue 2 and Vue 3 applications. So, regardless of Bobβs efforts, more kilobytes will be loaded in on a page with Vue 2 and Vue 3 applications running side-by-side.
So, by last migrating those microservices that run on many pages, including core landing pages, the timeframe during which the performance of those pages is negatively impacted is kept to a minimum.
For about half of our microservices, a specific migration order was already defined at this point.
Some microservices not migrated
Microservices that are not actively developed on and are not loaded in initially do not impact page performance much. Hence, we decided not to migrate those applications, as the needed efforts would not be worth it.
Component syntax
When migrating to Vue 3, we would configure our components using the Composition API
and the so-called Vue Class Component
setup. Later on, this decision changed to: only use the Composition API in Vue 3. A bit further down this change of plan is clarified a bit more.
A better defined plan moving forward
With all our scrum teams on the same page and the most important decisions made, the broad migration plan mentioned earlier could now be made more specific. The taking-care-of-migration step could be further specified as follows:
Prepare tooling around microservices: Resources, such as NPM packages developed by Studyportals, should be ready to be used in Vue 3. More details are mentioned on this further down.
Kick off with a first application: It should be a relatively small and simple microservice, so that additional time needed to get familiar with Vue 3 syntax does not result in a huge scope and a migration that takes many weeks to complete.
Continue with a second application: Unlike the first one, this one should be big and challenging. After having gotten acquainted with Vue 3 by migrating the first application, it is useful to now pinpoint the biggest remaining bottlenecks that need to be taken into account for the migration of other microservices.
Diverge: Get more people involved, so that it is possible to migrate multiple microservices alongside each other. In our case, the first two microservices would be tackled by the same scrum team. So at this state of the migration, all the insights gained could be shared with other scrum teams. It is important that all of the front-enders in the company get involved and get acquainted with Vue 3. After all, they should all be able to work with it and can help to make the overall migration go faster.
The Enrolment Review Tool is our biggest, most complex, internal microservice. So, it was migrated second.
Takeaways
With any big project, you can have a well-thought-out plan and still encounter some unforeseen issues and challenges. You can also stumble upon new opportunities that are worth exploring. While attempting to migrate the first few microservices, we also had a few unexpected findings. Some of them are worth mentioning here as takeaways.
Migrating in-house-built NPM packages
We use Webpack to build and bundle our microservices. Before we started the migration to Vue 3, we were using Webpack 4. We figured that, while we are upgrading Vue, we might as well upgrade to the latest version of Webpack as well: version 5.
What we did not foresee however is that this Webpack-upgrade also impacts pieces of Webpack-dependent functionality we develop in-house and make available for our microservices as NPM packages. This meant that extra work was needed to upgrade additional dependencies that we initially did not think of.
Some NPM packages that needed to be upgraded, which are used in microservices for various purposes.
Vue Class Component not working
In Vue 3, there are two main ways to configure your components: the Options API
and the Composition API
. In Vue 2, we used another way which is known as Vue Class Component
. This setup depends on a package that is not developed by the Vue core team. Initially, it seemed that the maintainer had also got his package working in Vue 3.
So, we thought we could limit our migration efforts somewhat by continuing to use Vue Class Component
for some microservices in Vue 3. We had a working proof of concept, but when we tried to migrate the first microservice in this way, it did not work. The reason for this, as we found out, was that the latest minor version of Vue 3 was not supported anymore by the package.
We concluded that it would be best not to make use of this unstable setup any more and move over fully to the Composition API
. This is always the risk when you rely on packages that are not well-maintained. For our migration, it meant that more time would be needed than we initially expected.
Replacing non-essential dependencies
One of the opportunities we recognized was that we could fairly easily build the functionality of dependencies such as Vuex
and Vue-Router
ourselves with the features that are available in Vue 3. We figured that the code needed for that would be small and simple enough, and that it would fit nicely with the code changes we needed to make anyway to move to Vue 3.
The advantage of it is that we have less dependencies to worry about and that we can reduce the bundle size of our applications.
Conclusion
At the time of writing this article, five microservices are migrated with another two in progress, and the rest still waiting to be picked up later in the year. So far, we are quite happy with how it is going, and we are still able to follow the strategy we had initially defined.
The aforementioned issues, challenges, and opportunities caused some delays for the migration of the first microservices, but none major enough to put the planning that we had in mind for the year in jeopardy. The insights gained will surely help speed up the migration of microservices that are up next to be migrated.
We are optimistic and excited to see how this big migration project will progress. Hopefully, at the end of the year the core parts of our codebase will be up-to-date with the latest technology, making it therefore maintainable and sustainable for many years to come.
Update (March 2023): I wrote a second blogpost, A migration to Vue 3: part 2. If you're interested how the rest of the migration process turned out, go ahead and check it out!
Top comments (0)