The story of migration from Angular to Vue (Part 1)

Reading Time: 4 minutes


It was over two years ago when I joined Everli. Besides usual duties, I was given the tremendous opportunity to migrate the frontend of a complex e-commerce system from Angular to Vue. It’s this type of a challenge you wait most of your life as a developer to be able to use all of your past experience and build something new and as close to “perfection” as it can be.

The most crucial requirement, at that time, was to avoid big rollouts and make every release as much valuable and smooth as possible. Back then, It sounded pretty complex, but it was vital for the company, which was about to double the number of users in the next months. We were growing fast, and new markets were about to be conquered. With my buddy Nicola, we decided to take the small steps and take the pressure off our shoulders by replacing Angular with Vue bit by bit.

I loved the component-driven development way before Brad Frost introduced the Atomic Design concept. At various stages of my career, I tried to implement a components-first approach. The difference was, this time, it was not about adding something to the existing workflow. This time it was about building the workflow from scratch on top of the component library.

Solution – Go hybrid!

Since big migration was not an option for us (by big, I mean switching from Angular to Vue with one big release) – we decided to go hybrid. We left out most of the SPA logic on the Angular side (routing, session handling, etc.) and used Vue components as building blocks of each page.

We started with a new repository and decided to use Storybook to manage components. Storybook is an open-source tool for building UI components and pages in isolation. It allows to write component stories (which represents all component variants and possible behaviors), make snapshots tests, and gives the ability to mock API requests.

On the Vue side – we chose Vue CLI because of the built-in ability to create component library build.

With this setup, we created the first components, add units, snapshot tests, and shared clickable UI with the design team.

The new development flow was almost ready, and the only missing step was about connecting the component library with the current web app and make them communicate properly.

We needed to be able to get the data from Angular and pass it to Vue (API responses, routing state/params, etc.) and handle the emitted data/events by Vue on Angular side.
At that time, there was no open-source solution that would fit our needs, so we ended up with a custom directive. It was built on top of the ng-non-bindable directive and was responsible for creating a Vue instance and pass the Angular data to it.


app.directive('everliComponentWrapper', function() {
  return {
    restrict: 'A',
    scope: {
      everli: '='
    link: function(scope, element) {
      if (scope.everli) {
        if (window.everliInstance && !scope.everli.keepalive) {

        createVueInstance(scope, element)

createVueInstance = function(scope, el) {
  var loadComponents = function() {
    return scope.everli.components.reduce(
      function(prev, curr) {
        prev[curr] = window.everli.default[curr];
        return prev;
      }, {}

  window.everliInstance = new Vue({
    el: el[0].querySelector('[ng-non-bindable]'),
    data: {
      everli: scope.everli
    components: loadComponents(),
    methods: {...}

Directive usage

<div everli-component-wrapper
     'components': ['EverliStoreListPage'],
     'data': dataFromAngularController
     <div id="EverliStoreListPage" ng-non-bindable>

With this solution, we were able to load the Vue component library, pick one of its components, and use it as content for the Angular template. It worked like a charm!


Since the component library was stored in its own repository, we were able to work without any constraints related to the old/legacy project. We split components into two groups – components as building blocks and components as pages.

Each component contained:

  • required business logic
  • JSDoc comments
  • Storybook stories
  • unit tests for component and Vuex store (when present)
  • snapshot tests

With a couple of small adjustments, we ended up with a sufficient process to cover all our business and technical requirements and allow the onboarding of our new employees to be fast and confident.

But it wasn’t over – Angular was still there, responsible for routing – and it was slowing us down while working on new features. Every time we had to add/change routing, we were forced to work on two repositories and release both of them concurrently. It was time to introduce a new player on the field – Nuxt, which was about to takeover SPA framework responsibility.

What’s Nuxt?

Nuxt is an open-source and powerful Vue framework with a big community and is partnered by essential players in the IT world (Chrome, Netlify, Vercel). It comes with a modular architecture, outstanding performance, powerful defaults, and detailed documentation.

As the next step of our migration, we started moving all our routing definitions from Angular to SPA (Nuxt) repository, migrating session logic, and moving all components from our component library.

To follow Nuxt conventions, we moved pages components to the Pages directory, migrated Vuex modules, configured tests environments and Storybook stories. With all those changes, we were able to have a complete SPA experience just by running npm run dev. By porting Vue CLI into the repo, we could still generate a component library and use it with the current Angular SPA.

These changes allowed us to archive the component-library repository and start working on SPA on a daily basis, at the same time being able to generate component library from within the SPA repository. It gave us a boost and simplified the work, leaving us with only one step left needed – switching off Angular and replace it with Nuxt based SPA app.

to be continued…

Author: @pdrazewski

Leave a Reply

Your email address will not be published. Required fields are marked *