Introduction to the

Have you ever thought of learning APP development to make up for your lack of mobile terminal ability? However, many students felt a little confused when faced with many choices: should I study iOS or Android development? Learn native development, hybrid development (e.g. Ionic), or use a cross-platform framework like React Native or Flutter? However, the long learning cycle and high learning cost of APP development also make some people prohibitive. Thanks to the rapid development of front-end technology and the continuous improvement of browser performance, it becomes a reality to use web technology to develop applications that are close to native experience. PWA comes into being in this context. You can use your familiar HTML, CSS and JavaScript to develop a website comparable to native APP. It not only has the fluency of native APP, but also has some features that native APP has, such as: a. You can install app ICONS on the home screen, b. Offline access, c. Get notifications, etc. The emergence of PWA gives us hope!

Comparing native apps

So how does PWA compete with native apps? Let’s look at the features of native apps and PWA separately:

Native Apps:

  • Develop using native SDK and development tools
  • Cross-platform considerations are needed, and different systems often need to be developed independently
  • You need to publish to the app store to download and use it
  • You can install the phone home screen to generate app ICONS
  • Directly running on the operating system, easy access to system resources
  • It can be used offline
  • You can get message notifications

PWA application:

  • Use HTML, CSS, JS development
  • Don’t worry about cross-platform, just browser compatibility
  • Access via URL without having to publish to the app store
  • You can install the phone home screen to generate app ICONS
  • Run in the browser, can access system resources
  • It can be used offline
  • You can get message notifications

It can be seen that PWA has the main capabilities of native apps, but the development process is much simpler than that of native apps: A. HTML/CSS/JS has a better mass base and development efficiency is higher; B. It saves a lot of cost of developing separate versions for different systems; C. Eliminate the tedious process of getting on the shelf to the application market; D. No need to go to the app store to download it, and it is more convenient for users to use it. It’s worth noting, however, that PWA is a relatively new technology, there’s still a lot of room for tweaks to the specification, and some browsers don’t have complete support for PWA, but PWA is a trend, so it’s a good time to learn!

This article will show you the development process of PWA With a simple example (a simple ZIP code query app). The project can be found at Traversy Media – Build a PWA With Vue & Ionic4. This is what it looks like.

Create a project

The project was developed using a combination of VUE + Ionic. This paper mainly focuses on the construction of PWA, so VUE, Ionic and other techniques are not described too much. For those of you using VSCode, it is recommended to install the Vetur plugin to increase your development efficiency.

1. Install globally first@vue/cli:

npm install -g @vue/cli

2. Initialize the Vue project:

vue create vue-ionic-pwa

3. Because ionic routing depends onvue-router, so install it nextvue-router:

vue add router

4. Install@ionic/vue

npm install @ionic/vue

In 5.src/main.jsAdd a reference to ionic:

. import Ionic from '@ionic/vue' import '@ionic/core/css/ionic.bundle.css' Vue.use(Ionic) ...

In 6.src/router.jsThe use ofIonicVueRouterReplace the default Vue Router:

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.src/App.vueThe content is modified to:

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

Will 8.src/views/Home.vueThe content is modified to:

<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:

APP function realization

The APP is mainly composed of three parts: 1. Search component, which is used for entering the zip code and searching; 2. Display component is used to display the queried postcode information. 3. Clear button is used to clear the queried postcode information

1. Search components

We created a new ZipSearch.vue file under SRC /components as the zip code search component. The main logic is that when the user enters a string of characters, press the search button, trigger a get-zip event if the input is valid, and prompt if it is not.

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>

In SRC/views/Home. Vue introducing ZipSearch components, when Home to receive the get – zip event interface, called https://www.zippopotam.us for zip code corresponding to the 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 search component first:

Inputted postal code format error:

2. Information display and clearance components

Once we get the zip code information we need a component to display the zip code information and a button to clear the information. Create new ZipInfo.vue and clearInfo. vue under SRC /components.

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>

Next, introduce the ZipInfo and ClearInfo components in the Home:

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 body of the app is complete, and the effect is as follows:

Realize the PWA

We used the off-the-shelf @vue/ PWA plugin to add PWA capabilities to our app.

The installation@vue/pwa:

vue add @vue/pwa

Two files, public/manifest.json and registerServiceWorker.js, were added to the project after installation. The contents of the public/manifest. Json file are 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. json mainly contains the basic information of APP, such as name, ICONS, display and so on. It is a necessary configuration for Web APP to be installed and displayed in a similar native way. See the MDN Web App Manifest for more configuration items.

The App Manifest configuration can also be seen in the Chrome console:

RegisterServiceWorker.js is used to register service workers. Generally speaking, the service worker is a script that runs independently of the web page in the background of the browser. The service worker can complete some special functions, such as message push, background synchronization, intercepting and processing network requests, managing network cache, etc. The significance of Service worker in PWA is that it can provide offline experience for users, that is, users can still visit the website and obtain cached data under offline state. Using service workers requires HTTPS, and browser compatibility is considered.

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 the service worker can also be seen in the Chrome console:

Of course, just registering the service worker is not enough, we also want to control the behavior of the service worker, by adding the relevant configuration in vue.config.js we can set the name of the service worker file, the caching logic, etc.

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]}}}}]}}}

See @vue/cli-plugin-pwa and workbox-webpack-plugin for more configurations. Since the service worker generated by @vue/cli-plugin-pwa only takes effect in the production environment, it is recommended to deploy the project to the production environment for testing after build. The examples in this article are deployed and demonstrated using GitHub Pages.

At this point, the work of converting ordinary Web APP into PWA is basically completed. Let’s deploy it online and see the effect:

The file has been cached for offline access:

If you look up a zip code, you can see that the request was cached:

We then turn off the network, query the previous zip code, and find that immediately after the network failed to switch to the local cache:

There you go, a simple PWA is done. Of course, the functions of PWA are much more than what is shown in this article, such as push and install to mobile phones. I will share with you later when I have the opportunity. Thank you 🙏.

Finally, I recommend you to use it
Fundebug, a very useful BUG monitoring tool ~

In this paper, the demo address: https://github.com/MudOnTire/…