Thriva’s front-end

Background

I’ve been working at Thriva as a front-end engineer for just shy of two years. We’re building a personalised healthcare service to change the way people approach their health.

We’ve created products for people to understand what’s going on inside their bodies — allowing them to improve their health today and catch any small issues before they become big issues.

To do this we use a lot of modern tech. Let’s take a quick look at what we’re using to build our front-end applications.

Vue

At Thriva we love Vue. All of our front-end applications (apart from some old Rails views — Thriva was originally a monolith Ruby on Rails application) are built using Vue. Even our internal style guide is a Vue app and our internal docs use Vue Press — we’re all in on Vue.

We scaffolded our apps using Vue CLI 3, with Pug as our templating language and Stylus as our CSS preprocessor. We try to stick as closely to BEM methodology as possible and have Eslint to keep our coding styles in check.

We use Axios to connect to our Rails API. Plus some additional packages to help display our complex data sets back to our users like:

We also use a lot of ES6 and ES7 features like Async/Await. Babel compiles these newer features down to IE11 compatibility. Webpack then bundles everything together, performs code splitting and tree shaking — so we’re serving highly optimised bundles to all of our users.

Nuxt

Nuxt is a framework for building universal Vue applications. Our marketing website thriva.co is a progressive web app built using Nuxt. This allows us to use server-side rendering and service workers for an offline experience straight out of the box.

Nuxt has helped us to build a website that is highly performant and provides a great user experience that’s optimised for SEO.

Vuex

Vuex is a state management library that ensures state can only be mutated in a predictable fashion. It’s the central store for all the components within the application.

We use Vuex for all of our Vue applications. As the features of our apps grew, things quickly became bloated — so we adopted a modularised approach. Each feature now has its own state, mutations, actions and getters to manage its own concerns.

We also have a generic resource module that handles getting and setting data via the API, as well as some global functionality like loading and error states.

A nice feature of Vuex is that all modules can access each other’s internal data if required — which helps keep the code nice and DRY.

Code structure

Vue doesn’t provide much direction with regards to structuring large, complex apps like ours. So we’ve tried a few different approaches and have developed a structure that includes four different types of components:

  • layouts
  • views
  • connectors
  • functional components

Layouts

Layouts are simple components that provide reusable general styling and configuration. These determine a few high-level settings — for example, the version of navigation that should be used.

Views

Views are more specific to a route or a feature within the application. They act as the parent component and trigger a Vuex action to get the initial data from the API when the page is first loaded. This data is then passed down to its children — connectors and components.

Connectors

Connectors wrap functional components and are responsible for ‘connecting’ to the store in Vuex. This means they can get data from state and getters. They also call actions to trigger API calls and mutations to trigger state updates. This data is passed down to child components, allowing them to display their part of the UI or perform specific functionality.

Functional Components

We try to keep our components as functional as possible. They don’t keep any of their own internal state or interact with Vuex or the API directly. Everything they need is passed in via props. Their purpose is to use the data they were given as props and display that in the UI. They also emit events that the connectors use to perform Vuex/API communication on their behalf.

We’ve found this approach to be highly scalable and predictable as each component level has a defined purpose.

Thriva-UI

At Thriva we take a design-led approach to building our front-end applications. We want to ensure design consistency across the board and have a shared component library between our apps to achieve this.

Thriva-UI is our shared component library that’s deployed as an NPM package. This is where we build all of our atoms and molecules that are used across the rest of our applications. This module is also responsible for our:

  • Foundation XY Grid,
  • base typography settings,
  • brand colours,
  • and general code or helpers that we would consider global.

We run Storybook inside Thriva-UI as a quick way to view all the components we have and play around with the different behaviour of each. We also run jest inside Storybook so we can gauge the health of each component as we interact with them.

Toggling through the different component states of Thriva-UI in Storybook

Jest + Cypress

We use Vue Test Utils with Jest to unit test all of our functional components, as well as Vuex actions, getters and mutations. We have Cypress for our end-to-end testing.

Github + CircleCI + Reviews + Heroku

We use Github for version control and to kick off our continuous integration. Code reviews take place in Github and CircleCI runs the unit and end-to-end tests.

Once all the tests are passing we deploy the branch to our staging environment on Heroku — where our product designers do their design reviews. It gives them a chance to find anything that doesn’t look exactly like the designs and to find any UX issues before they’re found by customers.

This isn’t the first time the designers are seeing their designs coming to life in the browser. They’re very involved in the build process and are viewing the build on our dev machines as we code. The purpose of the design review is to give everything one last check.

If everything thing is looking 💯 the final step is to deploy to Heroku 🚀.

Come and join us

If you like the sound of the tech we’re using and are keen to work as part of a small team (with a bunch of awesome people solving big problems), then get in touch or head over to our careers page to view all the positions we’re hiring for.