David De Vargas
Micro-Frontend Migration Approaches: From Nuxt 2 to Nuxt 3
Photo by Simon Berger on Unsplash
Reasons
There is a new version of Nuxt available (Nuxt 3) that is handier and requires less configuration
Nuxt 3 requires Vue 3
Both of these improve DX and maintainability over time
Last and more important: Vue 2 will no longer receive support from version 7
Content
The Architecture
The Problem
The Strategy
The Workflow
Other Considerations
The Architecture
Let’s see what we have:
Layer 1 or Main Layer, Layer 2 or Module Layer, and Layer 3 or Shared Layer
This is a pretty common micro-frontend distribution, consisting of 3 layers:
Layer 1 or Main Layer exposes modules through a single window to the user.
Layer 2 or Module Layer contains different domains or modules from our application, payments, blogs, and so on.
Layer 3 or Common Layer is responsible for sharing reusable code within modules. Here we can find our Design Systems and cross-module utilities, for example.
In our particular case, our main repository exposes modules to the rest of the world and contains our internal APIs using Vue 2 and Nuxt 2, the other repositories are normal Vue 2 SPAs (Single Page Applications).
We use Module Federation (MF), to share and consume code between repositories using a “remote” and “host” pattern where the remote exposes code, and the host uses it as if it were from itself.
The Problem
Although Module Federation discloses a huge potential it also offers a weakness: it leads us to a tightly coupled micro-frontend architecture:
If we update a common dependency between any repository we could break the whole app 🫠🤯
This is true especially when using different versions of Vue as we move from version 2 to version 3.
The Strategy
So let’s see the options we have:
Expose components in the remote as Web Components, so the host receives it as native and framework-independent code.
Upgrade to Vue 3 and use a compatibility package that supports Vue 2 code inside of it.
Web Components Advantages:
make it easier for future updates not having to write Web Component configuration once again
allows upgrading repositories in Layers 2 and 3 without a specific order
allows using different frameworks if needed
Although the first option sounds promising, components lose their styles when we share web components made on Vue 2 (See example
Vue 3 app supporting Vue 2 code using a compatibility package
Note: Vue 3 solved the styles problem and this option shouldn’t be discarded for future upgrades
That being said the process should be divided into 2 stages:
Stage 1
Use the compatibility package in every repository from top to bottom
Use the compatibility package and fix errors in Layer 1
Use the compatibility package and fix errors in each repository on Layer 2
Upgrade repositories in Layer 3 to Vue 3 (doesn’t require compatibility package)
Stage 2
Upgrade the repositories from bottom to top to Vue 3 style and remove the compatibility packages once it’s not required
Upgrade each repository in Layer 2 and remove the compatibility package
Remove the compatibility package in Layer 1
The Workflow
At the same time we work in the migration process we should allow a continuous workflow for other teams to work on their normal tasks, once again we have 2 options:
make the migration inside the current repository through a new branch
make a new repository and migrate progressively our code
First Approach
Advantages
Doesn’t require building a new infrastructure because we are using what we have
Disadvantages
as other teams introduce features we are prone to invest a decent amount of time in resolving conflicts when we pull them to our migration branch
we test if it works only when we merge our branch at the end
we are isolated from other team’s work
In summary, it’s suitable for small projects: when dependencies are few and teams are small.
Second Approach
Advantages:
when we move code to the new repository we remove it from the old one reducing the number of conflicts
increase collaboration: other teams can accomplish their tasks in the new repository
we quickly ensure that our new repository is working because we are using it in parallel with the old one
Disadvantages
requires a reverse proxy to point to the old or the new repository
requires building a new automatic pipeline for the new repository
developers should use 2 repositories for the same project
In summary, it’s suitable for medium to large projects: when dependencies and teams are many.
In our case, we are multiple teams working through the whole architecture and we already have a reverse proxy implemented, so the additional effort would be building a new pipeline for the new repository, and for that reason, this is our way to go.
Other Considerations
Bundler
We use Webpack 5 in all our repositories but at this time the information on the web is scarce on how to use it in a Nuxt 3 app. Because Vite is the default and offers a better Developer Experience we choose this one.
Node Version Update
We are currently using Node 14 but Nuxt and Vue 3 require version 16 or higher, we are going to use version 18.
Conclusions
As we are a medium size team and we use a lot of dependencies within our app we decide to:
Use a compatibility package to update our code
Create new repositories to migrate progressively and collaboratively
In the process upgrade our node version and replace Webpack with Vite
Build Apps with reusable components, just like Lego
Bit
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:
Learn more: