Migrating Juniper Square to React and GraphQL

Federico Torre
Juniper Square Engineering
4 min readJun 7, 2021

Juniper Square has evolved significantly as both a company and a platform since its founding in 2014. The first few years were dedicated to truly understanding the problem space, the opportunity, and our customers in order to build a comprehensive and scalable solution. Within a few years, the Juniper Square platform was supporting hundreds of enterprise customers and millions in recurring revenue.

Origins

Leveraging feedback and insights from our beta partners, our founding team built the initial version of our platform.

Our core offering — the investment management application and the complementary investor portal — was originally built using a traditional server-side-rendered architecture with a proven and well-known stack consisting of Python with Pyramid, Jinja, jQuery, Bootstrap, Postgres, and Celery.

Given our strong growth over the last seven years, we’ve sought to iterate on and evolve our technology alongside our company and business.

Introducing React and GraphQL

In 2019 we began an effort to modernize our technology stack, introducing React with Typescript and GraphQL. New product areas, such as our unified investor portal, have been built exclusively on this stack. Upgrading our existing products, however, required deeper consideration.

As a company, we’re always looking to serve our customers. Pausing all feature work to exclusively work on rewriting existing functionality in a new stack wouldn’t work for us. Given our strong growth and expanding market share, the opportunity cost would be far too great.

That being said, we understand the value of modernizing our stack and the benefits it brings around developer enablement.

We were able to strike the right balance between improving our technology and delivering value by integrating React, and therefore GraphQL, into our existing stack in a seamless, developer-friendly manner.

Pillars

Leveraging webpack’s asynchronous loading, we defined a pattern for injecting React components into our server side rendered pages. These injected React components and the associated entry points into the legacy application are known as pillars.

Code samples are simplified for illustrative purposes.

The following code sample shows how a pillar would be added into a Jinja template.

Behind the scenes, the Jinja macro is injecting an inline script into the server-side rendered html. On the client side, during the page load, this script executes a function that has been exposed to the window, __jsqRenderPillar__.

This__jsqRenderPillar__ function is exposed by the previously-loaded JavaScript bundle.

Focusing on that JavaScript bundle, the entry point is shown below:

Asynchronously load the application

This entry point loads the application and defines __jsqRenderPillar__ on the window.

The application is a thin layer that looks to asynchronously load a particular pillar and ultimately render it.

The pillar registry reads the file system to automatically generate a list of valid React components.

Retrieve the pillar and render the component

The registry returns a manifest of all the pillars, with each having simple imports such that the actual pillar code is only loaded asynchronously, on demand.

Thin import file to asynchronously load a component

Considerations

We did have to make some trade offs regarding performance and convenience.

Loading JavaScript bundles asynchronously is beneficial to keep the total size of assets sent over the wire to a minimum, fetching only what is needed when it is needed.

The loading experience, however, could experience delays due to the sequential loading of asynchronous dependencies. For example, the first file which contains a reference to an async component, must finish downloading, before the code to request the async component executes.

Considering the pros and cons, while also giving adequate weight to the convenience and developer efficacy gains, we decided the simplicity in the interface outweighed the costs.

Closing

This solution enables developers to build new features, anything from a small component to a full page, using React and GraphQL in our legacy stack.

As we take on feature projects throughout the application, teams are taking on bite-size projects to migrate existing functionality over.

As areas of the application become fully converted, we will be breaking them out completely and into their respective single page application.

--

--