In this code pattern, we will create an Offline First shopping list. Shopping List is an Offline First demo Progressive Web App built using Polymer and PouchDB. This app is part of a series of Offline First demo apps, each built using a different stack. Credit goes to Bradley Holt for this Polymer/PouchDB implementation.
When the reader has followed this code pattern, they will understand how to:
- Implement an app database that runs in the browser with local data when offline, and syncs with a remote database when online.
- Create an Offline First Progressive Web App.
- The user manages shopping lists using the Offline First web app.
- Polymer is used to make it a Progressive Web App with Web Components and Service Workers.
- The shopping lists are stored locally in PouchDB while offline.
- When online, PouchDB syncs with Cloudant.
Want to take your Watson app to the next level? Looking to leverage Watson Brand assets? Join the With Watson program which provides exclusive brand, marketing, and tech resources to amplify and accelerate your Watson embedded commercial solution.
- Cloudant NoSQL DB: A fully-managed data layer designed for modern web and mobile applications that leverages a flexible JSON schema. Based on the open source Apache CouchDB, IBM Cloudant provides additional full text and geospatial capabilities.
- Polymer: Libraries, tools, and patterns for building Progressive Web Apps using web platform features such as Web Components, Service Workers, and HTTP/2.
- PouchDB: An open source JavaScript database that syncs with anything that implements the CouchDB Replication Protocol.
- Databases: Repository for storing and managing collections of data.
This shopping list app is a small single page web application built using Polymer and PouchDB library. The web app will allow multiple shopping lists to be created (e.g., Groceries, Camping Supplies) each with a number of shopping list items associated with them (e.g. Mangos, Oranges).
So what sets this app apart? Its Offline First architecture. The Offline First approach plans for the most constrained network environment first, enabling a great user experience even while the device is offline or has only an intermittent connection, and providing progressive enhancement as network conditions improve. This design also makes the app incredibly performant (fast!) on the best of networks.
PouchDB, CouchDB, and Service Worker are the primary tools that turn our simple shopping list app into a high performance, offline-capable Progressive Web App.
Data stays safe on your device, even while it's offline. Persistance of shopping lists and item data entered by the user is achieved using the in-browser database PouchDB. This will allow your data to survive between sessions and when disconnected from the network. (Whether you remember that you need juice while you're on your trusty home Wi-Fi or in the middle of the wilderness, you can still add it your list.)
Data syncs between devices when a connection is available. When a connection is available, the data is synced from the local device to a CouchDB database in the cloud, and can thus be shared across multiple devices or users. (Need to share your grocery list with your roommate or access it on both your phone and your laptop? No problem!)
The app loads quickly, even while offline. To keep the app itself functional while offline, a Service Worker is used to cache page resources (the most important HTML, CSS, and JavaScript files) when the web application is first visited. Each device must have a connection for this first visit, after which the app will be fully functional even while offline or in shoddy network conditions. (No more error messages or frustratingly slow page loads.)
The app can be installed on a mobile device. In combination with the Service Worker used for caching, a manifest file containing metadata allows the app to become a Progressive Web App, an enhanced website that can be installed on a mobile device and can then be used with or without an internet connection. (It's secretly still a website, but you can access it through one of those handy dandy little app icons on your homescreen!)
Explore the code in this GitHub repository to see how the Offline First design is applied.
-
Press the above
Deploy to IBM Cloud
button and then click onDeploy
. -
In Toolchains, click on Delivery Pipeline to watch while the app is deployed. Once deployed, the app can be viewed by clicking
View app
. -
To see the app and services created and configured for this code pattern, use the IBM Cloud dashboard. The app is named
shopping-list-polymer-pouchdb
with a unique suffix. The following services are created and easily identified by theslpp-
prefix:- slpp-CloudantNoSQLDB
NOTE: These steps are only needed when running locally instead of using the
Deploy to IBM Cloud
button.
Clone the shopping-list-polymer-pouchdb
locally. In a terminal, run:
$ git clone https://github.com/ibm-watson-data-lab/shopping-list-polymer-pouchdb
First, install Polymer CLI using npm (we assume you have pre-installed Node.js):
npm install --global polymer-cli
Second, install Bower using npm:
npm install --global bower
Third, install the Bower npm resolver:
npm install --global bower-npm-resolver
This command serves the app at http://127.0.0.1:8081
and provides basic URL routing for the app:
polymer serve
PouchDB can synchronize with CouchDB and compatible servers. To run and test locally, you can install CouchDB. Alternatively, you can use a hosted Cloudant NoSQL DB service for your remote DB.
Install CouchDB 2.1. Instructions are available for installing CouchDB 2.1 on Unix-like systems, on Windows, on Mac OS X, on FreeBSD, and via other methods.
Configure CouchDB for a single-node setup, as opposed to a cluster setup. Once you have finished setting up CouchDB, you should be able to access CouchDB at http://127.0.0.1:5984/
. Ensure that CouchDB is running and take note of your admin username and password.
Sign up for an IBM Cloud account, if you do not already have one.
Once you are logged in to IBM Cloud, create a new Cloudant instance on the Cloudant NoSQL DB Bluemix Catalog page. This should take you to a page representing the newly-created service instance. Click the "Service credentials" link. You should have one set of service credentials listed. Click "View credentials" which should show you a JSON object containing your service credentials. Copy the value for the url
key to your clipboard (the value will be in the form of https://username:password@uniqueid-bluemix.cloudant.com
).
Use your Cloudant or CouchDB dashboard to create a database. Select the Databases icon on the left and then use the Create Database
button to create the "shopping-list" database.
The Shopping List app can be used locally before the database exists, but cannot sync
until the remote database is completed.
Cross-Origin Resource Sharing (CORS) needs to be enabled. Use your Cloudant or CouchDB dashboard to enable it. The CORS options are under the account settings or config depending on your version. Enable CORS and restrict the domain as needed for security.
Run the Shopping List app and use the Replicator
form to enter your Database URL.
If you use the Bluemix Cloudant URL taken from the service credentials as described above, the URL includes user and password GUIDs.
Add /shopping-list
to the URL to connect to the database that you created.
The app allows you to create a shopping list by clicking on the plus sign. Click on the list to see its items. Then, you can add items to the list by clicking the plus sign. There is a checkbox to allow you to mark the items complete as you buy load up your cart.
When you have not configured your Replication Target or when you are offline, the lists will not sync. One good way to test this is to run two browsers. You can use Chrome and Firefox and have different lists in each.
When you go online and have the database and CORS enabled and the Replication Target is set, the shopping lists will sync. You will then be able to use both lists from either browser.
Shopping List is a simple demo app, with a limited feature set. Here is a list of features written as user stories grouped by Epic.
Not all features are implemented in the current Polymer app. This demo app does not yet include item/list removal, geolocation features or multi-user features.
The polymer build
command builds your Polymer application for production, using build configuration options provided by the command line or in your project's polymer.json
file.
You can configure your polymer.json
file to create multiple builds. This is necessary if you will be serving different builds optimized for different browsers. You can define your own named builds, or use presets. See the documentation on building your project for production for more information.
This app is configured to create three builds using the three supported presets:
"builds": [
{
"preset": "es5-bundled"
},
{
"preset": "es6-bundled"
},
{
"preset": "es6-unbundled"
}
]
Builds will be output to a subdirectory under the build/
directory as follows:
build/
es5-bundled/
es6-bundled/
es6-unbundled/
es5-bundled
is a bundled, minified build with a service worker. ES6 code is compiled to ES5 for compatibility with older browsers.es6-bundled
is a bundled, minified build with a service worker. ES6 code is served as-is. This build is for browsers that can handle ES6 code - see building your project for production for a list.es6-unbundled
is an unbundled, minified build with a service worker. ES6 code is served as-is. This build is for browsers that support HTTP/2 push.
Run polymer help build
for the full list of available options and optimizations. Also, see the documentation on the polymer.json specification and building your Polymer application for production.
This command serves your app. Replace build-folder-name
with the folder name of the build you want to serve:
polymer serve build/build-folder-name/
This command will run Web Component Tester against the browsers currently installed on your machine:
polymer test
If running Windows you will need to set the following environment variables:
- LAUNCHPAD_BROWSERS
- LAUNCHPAD_CHROME
Read More here daffl/launchpad
You can extend the app by adding more views that will be demand-loaded e.g. based on the route, or to progressively render non-critical sections of the application. Each new demand-loaded fragment should be added to the list of fragments
in the included polymer.json
file. This will ensure those components and their dependencies are added to the list of pre-cached components and will be included in the build.
If you are deploying to a Project Page then you will first need to modify the base URL and root path values in index.html
to match your project name. For example, for the project name shopping-list-polymer-pouchdb
change:
<base href="/">
To:
<base href="/shopping-list-polymer-pouchdb/">
And change:
window.Polymer = {rootPath: '/'};
To:
window.Polymer = {rootPath: '/shopping-list-polymer-pouchdb/'};
You can then deploy the app to GitHub pages by running:
npm run deploy:gh-pages
This app uses a drawer-based layout. The layout is provided by Polymer's app-layout
elements.
This app, along with the polymer-cli
toolchain, uses the "PRPL pattern" This pattern allows fast first delivery and interaction with the content at the initial route requested by the user, along with fast subsequent navigation by pre-caching the remaining components required by the app and progressively loading them on-demand as the user navigates through the app.
The PRPL pattern, in a nutshell:
- Push components required for the initial route
- Render initial route ASAP
- Pre-cache components for remaining routes
- Lazy-load and progressively upgrade next routes on-demand
https://ibm-watson-data-lab.github.io/shopping-list-polymer-pouchdb/
Refer to the tutorial for step-by-step instructions on how to build your own Offline First shopping list Progressive Web App with Polymer and PouchDB.
- Demo on Youtube
- Offline First: In a data-first world, your web and native apps need to deliver excellent user experiences, including during network disruptions. The Offline First approach to application development puts performance first and recognizes that network downtime is a fact of life.
- Progressive Web Apps: A Progressive Web App provides both the discoverability of a web app and the reliable, fast, and engaging user experience of a native mobile app.
- Web Components: Open standard for components and widgets that are customizable, reusable, and encapsulated
- Polymer App Toolbox: Components, tools, and templates for building Progressive Web Apps with Polymer and Web Components.
- Polymer App Toolbox - Starter Kit: A starter kit for building Polymer apps.
Refer to https://github.com/IBM/metrics-collector-service#privacy-notice.
To disable tracking, simply remove require('metrics-tracker-client').track();
from the app.js
file in the top level directory.