Until a couple of years ago, the front-end of our web application for Phoenix at Druva was written purely in jQuery. But with the growth of the application and a number of new features being continuously added, we started seeing some challenges in terms of complexity and scaling.
Some of the challenges that we faced with jQuery:
- Slowness and performance issues when user interaction increased
- Difficulty in maintaining the growing codebase
- Code reusability to maintain UX consistency across different products of Druva
So our team started brainstorming new solutions to our front-end architecture. After evaluating a number of different frameworks, we decided to go with React to take advantage of:
- Independent and reusable components, which are helpful for maintaining UX consistency by reusing components
- Virtual DOM (Document Object Model), which updates only the part of the DOM that has changed, not the whole DOM; it overcomes page slowness with increased user interactions
As Phoenix is continuously changing and already in use by a large number of customers, a complete rewrite all at once was out of the question. We decided to start migrating module by module. New features were added in the new React module as an ongoing part of the migration. For older modules, we kept adding support in jQuery.
Strategy
We brainstormed quite a few ideas about how to plug in React in our existing jQuery code, such as:
- Keeping two separate apps for jQuery and React.
- iFrame-based approach — An iFrame (short for inline frame) is an HTML element that allows an external webpage to be embedded in an HTML document. Unlike traditional frames, which were used to create the structure of a webpage, iFrames can be inserted anywhere within a webpage layout. In an iFrame-based approach, the parent page could still be in jQuery, but individual components within the page could be created in the separate react app. For example, an existing user details page that is in jQuery could have child sections like basic user details, charts, etc. These child sections could be built using React and injected as an iFrame in the parent user details page.
- Keeping a single app for both React and jQuery and rendering corresponding pages based on routes. Routes are the paths to navigate to a page in an application. For example — if you are in /home currently, which can be an existing jQuery page or route, and if you click on a link to navigate to /home/details, it can be a new React page or route.
Of these approaches, the first approach had some drawbacks, like loading the whole app (resources, etc.) on change of routes. In the second approach (iFrame-based approach), we needed to keep two different apps (one for jQuery and one for React). Apart from general limitations of using an iFrame, such as communication between cross-domain iFrames, handling extra scroll bars, etc., communication with an iFramed application becomes cumbersome. Also, there are some challenges like security risks, usability issues, and SEO problems with iFrames.
So we decided to go with the third approach as our application was already using hash-based routing for rendering jQuery code. Also, we wanted to listen to the same hash change event in jQuery as well as in React app. This helped us keep both the React and jQuery pages separate.
In addition, we had to decide on how we would incorporate the new requirements along with existing code to be rewritten. With the idea of keeping jQuery and React separate, whenever there was a requirement of a new page/route, we preferred writing it in React, but if it was a change in an existing page, we made changes in jQuery code only.
After deciding upon the strategy, we started with keeping the jQuery application as the entry point and inside that we created a mount point for React.
A snippet containing the starting point of the application (index.html) is shown below: