Moving PRIMUS from React and Redux to Angular
An 18-month migration alongside feature work: consolidating the PRIMUS frontend, reducing load times, and living with two frameworks during the transition.
PRIMUS was the premium recruitment platform at Navigos Group. I joined as its sole frontend developer. The frontend consisted of several React applications written in plain JavaScript, connected through tangled Redux stores. Initial page load took 7 seconds, and switching between features took about 3.
Over about 18 months, I consolidated those applications into one Angular app while continuing to ship features. Initial load fell to under 1 second, and navigation between features took under half a second.
Choosing Angular
The existing implementation lacked TypeScript and module boundaries. Its shared global state was difficult to understand. Those were problems with how we had built the React applications, so changing frameworks alone would not solve them.
I chose Angular because its modules, services, and dependency injection gave me a structure to work within. As the only frontend developer, I also wanted to spend less time evaluating libraries. Having routing, HTTP, forms, and RxJS available reduced the number of separate choices I had to make.
Migrating alongside feature work
A full rewrite would have meant months without shipping. I moved the application over as work reached each part of it:
- New features shipped in Angular from day one.
- I extracted shared functionality into Angular services as I touched it.
- I rewrote legacy React screens when they needed significant changes.
- I replaced the Redux stores one at a time, starting with those causing the most bugs.
I completed 89 Jira tickets on my own during the roughly 18-month migration.
Adding usage tracking
Product managers had no usage data. They prioritized features using customer complaints and their own judgment, so I built an event-driven tracking system.
Components could register handlers to modify an event’s payload before it was sent. For a page view, the active module could add the candidate pipeline stage, the search component could add its Boolean query, and another handler could supply the user’s permission level. The tracking system did not need to know the details of those components.
Handlers could add, modify, or filter events from anywhere in the application. This gave product managers usage data for the first time.
What I’d change
Angular worked well for this project. If I were starting it again, though, I’d use SvelteKit or Next.js. The ecosystem has changed, and I find Angular’s decorators, modules, and dependency injection configuration add overhead when I’m working solo.
I’d also push for a focused 6-month rewrite with a feature freeze on the legacy application. Running React and Angular side by side was the most painful part of the gradual approach. Continuing feature work made the migration possible, but stretched that period to 18 months.
PRIMUS was eventually discontinued for business strategy reasons. The application was working well when that decision was made.