Polymer 2.0 — Building Progressive Web Apps with Enhanced Web Platform Features

#useThePlatform to deliver great user experiences 🙂

(1) Introduction

Google’s Polymer Project blends 2 major front-end development trends in the modern web:

  1. Web Components — through Polymer Library (a light-weight library to create framework-independent, strongly-encapsulated custom components)
  2. Progressive Web Apps (PWAs)— through Polymer App Toolbox (a minimal progressive web app toolset which supports modern enhanced web platform features like Web Components, Service Worker, and HTTP/2)

(1.1) Why Web Components?

  • Web components can form encapsulated and reusable custom HTML elements. Unlike the usual framework-dependent UI components in React/Angular, web components are independent of the frameworks because they are made of pure HTML/CSS/JS. They will work with any framework of your choice (CustomElementsEverywhere.com)

(1.2) Why PWAs?

  • PWAs are a type of modern web apps with enhanced capabilities like cross-device functionality, better user experiences, and slow network support. They are reliable, fast, secure, and built on modern web standards supported by all browsers and web platforms.

(1.3) Why Polymer?

  • Rapidly-growing community, documentation, and overall production-ready ecosystem (backed by Google)

(2) Setting Up Development Environment

Install Node/NPM, Git, Bower, and Yarn (in the given order). If you are behind a proxy server, configure proxy settings after installing each tool (Proxy Config Guide). Now install polymer-cli globally:

$ npm install -g polymer-cli

Although Polymer is built upon the modern web platform standards, some browsers have not yet implemented these new features. So as a workaround, in a below section, we build 3 versions of our app and start serving different build versions to different browsers based on browser capabilities (ES6, HTTP/2 Server Push, Service Worker API, JS Modules). For that, install this HTTP server now:

$ yarn global add prpl-server

(3) My First Polymer Mini App

  • Let’s create a mini app which collects some data from a JSON API with an AJAX call and display them using an editable data grid.
$ mkdir awesome-app
$ cd
awesome-app
$ polymer init
$ Which starter template would you like to use?
1) polymer-2-element - A simple Polymer 2.0 element template
2) polymer-2-application - A simple Polymer 2.0 application
3) polymer-2-starter-kit - A Polymer 2.x starter application template, with navigation and "PRPL pattern" loading
4) shop - The "Shop" Progressive Web App demo
5) vaadin-elements-app - Progressive web application template with Polymer App Toolbox and Vaadin Elements
// Select 3 
  • Let’s fire up your browser with the freshly-scaffolded app with the following command:
$ polymer serve --open
  • In the web component world, we can find an element for most of our tiresome tasks (check webcomponents.org catalog for many such elements). So I chose 3 web components — iron-ajax(a Polymer element which makes it easy to create AJAX calls and parse the response), vaadin-grid (an element which provides a high performance, customizable data table), and paper-checkbox to save our time:
$ bower install --save vaadin-grid
$ bower install
--save iron-ajax
$ bower install
--save paper-checkbox
  • Now modify the src/my-view1.html file with the following code lines:
  • Now refresh your browser. Our mini app will look like below:
  • In the above code, the iron-ajax element creates an AJAX call to “https://randomuser.me/api?results=100", parse the data as JSON, and assign it to ‘users’. This data set is displayed in the data grid. If you select the ‘Enable Editing’ option, you can see how the two-way binding works in Polymer too.
  • See how fast it is to create a tiny meaningful app with Polymer. We didn’t use much styling, most of the code we wrote belongs to the business logic of our app.
  • Now let’s see some of the underlying concepts in Polymer 😄

(4) PRPL Pattern:

  • PRPL pattern defines how a production-ready Polymer app works efficiently by sending only the required resources to the client-side:
  1. Push critical resources for the initial route.
  2. Render initial route.
  3. Pre-cache remaining routes.
  4. Lazy-load and create remaining routes on demand.
  • In PRPL pattern, the server needs to be able to identify the resources required by each of the app’s routes. Instead of bundling the resources into a single unit for download, it uses HTTP2 push to deliver the individual resources needed to render the requested route. When building an app, always consider to prioritize sending the critical resources to render a meaningful view first, and later send the rest of your app resources as per the request. Here’re some great insights from Chrome Team to improve your app’s startup performance:
  • Coming back to our topic, in PRPL pattern, the server and service worker together work to precache the resources for the inactive routes.
  • When the user switches routes, the app lazy-loads any required resources that haven’t been cached yet, and creates the required views.
From Polymer Summit 2017 (End to End Apps with Polymer)

(5) App Structure

App Shell Structure

A Polymer app works like a single-page app (SPA) and therefore, it includes only a single index.html file as an entry point to the app. These apps are made of several main views that include various custom elements inside them. A top-level application element (app shell) serves as the main controller for the app. It handles routing and dynamic page loading too. App-specific custom elements together build the main views of an app. These fragments that represent particular views of the app are lazily loaded upon the dynamic requests coming from app shell.

Youtube (the new re-write) is the largest Polymer app ever built. Let’s check how the app shell architecture looks like in the production:

(6) Modular Development:

  • This approach is great for developing large applications with many feature teams. While UX teams are working on fundamental UI components, development teams can build feature components and integrate them in the app views.

(7) State management:

  • Avoid direct communication between two components and always use the mediator pattern with a suitable state management implementation.
  • One good option is to use a global mediator with/without Redux — Redux stores the state as one big serialized object. State changes are uni-directional, hence it makes the state immutable. When an event happens, it dispatches an action to the reducer. Then, the reducer takes the action with the current state, and produce the next state. Redux Store manages the state flow. Middleware can also be integrated (e.g. for logging). (concepts: One global state, single store, one source of truth, no dispatcher, immutable state)
From Polymer Summit 2017 (End to End Apps with Polymer)
  • If Redux is not an option, you can still use your in-house implementations— create own event handlers and implement state management rules that match the use cases.

(8) Browser support:

  • Chrome supports Polymer apps natively without any polyfill. All other browsers need polyfills to run Polymer apps. To serve all these browser types, we use 3 build presets and generate 3 build versions during the build process. Depending on the browser (by reading the user agent), we serve the right build for each browser. A Node.js application environment is necessary to run this task (Read: prpl-server-node ).
https://www.polymer-project.org/2.0/docs/browsers
  • Let’s try this out. Open up your polymer.json file and modify the builds section with "basePath": true as below:
"builds": [
{ "preset": "es5-bundled", "basePath": true },
{ "preset": "es6-bundled", "basePath": true },
{ "preset": "es6-unbundled", "basePath": true },
]
  • Now build the project:
$ polymer build --verbose
  • Instead of using $ polymer serve command, now run the below command to serve the app from your build directory with the support of prpl-server:
$ prpl-server --root ./build
  • Now open up different browsers and check the build version served for each:
  • prpl-server is smart enough to use the user-agent header, detect browser capabilities, and serve the right build for your browser 👌
From Polymer Summit 2017 (End to End Apps with Polymer)

(9) Offline support:

  • To make our app run on slow network and offline modes, Polymer registers a service worker script in the browser. It can intercept network requests, access the browser’s cache, and serve requests out of the cache instead of accessing the network (acting as a client-side proxy for network requests).
  • Service worker works well with the app shell strategy. It can cache the UI views and resources so that they can be served from the cache next time.
Image from Offline web by Steven Alexander
  • On Chrome DevTools, you can see that a service worker script has been registered for the URL of your app:

(10) My Thoughts ( 😄 )

Polymer has already solved some of the major problems in enterprise level web applications. A few months ago, I started trying out the power of web components and PWAs and so far I am really excited for being able to accelerate my development work with Polymer!

Polymer team has already announced the Polymer 3.0 preview version which ships very promising changes to the development workflow like:

  1. Moving from Bower to npm (Yarn)
  2. Switching to using ES6 modules instead of HTML Imports

While React, Angular, Vue, or Ember is still a great choice to build a general-purpose web app, if you need to make use of enhanced web capabilities and serve millions or billions of devices and users coming from different geographical regions, I recommend you to try out and see how the Polymer ecosystem can help you.

Polymer community is growing so fast and this is an exciting time to #useThePlatform to deliver better user experiences!


More Insights

  • If you are interested in learning more about the Polymer community, watch Polymer Summit 2017 on Youtube: