Wildcat runs behind-the-scenes. It is a pre-configured environment that handles server-side rendering and logic, leaving front end engineers to focus strictly on the client. It utilizes pragmatic, peer-reviewed dependencies that cover state management, routing, styling and dev tooling. Backed by Wildcat, work can immediately start on individual projects with no overhead distractions on libraries or frameworks. It consists of the following core packages:

react-wildcat is the application server

is the application server react-wildcat-handoff is the application client / server renderer

is the application client / server renderer react-wildcat-prefetch is an agnostic higher order component to prefetch component data

is an agnostic higher order component to prefetch component data react-wildcat-hot-reloader adds hot-reloading capabilities to Wildcat

adds hot-reloading capabilities to Wildcat react-wildcat-ensure is a wrapper for System.import that behaves like Webpack’s require.ensure

is a wrapper for System.import that behaves like Webpack’s require.ensure react-wildcat-test-runners manages end-to-end and unit testing with Karma, Protractor and Mocha.

Our framework attempts to solve a litany of architectural concerns, outlined across four core verticals:

The Application Server

Wildcat uses jspm and SystemJS to universally render React on the server and client. Using host headers, it resolves a user’s current domain and/or subdomain, lazily loading only what is necessary to render a given route. This technique allows us to maintain a monolithic repository, giving us the advantage of developing, running, and deploying multiple projects hosted across multiple domains based on a single application entry point.

Additionally, the app server handles data dehydration, prepping API data for client ingestion. It’s also responsible for ancillary tasks like request proxying, CORS handling and so forth.

In development, a WebSocket listens for static asset changes and hot-reloads modules as they change. You may be surprised to learn we also hot-reload in production. Using Kafka, our deploy pipeline publishes a notification of every static file change. The app server uses a Kafka consumer to listen for file invalidations and purges assets as they stream in. This allows us to publish static deploys without the need to bounce our app server. The server simply picks up the invalidation notifications, updates its in-memory module cache, and renders the updated module on the next reload.

Static Asset Management

One of our biggest challenges, static asset management was an architectural puzzle we debated for weeks. Prior to Wildcat, our decentralized deploy workflow revolved around minified, concatenated Webpack bundles. For each domain/subdomain, we generated a static asset bundle and served it from the target domain. This resulted in a high probabilty that modules would be duplicated across our domains. That is, if two separate domains depended on an identical module, that module would be downloaded once per domain. To put it in visual terms:

www.nfl.com -> moduleA -> www.nfl.com/bundleContainingModuleA.js

sso.nfl.com -> moduleA -> sso.nfl.com/bundleContainingModuleA.js

To solve this, we aimed to have a single source of truth for each shared dependency. We wanted the flexibility to deploy an individual module to one location and have it propagate across all our web applications. In Wildcat, we achieve this using a custom jspm + SystemJS fork that allows us to fetch modules on both the client and the server from a central destination:

www.nfl.com -> moduleA -> static.nfl.com/moduleA.js

sso.nfl.com -> moduleA -> static.nfl.com/moduleA.js

On the DX front a local static dev server listens for incoming module requests, locates the requested source ES2016 module, transpiles the module and serves an ES5 version back for client/server ingestion. One major advantage of on-the-fly transpilation is a lightning-quick dev mode boot time.

In production, source modules are transpiled on deploy and served as static ES5 modules through a CDN provider. Third-party modules are gathered, minified and bundled. Third-party modules shared across two or more domains are grouped into a common bundle, while domain-specific bundles are generated and served as needed.

The Client

The client render stack is a near copy of the app server. Using jspm + SystemJS, we leverage lazy loading techniques to resolve the current domain and route path, hydrate any API data retrieved from the server, and render the result on the client. Here’s a quick glance at our JavaScript stack:

Route-based lazy component loading with React Router + jspm

Radium for inline styling

Helmet for managing your document head

React Metrics for tracking analytics

Store-agnostic Prefetching for client data hydration

In development, a WebSocket listens for static asset changes and hot-reloads modules as they change. Production changes are not hot-reloaded on the client.

Dev Tools

As important as static asset management is, we also took the opportunity to improve our dev tooling with Wildcat. To ensure code quality, it is critically important to cover our code with unit tests, integration tests, and code coverage analysis. Our testing stack consists of Karma for unit tests and Protractor for e2e testing (turns out it works great for React!). Mocha+ Chai are used in both. We also use ESLint for static code analysis to catch potential bugs and to keep a uniform coding style across our web projects.