Introduction to PWA: Hand in Hand to Teach You to Make a PWA Application

  ionic, pwa, vue.js

image

brief introduction

Do students at the front end of the Web want to learn app development to make up for their lack of mobile capability? However, when faced with the choice of a large crowd, many students felt a little confused. Is it to learn ios or android development? Is to learn native development, mixed development (such as:Ionic), or usereact nativeOr ..flutterSuch a cross-platform framework? The long learning cycle and high learning cost of app development have also deterred some people. Thanks to the rapid development of front-end technology and the continuous improvement of browser performance, the use of web technology to develop applications close to native experience has become a reality, and PWA came into being under this background. You can use your familiar HTML, CSS and Javascript to develop websites comparable to native app, which not only have the fluency close to native app, but also have some features unique to native app, such as: A. you can install application icons on the main screen, B. you can access them offline, C. you can get message notifications, and so on. . The appearance of PWA makes everyone see hope!

Contrast with native application

How competitive is PWA compared to native applications? Let’s look at the characteristics of native applications and PWA respectively:

Primary applications:

  • Develop using native SDK and development tools
  • Cross-platform needs to be considered, and different systems often need to be developed independently.
  • You need to publish to the application store to download and use it.
  • Can be installed on the mobile phone main screen to generate application icons
  • It runs directly on the operating system and has convenient access to system resources.
  • Can be used offline
  • Message notification can be obtained

PWA applications:

  • HTML, CSS, JS development
  • There is no need to consider cross-platform, only browser compatibility
  • Access via url, no need to publish to app store
  • Can be installed on the mobile phone main screen to generate application icons
  • Run in browser, can access system resources
  • Can be used offline
  • Message notification can be obtained

It can be found that PWA has the main capability of native application, but the development process is more concise than native application: a. html/css/js has better mass base and higher development efficiency; B. a large amount of cost for developing independent versions for different systems is saved; C. the complicated process of putting on shelves to the application market is saved; D. users do not need to go to the application store to download, and it is more convenient to use. However, it is worth noting that PWA is still a relatively new technology. There is still much room for adjustment in the implementation of the specification. Some browsers’ support for PWA is not perfect, but PWA is a trend, so it is appropriate to learn now!

This article will show the development process of PWA through a simple column (a simple postal code query app). For project reference:Traversy Media – Build a PWA With Vue & Ionic4. After the completion of the effect issuch.

Create project

The project was developed using a combination of Vue+Ionic. This article focuses on the construction of PWA, so vue, ionic and other technologies will not be described too much. For students who use VSCode, installation is recommended.VeturPlug-ins Increase Development Efficiency.

1. First, install globally@vue/cli

npm install -g @vue/cli

2. Initialize vue Project:

vue create vue-ionic-pwa

3. because ionic’s routing depends onvue-router, so the next installationvue-router

vue add router

4. Installation@ionic/vue

npm install @ionic/vue

5. Insrc/main.jsAdd a reference to ionic in:

...
import Ionic from '@ionic/vue'
import '@ionic/core/css/ionic.bundle.css'

Vue.use(Ionic)
...

6. Insrc/router.jsUsed inIonicVueRouterReplace the default vuelouter:

import Vue from 'vue'
 import { IonicVueRouter } from '@ionic/vue';
 import Home from './views/Home.vue'
 
 Vue.use(IonicVueRouter)
 
 export default new IonicVueRouter({
 mode: 'history',
 base: process.env.BASE_URL,
 routes: [
 {
 path: '/',
 name: 'home',
 component: Home
 }
 ]
 })

7. Willsrc/App.vueThe content was amended to read:

<template>
 <div id="app">
 <ion-app>
 <ion-vue-router/>
 </ion-app>
 </div>
 </template>

8. Willsrc/views/Home.vueThe content was amended to read:

<template>
<div class="ion-page">
<ion-header>
<ion-toolbar>
<ion-title>
ZipInfo
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">My App</ion-content>
</div>
</template>

<script>
export default {
name: 'home',
components: {}
}
</script>

Finally, we runyarn serveLook at the effect:

1

App function implementation

App mainly consists of three parts: 1. Search component, which is used to input postcode and query, 2. Display component, which is used to display the queried postcode information, and 3. Clear button, which is used to clear the queried postcode information

1. Search component

We aresrc/componentsNew belowZipSearch.vueAs a postcode search component, the main logic is to press the search button when the user enters a string of characters and trigger if the input is legal.get-zipEvents, if not in accordance with the law to give a hint.

ZipSearch.vue

<template>
 <ion-grid>
 <form @submit="onSubmit">
 <ion-col>
 <ion-item>
 <ion-label>ZipCode:</ion-label>
 <ion-input
 :value="zip"
 @input="zip = $event.target.value"
 name="zip"
 placeholder="Enter US ZipCode"
 />
 </ion-item>
 </ion-col>
 <ion-col>
 <ion-button type="submit" color="primary" expand="block">Find</ion-button>
 </ion-col>
 </form>
 </ion-grid>
 </template>
 
 <script>
 export default {
 name: "ZipSearch",
 data() {
 return {
 zip: ""
 };
 },
 methods: {
 onSubmit(e) {
 e.preventDefault();
 const zipRegex = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
 const isValid = zipRegex.test(this.zip);
 if (!  isValid) {
 this.showAlert();
 } else {
 this.$emit("get-zip", this.zip);
 }
 this.zip = "";
 },
 showAlert() {
 return this.$ionic.alertController
 .create({
 header: "Enter zipcode",
 message: "Please enter a valid US ZipCode",
 buttons: ["OK"]
 })
 .then(a => a.present());
 }
 }
 };
 </script>

Insrc/views/Home.vueIntroduction ofZipSearchComponents, whenHomeReceive toget-zipCalled when an event occurshttps://www.zippopotam.usInterface, get zip code corresponding information:

...
 <ion-content class="ion-padding">
 <ZipSearch v-on:get-zip="getZipInfo"/>
 </ion-content>
 ...
 
 <script>
 import ZipSearch from "../components/ZipSearch";
 
 export default {
 name: "home",
 components: {
 ZipSearch
 },
 data() {
 return {
 info: null
 };
 },
 methods: {
 async getZipInfo(zip) {
 const res = await fetch(` https://api.zippopotam.us/us/${zip}`);
 if (res.status == 404) {
 this.showAlert();
 }
 this.info = await res.json();
 },
 showAlert() {
 return this.$ionic.alertController
 .create({
 header: "Not Valid",
 message: "Please enter a valid US ZipCode",
 buttons: ["OK"]
 })
 .then(a => a.present());
 }
 }
 };
 </script>

Let’s look at the effect of the search component first:

search

Incorrect format of postcode input:

invalid input

2. Information display and removal components

After obtaining the postcode information, we need a component to display the postcode information and a button to clear the information, atsrc/componentsNew belowZipInfo.vueAndClearInfo.vue.

ZipInfo.vue

<template>
<ion-card v-if="info">
<ion-card-header>
<ion-card-subtitle>{{info['post code']}}</ion-card-subtitle>
<ion-card-title>{{info['places'][0]['place name']}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-list>
<ion-item>
<ion-label>
<strong>State:</strong>
{{info['places'][0]['state']}} ({{info['places'][0]['state abbreviation']}})
</ion-label>
</ion-item>
<ion-item>
<ion-label>
<strong>Latitude:</strong>
{{info['places'][0]['latitude']}}
</ion-label>
</ion-item>
<ion-item>
<ion-label>
<strong>Longitude:</strong>
{{info['places'][0]['longitude']}}
</ion-label>
</ion-item>
</ion-list>
</ion-card-content>
</ion-card>
</template>

<script>
export default {
name: "ZipInfo",
props: ["info"]
};
</script>

ClearInfo.vue

<template>
<ion-button color="light" expand="block" v-if="info" @click="$emit('clear-info')">Clear</ion-button>
</template>

<script>
export default {
name: "ClearInfo",
props: ["info"]
};
</script>

Then inHomeIntroduction ofZipInfoAndClearInfoComponents:

src/views/Home.vue

...
 <ion-content class="ion-padding">
 <ZipSearch v-on:get-zip="getZipInfo"/>
 <ZipInfo v-bind:info="info"/>
 <ClearInfo v-bind:info="info" v-on:clear-info="clearInfo"/>
 </ion-content>
 ...
 
 import ZipInfo from "../components/ZipInfo";
 import ClearInfo from "../components/ClearInfo";
 
 export default {
 name: "home",
 components: {
 ZipSearch, ZipInfo
 },
 methods:{
 ...
 clearInfo(){
 this.info = null;
 }
 }
 }

At this point, the main body of app is completed with the following effects:

app

Implement PWA

We use ready-made ones.@vue/pwaPlug-ins to add PWA capabilities to our app.

Installation@vue/pwa

vue add @vue/pwa

After the installation is completed, the project has been addedpublic/manifest.jsonAndregisterServiceWorker.jsTwo files. among thempublic/manifest.jsonThe document reads as follows:

{
 "name": "vue-ionic-pwa",
 "short_name": "vue-ionic-pwa",
 "icons": [
 {
 "src": "./img/icons/android-chrome-192x192.png",
 "sizes": "192x192",
 "type": "image/png"
 },
 {
 "src": "./img/icons/android-chrome-512x512.png",
 "sizes": "512x512",
 "type": "image/png"
 }
 ],
 "start_url": "./index.html",
 "display": "standalone",
 "background_color": "#000000",
 "theme_color": "#4DBA87"
 }

manifest.jsonIt mainly contains the basic information of app, such as name, icons, display, etc. It is a necessary configuration for web app to be installed and displayed in a similar native way. For more configuration items, please refer toMDN Web App Manifest.

The app’s manifest configuration can also be seen in the Chrome browser console:

manifest

registerServiceWorker.jsUsed to register service worker. Generally speaking, service worker is a script that runs independently of the web page in the browser background. service worker can complete some special functions, such as: message push, background synchronization, interception and processing of network requests, management of network cache, etc. The significance of Service worker to pwa is to provide users with offline experience, that is, users can still access websites and obtain cached data in the offline state. HTTPS is required to use service worker, and considerBrowser compatibility.

registerServiceWorker.js

import { register } from 'register-service-worker'
 
 if (process.env.NODE_ENV === 'production') {
 register(`${process.env.BASE_URL}service-worker.js`, {
 ready () {
 console.log(
 'App is being served from cache by a service worker.\n' +
 'For more details, visit  https://goo.gl/AFskqB'
 )
 },
 registered () {
 console.log('Service worker has been registered.')
 },
 cached () {
 console.log('Content has been cached for offline use.')
 },
 updatefound () {
 console.log('New content is downloading.')
 },
 updated () {
 console.log('New content is available;  please refresh.')
 },
 offline () {
 console.log('No internet connection found. App is running in offline mode.')
 },
 error (error) {
 console.error('Error during service worker registration:', error)
 }
 })
 }

The status of service worker can also be seen in Chrome browser console:

service worker

Of course, it is not enough to register only the service worker. we also hope to control the service worker’s behavior by using thevue.config.jsWe can set the name of the service worker file, cache logic, and so on.

vue.config.js

module.exports = {
pwa: {
workboxPluginMode: 'GenerateSW',
workboxOptions: {
navigateFallback: '/index.html',
runtimeCaching: [
{
urlPattern: new RegExp('^https://api.zippopotam.us/us/'),
handler: 'networkFirst',
options: {
networkTimeoutSeconds: 20,
cacheName: 'api-cache',
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
}
}

For more configuration, please refer to:@vue/cli-plugin-pwaAndworkbox-webpack-plugin. Due to@vue/cli-plugin-pwaThe generated service worker only takes effect in the production environment, so it is recommended to deploy the project after build to the production environment for testing. This article exemplifies the use ofgithub pagesDeploy and demonstrate.

At this point, the conversion of ordinary web app into PWA has been basically completed. We deployed it online to see the effect:

File cached for offline access:

app

Try searching a postcode and you will find that the request has been cached:

api cache

We then shut down the network and looked up the postcode just now. We found that after the network request failed, we immediately switched the data cached locally:

offline

Well, a simple PWA has already been made. Of course, PWA’s functions are much more than those shown in this article, such as pushing and installing to mobile phones. I’ll share with you later. Thank you.

Demo address in this article:https://github.com/MudOnTire/ …