Welcome to the VA digital services platform frontend overview. The goal of this article is to provide a high-level overview of our frontend architecture to get you oriented with the vets-website and content-build repositories.

The overall architecture of VA.gov is comprised of an API backend written in Ruby on Rails (vets-api) and a static frontend, written in HTML, CSS, and JavaScript (vets-website). There is no server-side rendering or processing of the frontend. The build process compiles everything into static resources that are served to users.

Content build process

The build process has two primary functionalities that it processes: static content pages and JavaScript applications. Most of VA.gov consists of content that lives in Markdown files and the Drupal CMS, and is converted into HTML in the content build. There are shared templates and other enhancements to make this content easier to structure.

The content build process is controlled by a tool called Metalsmith, which is a pluggable Node.js static site generator. In general, everything in Metalsmith is a plugin, so if you're looking for specific parts of the build process, expect to view a plugin or two. We use Metalsmith because it's flexible and JavaScript based, making it easy to integrate with the rest of our tools.

JavaScript applications

JavaScript applications are the other type of functionality on VA.gov. These applications are written in React and Redux, and live in the src/applications/ directory in vets-website. For each application, you will find a manifest.json file that contains application specific information, as well as an entry in the content-build/src/applications/registry.json file. manifest.json files are used by Webpack in the application build, while registry.json is used by the content build. See Creating a new application for more information on the difference between manifest.json files and the registry.json file.

In an application’s manifest.json file, you'll find the root URL of the application, which you can use to navigate to on the website. These applications usually have client-side routes, so opening the root URL may allow you to click on links to other pages that are fully client-side.

If you're a developer, most of your time will likely be spent working on a React application. We use React because it's widely used by frontend developers, and provides a good balance of performance and approachability. We also use Redux to manage application state because it's commonly used with React, and suits the needs of most applications on VA.gov. We use React Router for client-side routing, and Webpack as a build tool, both of which are the de facto standards in the JavaScript world. For styles, we use Sass, and for dependency management we use Yarn.

Design system

You’ll also find that our visual components and site-wide styles live in an external design system. The VA.gov Design System is based on the US Web Design System, with some additional modifications by our team. As part of that design system, we provide a set of React components covering common patterns that get published to npm. You'll likely use these components to make your applications accessible and consistent with the rest of VA.gov.

Routing for React apps

Production

The production deployment of vet-website consists of static CSS and JavaScript assets that are deployed to an Amazon S3 bucket. We have an Nginx web server that serves those static assets and does some extra route handling for our single-page React apps.

React applications have a single entry page created by the content build, and a special Nginx config entry. Each of the React applications listed in that config are standalone single-page apps. For each of the URLs listed in the config entry, the Nginx server routes anything that starts with that URL to the static page at that URL, instead of trying to find a content page for a client-side route with the app. See the example below for a step by step view of that process.

When that page is loaded and the JavaScript bundle is downloaded and parsed, React Router sees the original route, removes the base URL specified in the entry page from the route, and routes to the page configured in the routes for the React app.

In summary, Nginx routes different URLs to the same static entry page, and React Router renders the correct component based on the route configuration on the client-side.

Example

Here's an example using the claim status application:

  1. User opens va.gov/track-claims/your-claims/2344/detail

  2. Nginx serves va.gov/track-claims/index.html, because /track-claims is configured as a React application

  3. In the browser, the JavaScript bundle loads and React Router sees a URL of /track-claims/your-claims/2344/detail

  4. Since React Router has a base URL of /track-claims, it runs its routing logic on /your-claims/2344/detail, and renders the appropriate component for that URL.

One other thing to note is that links that use the <Link /> component or the router object in the React app use the history API to change the URL without reloading the page. React Router listens for these URL changes and renders the right component for you. This is why you have to use <Link /> and not a regular <a> element, which results in a page refresh for the URL you're trying to link to.

Development

Locally, we've configured the webpack-dev-server to do the same redirects as Nginx, however they are duplicated in a few places:

You will need to the Nginx config entry when creating a new React application.

Architecture details