Skip to main content

Progressive Web App Wordpress Theme (Part 1/2)


After I read two articles: Progressive Web Apps Are The Next Big Thing and More Surprising Statistics About WordPress Usage. I decided to build a Wordpress theme which integrated Progressive Web Apps (PWA) to see how cool it is when two “Big Thing” mix together.

TL;DR

To avoid Too Long; Didn’t Read. I break the whole procedure into two blogs. In part 1, I will build a Progressive Web App in the local server.

What PWA features to be built here?

According to PWA wiki, the PWA will be progressive enhancements. The final webapp will be:

  • Responsive design: I choose Bootstrap 4 because it’s mobile-first design.
  • Contents retrieve from Wordpress CMS via REST API. It’s a natural way the App is developed in Javascript.
  • Offline support: The PWA still can run and display the contents when no Internet connection.
  • Installable on Android home screen: I will design the App icon and theme which makes the PWA more native app looks.

Developing steps by steps

Setup the environment using webpack

First of all, my NodeJS and NPM version are:
$ node -v && npm -v
$ v8.1.2
$ 5.2.0

Create the project root directory and initialize the project:
$ mkdir pwa-wordpress-1 && cd pwa-wordpress-1
$ npm init -y

Thus, it created package.json as below:

Install Webpack:
$ npm install --save-dev webpack
# ... after a moment ...
# + webpack@3.4.1
# added 363 packages in 41.937s

In the project root, create the directories:
$ mkdir src && mkdir src/pug && mkdir src/pug/inc && mkdir dist

Install necessary webpack & other packages/plugins:
$ npm install --save-dev amdefine babel babel-core babel-loader babel-preset-env babel-preset-es2015 caniuse-lite css-loader extract-text-webpack-plugin html-loader locate-path node-sass postcss-loader pug pug-html-loader rimraf sass-loader webpack-dev-server write-file-webpack-plugin

Install Bootstrap 4:
$ npm install --save bootstrap@4.0.0-alpha.6

It will automatically install jQuery and tether packages. I need to create a webpack config file to expose all packages (webpack.config.dev.js):

PostCSS requires a config file. I simply create a /postcss.config.js as follow:
module.exports = {}

In /package.json, I modified some my personal info:

Crafting the webpages

I start programming the webpages. I want the final design something like this:

I am using pug for HTML preprocess. Pug can greatly simplify HTML coding, the markups look more structural. The good thing is the ability to import other pug files. The program the home page /src/pug/home.pug content:

You can see home.pug extends inc/layout.pug file:

It includes two more pug files, inc/styles.pug:
link(rel='stylesheet', href='app.bundle.css')

and inc/scripts.pug:
noscript You need to enable JavaScript to run this
app.script(src='app.bundle.js')

There have several other pug files (navigator.pug, blogs.pug, pages.pug, pageview.pug, postview.pug). I don’t list it all here. You can check it out from my github repo.

Programming the main files

The main logic is covered in app.js, and the style app.scss. (Note: All require preprocessors, Javascript is based on Babel ES6 syntax and the style needs SCSS preprocessor to compile into CSS). The initially src/app.js content:

Take attention to the import sequence. Otherwise Bootstrap will load failure caused by jQuery not exposed. I took almost an hour to solve 😓

After that I create stylesheet src/app.scss:

In the first line, I changed the brand color to purple. The webpack SCSS preprocessor produces all bootstrap CSS files then bundles it in a single CSS.

Getting Wordpress posts & pages via REST API

Wordpress starting from version 4.7+ has built-in support REST API v2. I can easily retrieve the posts and pages via JS fetch(). But before working on my JS logic, I test the wordpress with Postman to make sure the REST API is working. If ‘Error 404: page not found’, try changing Wordpress Permalink to ‘Post name’. But for me using Nginx server, I need to change the Nginx site file /etc/nginx/sites-available/default:
server {
    ...
    location / {
        # IMPORTANT: Change to below line
        try_files $uri $uri/ /index.php$is_args$args;
    }
    ...
for more info: see Digital Ocean’s amazing article

After the REST API proved working (like this) via Postman:

I start programming the 4 JS objects inside app.js. Those 4 objects are to handle blogs list, pages list, view full blog, view full page tasks respectively. Now the src/app.js content becomes:

All 4 objects calling fetch() to get posts & pages from my demo wordpress server (temporarily live for testing only) via REST API. To make the data more realistic, I use FakerPress Wordpress plugin to create several “Lorum Ipsum” posts.

Now the time to test my works. I build the project by running:
$ npm run dev
...
       [0] ./src/pug/home.pug 41 bytes {3} [built]
       [1] ./src/pug/blogs.pug 41 bytes {4} [built]
       [2] ./src/pug/pages.pug 41 bytes {2} [built]
       [3] ./src/pug/pageview.pug 41 bytes {1} [built]
       [4] ./src/pug/postview.pug 41 bytes {0} [built]
...
       Time: 6240ms
       Asset     Size  Chunks                    Chunk Names
       app.bundle.js  1.21 MB       0  [emitted]  [big]  app
       app.bundle.css   148 kB       0  [emitted]         app
...

Nice, it seems fine. Let start the local server http-server:
$ cd dist && http-server

Browse http://localhost:8080. The browser can display all pages without error, as below (5 screenshots, 5 seconds per screen):


Create PWA assets files

As mentioned in Google Developer PWA tutorial, PWA requires a service worker (mention later in this blog), and manifest.json with favicon.ico and a bunch of icons (I skipped in this blog). I create a very simple src/manifest.json as below:

To copy those asset files to /dist in build processes. I simply change the scripts in /packag.json. Modify the script "dev" and add a script: "copy-assests", as below:
{
  ...
  "scripts": {
    "dev": "npm run clean && webpack -d --config webpack.config.dev.js && npm run copy-assets",
    "copy-assets": "cp src/manifest.json dist/ && cp src/favicon.ico dist/ && cp src/service-worker.js dist/"
  }
  ...
}

Create a Service Worker and register it

Service Worker is most important element of Progressive Web App. It handles offline caching, background communication to receive push notification. Simply say, it makes PWA more native Apps like.

Thanks to Chrome team, we can easily grab a service worker code, from a list of service worker samples. Where the service workers range from basic to sophisticated. (or even we don’t need to develop by hand). I select a basic one. Add some modification to handle pre-caching for the assets and runtime for REST API results. My `src/service-worker.js’ codes are:

PWA also needs to register the service worker. My registration logic is programmed in src/registerServiceWorker.js:

To trigger the function registerServiceWorker(), I add below codes into the src/app.js:
...
import {checkHTTPS, registerServiceWorker, GoogleAnalytics} from './registerServiceWorker.js'
// checkHTTPS() // enable this when running HTTPS
registerServiceWorker()
// GoogleAnalytics() // enable this if needed
...

Now I can test the service worker. Run the debug build: npm run dev. Then all the generated files store in /dist directory:
$ ll dist
total 2784
-rw-r--r--  1 simonho  staff   144K 29 Jul 22:35 app.bundle.css
-rw-r--r--  1 simonho  staff   1.2M 29 Jul 22:35 app.bundle.js
-rw-r--r--  1 simonho  staff   1.2K 29 Jul 22:35 blogs.html
-rw-r--r--  1 simonho  staff    24K 29 Jul 22:35 favicon.ico
-rw-r--r--  1 simonho  staff   1.1K 29 Jul 22:35 home.html
-rw-r--r--  1 simonho  staff   297B 29 Jul 22:35 manifest.json
-rw-r--r--  1 simonho  staff   1.2K 29 Jul 22:35 pages.html
-rw-r--r--  1 simonho  staff   1.5K 29 Jul 22:35 pageview.html
-rw-r--r--  1 simonho  staff   1.5K 29 Jul 22:35 postview.html
-rw-r--r--  1 simonho  staff   2.6K 29 Jul 22:35 service-worker.js

All necessary files are here, I run the local web server as: cd dist && http-server. Open Chrome, open developer tools, and select the Application tab. The screens showing (3 screenshots, 10 seconds each):
As you can see, Chrome shows the service worker is activated, cache storage is working. Even the webpages can be browsed when the web server is stopped.

To be continued…

This is the end of part 1. Part 2 will integrate it to build a WordPress theme. Finally, test the PWA on the mobile phone.


The source codes of this Part 1 keep in this Github repo.

Enjoy!


Comments

  1. Merkur 15c Safety Razor - Barber Pole - Deccasino
    Merkur 15C Safety Razor - Merkur 1xbet app - 15C for Barber casinosites.one Pole is deccasino the perfect kadangpintar introduction to the Merkur https://septcasino.com/review/merit-casino/ Safety Razor.

    ReplyDelete

Post a Comment

Popular posts from this blog

Create An Online Store Theme Used By MyCMS

MyCMS is an open-source Content Management System to generate static online shop website. You can use my hosting to input your products, or you can download the source codes and host it in your own server (running NodeJS). Please refer to my Github repo for the detailed installation instructions. This blog is a step-by-step tutorial that shows you how to create an online-shop theme. In this tutorial, it’s using my hosting to input the shop details and products. If you’re hosting the MyCMS by yourself, just change the domain name to yours will do. Introducing MyCMS Before making the theme, you’ll need to use MyCMS to configure the demo shop and input two demo products. MyCMS generates a static website via a theme. The generated static website is NO server program required. You can put the website files (HTML/CSS/JS) to any CDN, hosting. Shop Configuration You must prepare below settings Before using MyCMS: Setting Description Example Store name Your store name will be displayed in t

How I make a web-components based dynamic Javascript page at the top of Google Search

Introduction Everybody wants their website shown at the first position of Google search. SEO (Search Engine Optimization) is a big topic. I just helped my client's website shows the database records at the top search rankings (at least several Chinese generic keywords). See the three example questions all are listed at top ranking: Website background: My client's website  popa.qa  is a traditional Chinese Q&A site that lets members ask and answer questions. All answers and questions are storing in the database server. Step 1: Create The Project This blog illustrates the problems and the steps to fix that with project source codes. Below is the description of the basic project: NodeJS backend (server.js) Develop an API ( /get-database-records ) to simulate getting database records Web-components frontend (index.html) An example component IndexPage  make use of  LitElement to render database records To start the server type: npm start Then I check the webpage speed using th

Build A Simple Sales System using Google Drive

Google Drive is a free-to-use cloud service with a 15 GB limit storage. 15 GB is large enough to store documents, and "program" too. Yes, it's correct. We can program Google Drive. This blog is a step-by-step tutorial to show you how to build a simple P.O.S. system on Google Drive. Create a Google Sheets to define the products 1. Login to Google Drive using your Gmail account and create a Google Sheets: 2. Input the products in the Google Sheets Create a Google Forms for sale input 1. Create a new Google Form 2. Edit the form and the first field Note that leave the option field unchanged. We'll assign it programmatically in below 3. Add a quantity field 4.  Add a last field for the price input How to copy data from Google Sheets to Google Forms? We need to add a script to do that. Google developed Google App Script (GAS) for us to achieve that. Now go back to the Google Sheet we just created above. Then enter to the script editor You'll see the below screen. Then