AMPConf 2019 is just wrapping up, but we’re just getting started! In this series of blog posts, we celebrate AMPConf by highlighting how the React Storefront framework and Layer0 make life easier for developers to support AMP in their React apps.
We’ve been relatively early adopters in eCommerce for both Progressive Web Apps (PWAs) and Accelerated Mobile Pages (AMP). With React-powered PWAs, developers can deliver highly engaging experiences on the web that rival native apps. However, when it comes to search-generated traffic, AMP provides the fastest possible option.
In fact, Google’s recommended customer journey is to first deliver an AMP version of your app to search users and transition to the full PWA version of your site on subsequent pages. And since nearly half of retailer website traffic comes from organic search, supporting both AMP and PWA has become a priority.
Writing a great app once is hard enough. No one wants to write the same app twice. Developers hate this kind of thing so much they’ve given it a popular acronym, DRY (Do not Repeat Yourself). As developers, we invested early in adding automatic AMP support to the React framework we created for eCommerce PWAs. This way, developers can write their progressive web app in React and get AMP support with no extra development effort.
And it’s worked very well for our customers. Instead of rebuilding their app, implementing AMP with React Storefront typically takes our customers a day or two, and most of that is simply verifying everything works as expected.
In this post, we will cover how React Storefront does the hard work for you in supporting AMP and PWA from a single codebase. In the next installment, we’ll share some exciting new features of Layer0 that help deliver AMP in a complex enterprise context.
To overcome this limitation, we benefited from an early architectural decision to make React Storefront apps universal (sometimes called isomorphic) by default and support Server-Side Rendering (SSR) in Layer0. With SSR, rendering of the page is done on the server before it is served to users. While our primary goals in adding SSR were to improve performance and SEO, it also enabled us to run a React Storefront app on the server and then automatically convert the HTML output to valid AMPHTML in concert with the techniques below.
The first step towards implementing AMP is to notify Google’s crawler that AMP equivalents of your pages exist. Typically, you would need to create separate AMP versions of your pages, then configure your application’s router to serve both AMP and PWA content on distinct URLs. With React Storefront, all you need to do is add a @withAmp decorator to your top-level page component. React Storefront automatically renders valid AMPHTML for any page simply by adding “.amp” to the URL. The @withAmp decorator leverages this convention to add the necessary link tag to the document head.
In other words, this:
results in something like this on your PWA page:
When Google’s crawler sees a link to /p/1, it will download the AMP content and serve it directly from Google’s AMP CDN.
Note that for proper SEO, the AMP page also needs to embed a rel=canonical tag back to the original PWA version of the page like this:
It's worth stressing here the importance of having the AMP and non-AMP pages pointing back to each other with the appropriate (but different versions of) <link> tags. Without these setups properly, Google won't serve up your AMP content, and even worse, it could result in your AMP pages cannibalizing the SEO rank of your non-AMP pages. React Storefront does all the "AMP double entry bookkeeping" for you, so you don't have to worry about this happening simply because someone forgot to update the right tags.
Implementing even the most basic interactivity in AMP can be a huge pain. For example, a simple quantity field in AMP might look like this:
Imagine writing two versions of code like this FOR EVERY INTERACTIVE CONTROL in your progressive web app. There goes your launch deadline!
Thankfully, we've done that hard work for you. React Storefront gives you coarse-grained AMP-aware components like QuantitySelector that hide all of these gory details. In React Storefront, you would simply use:
The React framework takes care of rendering the AMP version of the component when Google requests an AMP page.
In most cases, developers can simply use one of the AMP-aware components within the React Storefront framework to provide interactivity in AMP. If, however, you find that you need to render something specific for AMP, the framework exposes a boolean amp field in the app state that you can use to conditionally render specific content in AMP.
AMP’s declarative way of defining interaction events is completely different from React’s. For example, imagine you want to track clicks on specific product links by sending events to Google Analytics. In AMP, this would be something like:
I’ll spare you the React implementation, but it’s likely going to involve an onClick listener and a few calls to ga(). Suffice it to say the two will look nothing alike.
React Storefront provides an abstraction, the Track component, that implements both of these for you:
The strategies above get us about 80% of the way towards rendering valid AMP. There are, however, additional changes that need to be made to the document. React Storefront transforms the outgoing HTML before it’s sent, making several changes, including:
AMP requires some specific elements to be present in the document. These include a “⚡” attribute on the root HTML element and a standard style element called the AMP boilerplate:
AMP requires that all CSS be provided in the body of a single style element. Use of the style attribute and <link rel="stylesheet"> are forbidden. React Storefront consolidates all the styles across your codebase, embedded within multiple <style> elements or even inline style attributes, into a single <style amp-custom> element. For each use of a style attribute, React Storefront creates a unique CSS class containing the corresponding rules, applies the class to the element, removes the style attribute, and adds the class to the amp-custom style element. In other words, this:
When added up across all your styles, this automated conversion of CSS takes away another major headache when writing AMP-compatible pages from your React app.
There are various other rules that AMP imposes on the markup. For example, the way that ReactDOM renders boolean attributes produces invalid AMPHTML. This JSX:
will result in this HTML:
which results in the AMP validator showing an error like this:
If you use a component library, some of the HTML rendered by the components may run afoul of the AMP validator for various reasons. React Storefront encourages using the widely popular Material UI library and provides specific rules for cleaning up the HTML it produces. This is where using a comprehensive react progressive web app framework that covers everything from state management to components and styling really shows its value in terms of increasing developer velocity.
As a developer implementing AMP and PWA, you could implement two versions of your app and then maintain them through future changes (meaning that every fix becomes a code change in two places) or use automation to derive AMP content from your pages. At Layer0 we chose the latter, which worked very well for our customers. The React Storefront features we’ve described so far are only part of the reason for that success. In the next installment, we’ll explore how this framework integrates with Layer0 (Edgio) to support AMP in an enterprise environment. Stay tuned.
Get the information you need. When you’re ready, chat with us, get an assessment or start your free trial.