In the last article we discussed things like infrastructure, build systems and code quality tools. This time we’re going to discuss the materials we’re using to build the house, which means we get to talk about every frontender’s favourite topic: frameworks.

Before we start, it’s important to set out the constraints we have:

We’re going to build a client-side rendered platform

The platform is feature-driven, not content-driven

We have to build a team from the ground up

Given these constraints, it’s obvious we need to pick something that is designed for client applications, is popular, well-maintained, and has momentum. Out goes Polymer (web components), and Meteor, Ember and Vue (especially given the fact we’re in the Netherlands). The two most viable options left are Google’s Angular-not-1.x and Facebook’s React.

Now, smarter people (and less smart people to be honest) have written very detailed comparisons between Angular (a framework) and React (a view library). I’m not going to go into that other than this: for me personally, Angular would have seemed a logical choice — when I started this job in November, I had worked on an Angular 1.x app for four years straight. A couple of reasons why I (so YMMV) didn’t, and went for React:

React is a better match for functional programming

React is easier to learn (yes, that’s partly because it is just a view library)

React has more momentum

But the main reason might have been the fact that all the interesting ideas seem to come from the React ecosystem — things like Relay, snapshot testing, co-located styling, Redux, and many more. Because of the fact React is focused, it leaves enough space for innovation (that’s also a bit of a downside, it’s not an easy task to set up a React stack for a large platform).

React: A library for building user interfaces. React allows us to build components, and then compose them to build a tree. That tree is your user interface. The mental model is actually quite close to that of HTML elements and the DOM:

A snapshot of ant.design, showing React Components intertwined with HTML output

At its essence, a component is simply a function that you call with data, and it returns HTML (or rather, an abstraction of HTML) mixed with other components. Here’s a simple example:

var MenuItem = function ( props ) => {

return <li>{props.label}</li>;

};

That funky syntax you see on the second line is not valid JavaScript today, and probably ever. It is something called JSX — nothing more than syntactic sugar for React.createElement , which is used to create instances of your components. Think of it as using innerHTML instead of document.createElement to construct interfaces. This abstraction also allows us to easily do server-side rendering: you can use this element tree to render to any target, including HTML. It’s the same construct that allows React to render native applications, or to crazy things like canvas .

This allows us to write declarative components instead of imperatively updating our interface, resulting in code that is better to understand, and a more stable application. Here’s more on that by Tyler McGinnis: https://tylermcginnis.com/imperative-vs-declarative-programming/.

By now, you’ll have noticed that React components blur the line between JavaScript and HTML. Even though it might feel dirty, in a component world it actually makes sense to keep that component’s logic and markup in the same place. It might even make sense for styling and data dependencies as well… which brings us to our next point.

CSS Modules: Now that we are no longer concerned about crossing technological boundaries, we can start thinking about incorporating CSS, or styling in our components. CSS is a solid, flexible solution for styling, but at scale, it is rife with issues — naming collisions, selector specificity, hard to statically analyze, and much more. There’s a great slidedeck by Facebook’s Vjeux which explains these issues in detail. He also proposes a solution: inline styles. That’s a little too much for me personally. Performance is bad, media queries are hard to do, hover styles become much harder, and post-processing/auto-prefixing properties can’t be done this way either. A middle ground here works fine: write your component’s CSS in a separate file, then import that CSS via a Webpack loader. We use a technology called CSS modules to use “local” styles: instead of using globally applicable CSS selectors, this technology generates unique names to be used as class es for your components, thus making every selector local by default, making collisions a thing of the past.

Relay/GraphQL: Now that we have logic, markup and styling all packed up in a component, there’s only one thing missing: data. In February 2015, Facebook announced both GraphQL and Relay. The first is a query language, the second is a client for that query language.

A basic GraphQL query looks like this:

user ( id:1 ) {

displayName

emailAddress

photo {

url

width

height

}

}

And the response then should look something like this:

{

"user": {

"displayName": "Foo Bar",

"emailAddress": "foo@example.com",

"photo": {

"url": "",

"width": 0,

"height": 0

}

}

}

This, amongst other things, allows a client to get just the data it needs from the backend, and pack everything into one request of many, which could mean great performance wins on mobile, where latency and waterfall requests have a huge impact on the performance of a web application.

GraphQL also requires you to define a schema. This schema is the basis for incredible developer tools, such as the GraphiQL explorer.

Where Relay comes in, is allowing you to define a component’s data dependencies (or rather: its part of a GraphQL query) along with your component:

Relay.createContainer(

( props ) => <div>{props.user.displayName}</div>, // the component

{

fragments: { // the data it needs

user: Relay.QL`

fragment on User {

displayName

}

`

}

}

);

Relay then analyzes your application’s expected structure, glues all the little parts together and builds one GraphQL query which is then send to the endpoint. When that data returns, your component is rendered with the data it needs — and nothing more.

To me, the birth of GraphQL and Relay is truly a watershed moment:

It allows us to co-locate data requirements along with a component — again making the surface of a component much more contained.

Secondly, facilitating a much more efficient approach to data fetching. In a normal REST API, chances are you would have many more (interdependent) requests, which can quickly become a problem on low-latency networks (like on mobile). GraphQL/Relay is able to minimize the amount of requests, reducing network overhead. In the future it will even become possible to fetch data before your application is initialized, speeding up the first load even more.

It gives us confidence about what data is used where. This allows us to remove unneeded data and validate the client’s data requirements (perhaps at deploy time) with the schema that’s provided by the server.

It enables amazing developer tools like GraphiQL, but imagine generating Flow definitions from a GraphQL schema, or autocomplete GraphQL statements in your editor of choice.

It does feel like Relay needs a second iteration (which is coming) to truly take web app development to the next level — it’s a bit hard to get started with and the minified build is 200kb, which has such a huge impact on startup time it’s hard to justify. But it’s a vibrant space, and it has fierce competition in another GraphQL client, Apollo.

Jest: Up until a couple months ago, Jest was pretty much just a run-of-the-mill JavaScript testing library, mainly used internally at Facebook. But somewhere in the summer it introduced something called snapshot testing. Remember those services that take screenshots of your application and tell you if something has changed? Snapshot testing is pretty much the same, but at a component level: it generates a (human-readable!) snapshot of your React component, saves it to disk, and if a test run encounters a difference with an older snapshot, you can either green light the change, or try to found out what went wrong.

Now, to me, component tests are pretty boring to write. I’d rather spend my time writing application code. What snapshot testing offers, is an easy way to notify me and others of changes within our components. It’s definitely not a replacement for unit tests — reviewing the changes is error-prone — but it offers a less time-consuming alternative to unit and end-to-end testing.