As you can probably already tell, this post is a little on the “advanced” side, but it does tackle a topic that’s very interesting and presents a new branch for us to follow on this whole mobile-first path for our websites and/or apps.
Well, Google thinks it’s the latter. And in come Progressive Web Apps!
Understanding Progressive Web Apps
Progressive Web Apps (PWA) are experiences that combine the best of the web and the best of apps. Native app store apps have become hugely popular in the past through features such as push notifications, working offline, smooth animations and transitions, loading on the homescreen and so on.
Google describes them as being:
- Reliable – Load instantly
- Fast – Quickly respond to user interactions
- Engaging – Behaving like a native app
To hit all of these points, a Progressive Web App must have the following capabilities:
- Work offline or on poor network conditions
- Web App Install Banners or Add to Homescreen
- Use Web Push Notifications. With the introduction of the Web Push API, we can now send Push Notifications to our users, even when the browser is closed.
- Implement HTTPS
- Use an application shell (or app shell) architecture that instantly loads on the users’ screens, similar to native applications.
Progressive Web Apps vs. Responsive Web Design
Progressive Web Apps should not be confused with Responsive Web Design. Progressive Web Apps have responsive capabilities because they can adapt to different screen sizes, but their unique value proposition are the features that make them app-like.
Are PWAs the solution for engaging mobile web users?
Building a high-quality Progressive Web App has incredible benefits, making it easy to delight users, grow engagement and increase conversions. There are several examples of companies, particularly from the e-commerce industry, that have successfully used Progressive Web Apps to improve their metrics, a lot of them are listed on Google’s Developers website.
- For example, Alibaba.com built a PWA that led to a fast, effective, and reliable mobile web experience. The new strategy delivered a 76% increase in total conversions across browsers and a four times higher interaction rate from Add to Homescreen.
- In another use case, OLX wanted to re-engage mobile web users by using Add to Homescreen and Push Notifications. They increased engagement by 250% and improved other metrics too: the time until the page became interactive fell by 23%, with a corresponding 80% drop in bounce rates. Monetization also improved, with clickthrough rate (CTR) rising 146%.
How do we know that a mobile web app is progressive?
- The Angular / Ionic combination is pretty popular nowadays. Ionic is a great framework that was originally built for mobile apps, but has expanded to Progressive Web Apps and even desktop applications.
- React is really intuitive and easy to understand. It benefits from a great boilerplate, create-react-app, which comes with PWA support by default.
Next, we’re going to see some code samples from an e-commerce application built with React on top of the WordPress and WooCommerce REST API.
Understanding WooCommerce REST API
When it comes to building an e-commerce application, the first thing we need is an API from where we can retrieve the data. Fortunately, the inclusion of the REST API in the core has opened the door for using WordPress as a backend. In addition, for e-commerce apps we can use the REST API from the popular WooCommerce plugin.
WooCommerce also has an NPM package (WooCommerce API) for making API calls, but unfortunately this package requires both the consumer key and consumer secret in order to authenticate requests. We would have a security issue if we used the consumer secret in a frontend app.
Also, when creating keys from the WooCommerce admin section, it’s not possible to specify permissions at the route level, for example allowing view access for products and write access for orders.
So, we had to create a proxy in our WordPress plugin, that allows access to a restricted set of API endpoints. As a base, we used the WooCommerce REST API PHP wrapper, as you can see in the below example:
We first initialize the WooCommerce client using the consumer key and secret. The second and third methods are creating a custom route called products and map that route to the products/categories endpoint from the WooCommerce API.
In this way, we can allow access to reading categories and products, but allow only the create operation for an order.
Creating new React app in four simple steps
Once we have set up the API, we can start working on our React application. After installing NodeJS and NPM globally, you can use the
create-react-app package to quickly generate a React JS app that has PWA support by default.
- Install NodeJS and NPM globally
- Install create-react-app boilerplate
npm install create-react-app -g
- Generate new React application
- Start application
cd my-app & npm start
Below is a screenshot of the application that is generated by
create-react-app, it has everything that we need, so we can start coding, including live reload:
There are a few things to keep in mind when starting a new app:
- 1) Organizing app files
- There are several good tutorials out there about how to best structure the app. I prefer folders-by-feature, because it allows better scalability. You can find a really good explanation here.
- 2) Linters and coding standards
- Coding standards can be annoying if you’re not used to them, but do not skip this step. They help clean up unused dependencies and make sure that data is properly validated at the component level. In addition, if you install a prettier editor plugin that automatically formats your code, using coding standards becomes a breeze. As for the standard itself, I prefer the popular one created by Airbnb.
- 3) Small components
- Keeping components files small makes them easier to test and manage. You can start writing code in a single component and, once it gets bigger, divide it into smaller component. For UI/UX components, there are several libraries that are compatible with React, such as Material UI, Semantic UI or even Bootstrap, just to give a few examples.
You can see a list of categories, a list of products and a side menu. Let’s dive into the code – you’ll see how easy it is to use React to create such an example.
Diving into ReactJS
Below is a React component that reads a set of product categories from the API. The component’s state is initialized with an empty list of categories. In the
componentWillMount method that is automatically called by React before render we make a request to fetch the categories and we add them to the state after receiving the response:
As you can see, we don’t need to call the render method when the categories are received, React takes care of that for us and re-renders the component. The render method just returns another custom component called
CategoriesList that receives the categories data and looks like this:
The above component iterates over the list of categories that it receives as a prop and calls another custom component called
CategoryCard to render a single category element.
All these components communicate by passing props between them. The main Categories component calls the API and passes down a list of categories to CategoriesList, which in turn passes a category’s details to the Category Cards.
Managing the global app state using Redux
The problem with the above approach is that sometimes we have data that needs to be managed at the top application level, for example a list of products that were added to the shopping cart. The number of products is shown in the shopping cart icon from the header bar, but these are also displayed as a list on the checkout page.
Also, using Redux doesn’t mean that we can’t use state or props at the component level. Redux should be used only for retaining data that makes sense at the application level.
Let’s see how we can read products from the API and render them in a list, similar to what we need with categories, but this time using Redux. First, we need to make the connection with Redux by wrapping our main app component into a global store:
In this example, the global app store will contain a list of categories and a list of products, which are merged together using the
combineReducers method from Redux.
Then, we continue by defining Redux actions, which are very simple functions that return objects that must contain a type property. Since JS is asynchronous, we’ll need two actions: one for signaling when a request is sent and the other for signaling when a response is received. The whole app will know when these actions take place.
Below, we have also added a function called
fetchProducts. As you can see, this function:
- dispatches the request products action,
- calls the API for retrieving products,
- dispatches the
receiveProductsaction when a result is received.
To modify the app state, we’ll add a so-called Redux “reducer”. The reducer is just a function that listens to particular actions and changes a portion of the global state, in this case the list of products.
This reducer doesn’t do anything when receiving a request products action, it always returns the current state. For the receive products action, the reducer returns the data that is passed to it, in this case it will be a list of products.
To wrap things up, we use these actions and reducer in a new Products component.
This component is wrapped in the
connect method from Redux, and just dispatches
fetchProducts in its
componentWillMount method. Also, the component includes a products list, but as you can see the products list component doesn’t directly receive the products data. That’s because the product list component is directly linked to the global app state, also using Redux.
In this way, it can access the products data directly from the app store, iterate over the list of products and use a
ProductCard component to render a single product element.
In this case, when the user clicks the “Add to cart” button, we will dispatch an action that will modify the global app state. The header bar, which displays the number of cart products, will be connected with Redux. It will count the number of products saved in the application’s cart and update itself accordingly.
Linking the app with WordPress
These are all basic examples to get you started, and you’re probably wondering how exactly we can link this app with WordPress.
create-react-app boilerplate includes commands for creating the application’s build, so we can get the production files immediately.
Where to use service workers
There are several strategies that you can use for offline mode, such as network first or cache first, and you can read about these in Google’s offline cookbook.
Caching the application’s shell has benefits even when we have a network connection, because the app will load much faster.
If you want to go even further and start caching the data that comes from the API, you can use NPM packages like redux-persist and modify your app to save / retrieve data from the browser’s local storage.
We’re already working on the beta version and here’s just a part of our roadmap:
- Add offline mode capabilities
- Add push notifications
- Finalize the checkout process
If you want to contribute or customize it for your own needs, you can find the alpha version of the e-commerce progressive web application on GitHub.
Don’t forget to join our crash course on speeding up your WordPress site. With some simple fixes, you can reduce your loading time by even 50-80%:
Layout and presentation by Karol K.