After 5 years of developing our application, VTS decided to move on from AngularJS and migrate to ReactJS for our UI layer. After countless complex features, UI interactions, and developer tools created in AngularJS, although we are sad to see it go, we have decided that the Angular ecosystem is no longer right for us. If you want to see more about what went into that decision, feel free to check out [this blog post](TODO: insert link here)! There I into detail about why we felt AngularJS wouldn't fit our needs going forwards.
Now comes the fun part: actually migrating our application to React! This post goes into the different steps and decisions we will take into consideration to get to that goal, and act as a guide for us (especially myself 😅) for when we are going through this migration. Hopefully, this plan will allow us to be able to stay on track, provide digestible chunks of work, and allow us to try to peek around corners and identify any potential pain points in this complex migration. There is definitely a lot in here that is pretty specific to VTS, but maybe you guys empathize with some of these pain points and this guide can help you along the way! Let's get into it.
- Create new folder structure
- Identify discrete "feature slices"
- Migrate first POC feature slice
- Train your team!
- Migrate feature slices
- Convert services
- Convert routing
Folder structures are important. They can convey intent of code, easily group business logic with associated styling and tests, and can serve as a representation of your layers of abstraction. While we were working in our angular codebase, we didn't have a great sense of what files should go where. We generally tried to keep it split up by feature, but that didn't always make sense. Sometimes there were services or utils that lived next to components, other times components and directives were kept in separate directories. This was okay, but we felt as if it was unclear whether or not a piece of code was intended to be shared, for whatever reason. As such, we found that it could be beneficial to split your application up into these folders:
- angular-ui // keep most of our old code the same, and throw it all in here
- react-ui // new folder for any react UI components
- components // shared components meant to be used anywhere. We consider these all part of our design system
- layout // one-off layout components
- vts-core // vanilla JS objects, functions, and classes
- services // data services to interact with our API
- utils // helper functions to isolate and reuse business logic
This specification helps us not only easily identify if a piece of code is intended for reuse, but also allows us to easily import shared modules as well, since now all shared modules live next to each other. The first step of this pattern was
Another key aspect of the migration is how we judge what to migrate when, and what chunks of work to do together. In order to do this, we came up with the concept of migrating by "feature slice" (thank you @nirkaufman for this idea!) Basically, this entails splitting your application into small bytes (aka feature slices) that can be migrated one at a time, while still maintaining sensible container/view boundaries between components. Coming up with these boundary points also helps our teams determine how long the migration will potentially take, and how large of a chunk it will be.
For example, let's say you're trying to migrate Github's website to React. Given this page:
You may decide that your feature slices could be the left gutter (where you can split "Your teams" and "Repositories" into different slices), the main center area, the right gutter, and finally the nav bar. These are distinct areas of the application that don't require much communication between each other, and can be migrated in isolation, separate from one-another.
Another caveat to these feature slices was that we wanted to be able to halt development on that feature slice while it was being migrated. This was to avoid potential regressions caused by migrating asynchronously, and also helps encourage people to migrate in small chunks at a time.
After identifying your feature slices, now it's time for us to finally write some React code! While we were going through the process of evaluating our feature slices, we also kept in mind what design-system components are used within each page. For our first POC feature slice, we tried to pick the slice that was the best balance of having a bunch of design-system components, and having a bit lower traffic. This would allow us to mitigate risk, while using this as a jumping off point for our internal component library! We found that we were able to knock out nearly a quarter of our design system components with that first feature slice, so picking one that has that balance can greatly help moving forwards.
Now it's time to train your whole team! Up until now, it has only been one team doing investigation into migration strategies, picking out patterns you want to use, etc. From here on out, your entire team will be coding in react, so this is when you want to train your whole team on both React in general, but also how your company chooses to operate. There are many decisions to be made when writing a React application, but if you can stay consistent on patterns and best practices, your team can act more cohesively together. This is the best time to train up your team, as to help reinforce the knowledge learned from the training.
Now to get into the hard stuff. For the first couple feature slices, we found it very useful to have one dedicated team go through a few more feature slices and build out that design system. Though that step isn't strictly necessary, for VTS this was particularly useful since we already knew what components we have in our design system. Some general guidelines to follow when migrating components are:
- Keep decomposing your components. You're creating a new React application; you don't want to end up with a bunch of AngularJS-like components written instead in React!
- Start small. If you can do simple functional components as a first step when diving in to a feature slice, it can help greatly reduce complexity of your changes.

