Tuesday, August 24, 2021

Format Date Time and Set Time Zone in Java

This is a quick tutorial on how to format the java Date in a format like "yyyy-MM-dd HH:mm:ss"  and also set the time zone for the date provided.

I would like to recommend always set the time in UTC while saving it in the database and also for the current date. Latter we can manipulate this UTC time to whatever timezone is required.

Now, let's see how we can format date time and also set the time zone in order to display to the user. Let's look at the example.

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class DateUtils {
    public static void main(String[] args) {
        String dateFormat = "yyyy-MM-dd HH:mm:ss";
        String timeZone = "Asia/Jerusalem";
        Date date = new Date(); // current server time
        String formattedDate = formatDate(date, dateFormat, timeZone);
        System.out.println(formattedDate);
    }

    public static String formatDate(Date date, String dateFormat, String timeZone) {
        if (date == null) return ""; // or simply throw Exception
        DateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
         if (timeZone != null)
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
        return simpleDateFormat.format(date);
    }
}
Here, we have created formatDate method that accepts the parameters date(current date), dateFormat(a format that the date needs to be converted), and timeZone(time zone to convert given date to desired time zone)
DateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
We are using the java core "SimpleDateFormat" class to convert the date in our desired date format.
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
This will set the given time zone. We are setting the Israel timezone. 

Output:
2021-08-24 12:25:52 
If you need a different format then simply change the dateFormat argument value for e.g
String dateFormat = "yyyy-MM-dd";
Output:
2021-08-24
Get the list of all TimeZones.

If you want to get all the time zones available then simply try using the following method.
import java.time.ZoneId;
import java.util.Set;

public static void visualizeAllTimeZone() {
        Set<String> zoneIds = ZoneId.getAvailableZoneIds();
        for (String id : zoneIds) {
            ZoneId zoneId = ZoneId.of(id);
            System.out.println(zoneId);
        }
    }


Output:

Asia/Aden
America/Cuiaba
Etc/GMT+9
Etc/GMT+8
Africa/Nairobi
America/Marigot
Asia/Aqtau
Pacific/Kwajalein
America/El_Salvador
Asia/Pontianak
Africa/Cairo
Pacific/Pago_Pago
Africa/Mbabane
Asia/Kuching
Pacific/Honolulu
Pacific/Rarotonga
America/Guatemala
Australia/Hobart
Europe/London
America/Belize
America/Panama
Asia/Chungking
America/Managua
America/Indiana/Petersburg
Asia/Yerevan
Europe/Brussels
GMT
Europe/Warsaw
America/Chicago
Asia/Kashgar
Chile/Continental
Pacific/Yap
CET
Etc/GMT-1
Etc/GMT-0
Europe/Jersey
America/Tegucigalpa
Etc/GMT-5
Europe/Istanbul
America/Eirunepe
Etc/GMT-4
America/Miquelon
Etc/GMT-3
Europe/Luxembourg
Etc/GMT-2
Etc/GMT-9
America/Argentina/Catamarca
Etc/GMT-8
Etc/GMT-7
Etc/GMT-6
Europe/Zaporozhye
Canada/Yukon
Canada/Atlantic
Atlantic/St_Helena
Australia/Tasmania
Libya
Europe/Guernsey
America/Grand_Turk
Asia/Samarkand
America/Argentina/Cordoba
Asia/Phnom_Penh
Africa/Kigali
Asia/Almaty
US/Alaska
Asia/Dubai
Europe/Isle_of_Man
America/Araguaina
Cuba
Asia/Novosibirsk
America/Argentina/Salta
Etc/GMT+3
Africa/Tunis
Etc/GMT+2
Etc/GMT+1
Pacific/Fakaofo
Africa/Tripoli
Etc/GMT+0
Israel
Africa/Banjul
Etc/GMT+7
Indian/Comoro
Etc/GMT+6
Etc/GMT+5
Etc/GMT+4
Pacific/Port_Moresby
US/Arizona
Antarctica/Syowa
Indian/Reunion
Pacific/Palau
Europe/Kaliningrad
America/Montevideo
Africa/Windhoek
Asia/Karachi
Africa/Mogadishu
Australia/Perth
Brazil/East
Etc/GMT
Asia/Chita
Pacific/Easter
Antarctica/Davis
Antarctica/McMurdo
Asia/Macao
America/Manaus
Africa/Freetown
Europe/Bucharest
Asia/Tomsk
America/Argentina/Mendoza
Asia/Macau
Europe/Malta
Mexico/BajaSur
Pacific/Tahiti
Africa/Asmera
Europe/Busingen
America/Argentina/Rio_Gallegos
Africa/Malabo
Europe/Skopje
America/Catamarca
America/Godthab
Europe/Sarajevo
Australia/ACT
GB-Eire
Africa/Lagos
America/Cordoba
Europe/Rome
Asia/Dacca
Indian/Mauritius
Pacific/Samoa
America/Regina
America/Fort_Wayne
America/Dawson_Creek
Africa/Algiers
Europe/Mariehamn
America/St_Johns
America/St_Thomas
Europe/Zurich
America/Anguilla
Asia/Dili
America/Denver
Africa/Bamako
Europe/Saratov
GB
Mexico/General
Pacific/Wallis
Europe/Gibraltar
Africa/Conakry
Africa/Lubumbashi
Asia/Istanbul
America/Havana
NZ-CHAT
Asia/Choibalsan
America/Porto_Acre
Asia/Omsk
Europe/Vaduz
US/Michigan
Asia/Dhaka
America/Barbados
Europe/Tiraspol
Atlantic/Cape_Verde
Asia/Yekaterinburg
America/Louisville
Pacific/Johnston
Pacific/Chatham
Europe/Ljubljana
America/Sao_Paulo
Asia/Jayapura
America/Curacao
Asia/Dushanbe
America/Guyana
America/Guayaquil
America/Martinique
Portugal
Europe/Berlin
Europe/Moscow
Europe/Chisinau
America/Puerto_Rico
America/Rankin_Inlet
Pacific/Ponape
Europe/Stockholm
Europe/Budapest
America/Argentina/Jujuy
Australia/Eucla
Asia/Shanghai
Universal
Europe/Zagreb
America/Port_of_Spain
Europe/Helsinki
Asia/Beirut
Asia/Tel_Aviv
Pacific/Bougainville
US/Central
Africa/Sao_Tome
Indian/Chagos
America/Cayenne
Asia/Yakutsk
Pacific/Galapagos
Australia/North
Europe/Paris
Africa/Ndjamena
Pacific/Fiji
America/Rainy_River
Indian/Maldives
Australia/Yancowinna
SystemV/AST4
Asia/Oral
America/Yellowknife
Pacific/Enderbury
America/Juneau
Australia/Victoria
America/Indiana/Vevay
Asia/Tashkent
Asia/Jakarta
Africa/Ceuta
Asia/Barnaul
America/Recife
America/Buenos_Aires
America/Noronha
America/Swift_Current
Australia/Adelaide
America/Metlakatla
Africa/Djibouti
America/Paramaribo
Asia/Qostanay
Europe/Simferopol
Europe/Sofia
Africa/Nouakchott
Europe/Prague
America/Indiana/Vincennes
Antarctica/Mawson
America/Kralendijk
Antarctica/Troll
Europe/Samara
Indian/Christmas
America/Antigua
Pacific/Gambier
America/Indianapolis
America/Inuvik
America/Iqaluit
Pacific/Funafuti
UTC
Antarctica/Macquarie
Canada/Pacific
America/Moncton
Africa/Gaborone
Pacific/Chuuk
Asia/Pyongyang
America/St_Vincent
Asia/Gaza
Etc/Universal
PST8PDT
Atlantic/Faeroe
Asia/Qyzylorda
Canada/Newfoundland
America/Kentucky/Louisville
America/Yakutat
Asia/Ho_Chi_Minh
Antarctica/Casey
Europe/Copenhagen
Africa/Asmara
Atlantic/Azores
Europe/Vienna
ROK
Pacific/Pitcairn
America/Mazatlan
Australia/Queensland
Pacific/Nauru
Europe/Tirane
Asia/Kolkata
SystemV/MST7
Australia/Canberra
MET
Australia/Broken_Hill
Europe/Riga
America/Dominica
Africa/Abidjan
America/Mendoza
America/Santarem
Kwajalein
America/Asuncion
Asia/Ulan_Bator
NZ
America/Boise
Australia/Currie
EST5EDT
Pacific/Guam
Pacific/Wake
Atlantic/Bermuda
America/Costa_Rica
America/Dawson
Asia/Chongqing
Eire
Europe/Amsterdam
America/Indiana/Knox
America/North_Dakota/Beulah
Africa/Accra
Atlantic/Faroe
Mexico/BajaNorte
America/Maceio
Etc/UCT
Pacific/Apia
GMT0
America/Atka
Pacific/Niue
Australia/Lord_Howe
Europe/Dublin
Pacific/Truk
MST7MDT
America/Monterrey
America/Nassau
America/Jamaica
Asia/Bishkek
America/Atikokan
Atlantic/Stanley
Australia/NSW
US/Hawaii
SystemV/CST6
Indian/Mahe
Asia/Aqtobe
America/Sitka
Asia/Vladivostok
Africa/Libreville
Africa/Maputo
Zulu
America/Kentucky/Monticello
Africa/El_Aaiun
Africa/Ouagadougou
America/Coral_Harbour
Pacific/Marquesas
Brazil/West
America/Aruba
America/North_Dakota/Center
America/Cayman
Asia/Ulaanbaatar
Asia/Baghdad
Europe/San_Marino
America/Indiana/Tell_City
America/Tijuana
Pacific/Saipan
SystemV/YST9
Africa/Douala
America/Chihuahua
America/Ojinaga
Asia/Hovd
America/Anchorage
Chile/EasterIsland
America/Halifax
Antarctica/Rothera
America/Indiana/Indianapolis
US/Mountain
Asia/Damascus
America/Argentina/San_Luis
America/Santiago
Asia/Baku
America/Argentina/Ushuaia
Atlantic/Reykjavik
Africa/Brazzaville
Africa/Porto-Novo
America/La_Paz
Antarctica/DumontDUrville
Asia/Taipei
Antarctica/South_Pole
Asia/Manila
Asia/Bangkok
Africa/Dar_es_Salaam
Poland
Atlantic/Madeira
Antarctica/Palmer
America/Thunder_Bay
Africa/Addis_Ababa
Asia/Yangon
Europe/Uzhgorod
Brazil/DeNoronha
Asia/Ashkhabad
Etc/Zulu
America/Indiana/Marengo
America/Creston
America/Punta_Arenas
America/Mexico_City
Antarctica/Vostok
Asia/Jerusalem
Europe/Andorra
US/Samoa
PRC
Asia/Vientiane
Pacific/Kiritimati
America/Matamoros
America/Blanc-Sablon
Asia/Riyadh
Iceland
Pacific/Pohnpei
Asia/Ujung_Pandang
Atlantic/South_Georgia
Europe/Lisbon
Asia/Harbin
Europe/Oslo
Asia/Novokuznetsk
CST6CDT
Atlantic/Canary
America/Knox_IN
Asia/Kuwait
SystemV/HST10
Pacific/Efate
Africa/Lome
America/Bogota
America/Menominee
America/Adak
Pacific/Norfolk
Europe/Kirov
America/Resolute
Pacific/Tarawa
Africa/Kampala
Asia/Krasnoyarsk
Greenwich
SystemV/EST5
America/Edmonton
Europe/Podgorica
Australia/South
Canada/Central
Africa/Bujumbura
America/Santo_Domingo
US/Eastern
Europe/Minsk
Pacific/Auckland
Africa/Casablanca
America/Glace_Bay
Canada/Eastern
Asia/Qatar
Europe/Kiev
Singapore
Asia/Magadan
SystemV/PST8
America/Port-au-Prince
Europe/Belfast
America/St_Barthelemy
Asia/Ashgabat
Africa/Luanda
America/Nipigon
Atlantic/Jan_Mayen
Brazil/Acre
Asia/Muscat
Asia/Bahrain
Europe/Vilnius
America/Fortaleza
Etc/GMT0
US/East-Indiana
America/Hermosillo
America/Cancun
Africa/Maseru
Pacific/Kosrae
Africa/Kinshasa
Asia/Kathmandu
Asia/Seoul
Australia/Sydney
America/Lima
Australia/LHI
America/St_Lucia
Europe/Madrid
America/Bahia_Banderas
America/Montserrat
Asia/Brunei
America/Santa_Isabel
Canada/Mountain
America/Cambridge_Bay
Asia/Colombo
Australia/West
Indian/Antananarivo
Australia/Brisbane
Indian/Mayotte
US/Indiana-Starke
Asia/Urumqi
US/Aleutian
Europe/Volgograd
America/Lower_Princes
America/Vancouver
Africa/Blantyre
America/Rio_Branco
America/Danmarkshavn
America/Detroit
America/Thule
Africa/Lusaka
Asia/Hong_Kong
Iran
America/Argentina/La_Rioja
Africa/Dakar
SystemV/CST6CDT
America/Tortola
America/Porto_Velho
Asia/Sakhalin
Etc/GMT+10
America/Scoresbysund
Asia/Kamchatka
Asia/Thimbu
Africa/Harare
Etc/GMT+12
Etc/GMT+11
Navajo
America/Nome
Europe/Tallinn
Turkey
Africa/Khartoum
Africa/Johannesburg
Africa/Bangui
Europe/Belgrade
Jamaica
Africa/Bissau
Asia/Tehran
WET
Europe/Astrakhan
Africa/Juba
America/Campo_Grande
America/Belem
Etc/Greenwich
Asia/Saigon
America/Ensenada
Pacific/Midway
America/Jujuy
Africa/Timbuktu
America/Bahia
America/Goose_Bay
America/Virgin
America/Pangnirtung
Asia/Katmandu
America/Phoenix
Africa/Niamey
America/Whitehorse
Pacific/Noumea
Asia/Tbilisi
America/Montreal
Asia/Makassar
America/Argentina/San_Juan
Hongkong
UCT
Asia/Nicosia
America/Indiana/Winamac
SystemV/MST7MDT
America/Argentina/ComodRivadavia
America/Boa_Vista
America/Grenada
Asia/Atyrau
Australia/Darwin
Asia/Khandyga
Asia/Kuala_Lumpur
Asia/Famagusta
Asia/Thimphu
Asia/Rangoon
Europe/Bratislava
Asia/Calcutta
America/Argentina/Tucuman
Asia/Kabul
Indian/Cocos
Japan
Pacific/Tongatapu
America/New_York
Etc/GMT-12
Etc/GMT-11
America/Nuuk
Etc/GMT-10
SystemV/YST9YDT
Europe/Ulyanovsk
Etc/GMT-14
Etc/GMT-13
W-SU
America/Merida
EET
America/Rosario
Canada/Saskatchewan
America/St_Kitts
Arctic/Longyearbyen
America/Fort_Nelson
America/Caracas
America/Guadeloupe
Asia/Hebron
Indian/Kerguelen
SystemV/PST8PDT
Africa/Monrovia
Asia/Ust-Nera
Egypt
Asia/Srednekolymsk
America/North_Dakota/New_Salem
Asia/Anadyr
Australia/Melbourne
Asia/Irkutsk
America/Shiprock
America/Winnipeg
Europe/Vatican
Asia/Amman
Etc/UTC
SystemV/AST4ADT
Asia/Tokyo
America/Toronto
Asia/Singapore
Australia/Lindeman
America/Los_Angeles
SystemV/EST5EDT
Pacific/Majuro
America/Argentina/Buenos_Aires
Europe/Nicosia
Pacific/Guadalcanal
Europe/Athens
US/Pacific
Europe/Monaco
You can select whatever time zone you need from the above list. 

In order to get the display name



import java.time.format.TextStyle;
import java.util.Locale;

System.out.println(zoneId.getDisplayName(TextStyle.FULL, Locale.US));
Share:

Friday, January 1, 2021

How to use static content in app root directory in grails

In Grails latest version, it provides static assets management mechanism. You can use different files under the corresponding folders.


All the images will go under the images directory, js files go under the javascripts directory and CSS goes under the stylesheets directory. These files will be accessed by the URL path start with "/assets/".

Now, what if you don't want to use this structure or need to use the root path for some static file content.

For this, grails provide another option to manage static resources. So, what you can do is create the /resources/public directory under /src/main/ and use static resources there.


For example, if you had a file under /src/main/resources/public/images/example.jpg path then you can access that file using https://example.com/static/images/example.jpg.

This means, your file can be accessed with "/static/" URL by default.

If you want to access the file in the app root directory, setup the following configuration under application.groovy

grails.resources.pattern = '/**'

Now, for the above example the file can be accessed with https://example.com/images/example.jpg URL and if the file is in /public/ directory that file can be accessed with root path https://example.com/file.js
Share:

Adding PWA support in existing VueJs application

In this tutorial, we are going to add the PWA support in the existing VueJs application.

1. Install Vue CLI

npm install -g @vue/cli
# OR
yarn global add @vue/cli

2. Add PWA in our application

Let's open the terminal or command prompt and go to the project directory and add PWA  to the project.
vue add pwa
This will add a couple of files and settings for PWA in our existing application.

1. registerServiceWorker.js under ./src directory.



/* eslint-disable no-console */

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)
    }
  })
}
Inside this file, the service worker is registered, and also, we can see the different hooks implemented which we can use in different cases like when the update is found in the app when the user is offline etc.

2. Dependencies added

Under package.json you can see the register-service-worker and PWA plugin is added.


3. Added some icons

Under public/img/icons/ folder some icons are added for mobile, desktop display. Make sure to change your icons for different devices. For more detail on changing this follow the following article.


If you want to configure via config file follow this guide.

Besides this, registerServiceWorker is imported inside main.js file.

3. Build and Deploy the application.

Build and deploy the application, you can see the service worker is activated and running.


You can see the cached file inside cache storage.

By default, it uses default mode which means a service worker is generated for us. If you want to customize it follow the following articles.


To notify the users about the app update follow the following post.


Share:

Monday, December 28, 2020

How to create WhatsApp and Telegram contact link in our website.

This is a short tutorial on how we can add some social media links to communicate.

If you provide the services and allow the client to communicate then this might be helpful.

1. Adding WhatsApp link to chat.

For WhatsApp, if you want to add the link that helps to send the message, it will be a good option. This feature will allow beginning to chat with someone whose phone number is not saved on your contact list. But they need to have an active WhatsApp account.

Once the link is clicked a chat will automatically open to start. It's suitable for both web and mobile. You can simply create the link as below:
<a href="https://wa.me/977XXXXXXX" target="_blank"><img
        src="whatsApp.png"
        alt=""> </a>
Make sure to have your phone number in the link above. The general format is:
https://wa.me/<number>
where, the number is a full phone number in international format without any zeroes, brackets, or dashes. 

Use: https://wa.me/1XXXXXXXXXX

Don't use: https://wa.me/+001-(XXX)XXXXXXX

2. Adding Telegram link to chat:

Similar to WhatsApp, you can add a telegram link.

First, create the telegram account and create a username. You can create a username from the web as well as mobile

Go the Setting >> Username >> 

Now, add the following link to your website.
<a href="https://t.me/yourusername" target="_blank"><img src="telegram.png" alt=""></a>
Add your username to the link.
Share:

Sunday, December 20, 2020

VueJs PWA: Notify User about the App Update | skipWaiting

Once the application is updated and deployed then, the new version of the application will be available. But how we can notify the user that a newer version is available while they are interacting with the application. How to give the user control over app updates.

Please check out my previous articles on PWA:


1. Understanding how the UI get an update when new content is available:

When you change the app content and deploy it then, you can see in the browser what the service worker is trying to do.




Here, you can see, as soon as the new content is available new service worker trying to install it and is in waiting state.

Although, the old service worker is registered and serving with the old content. The new service worker will be still in a skip waiting state i.e waiting.

Here, once we notify the user about the new update and if they allow us to update the app we can simply do skip waiting and reload the page for new content. After that, a new service worker will be activated and will serve with a new update available.

2. Register the custom event to notify the user about the app update:

We know that service worker can't access the web DOM element directly. As they will run in the background in a separate thread. So we have to notify users from our application. In order to do so, we need to register the custom event which can be listened to in the application.

You can see the file registerServiceWorker.js which is generated by Vue CLI.

/* eslint-disable no-console */

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

There are multiple events that will be triggered. Here, we need to use the updated hook to notify the user. Let's register for the custom event.
updated (registration) {
      console.log('New content is available; please refresh.')
      document.dispatchEvent(
          new CustomEvent('serviceWorkerUpdateEvent', { detail: registration })
      );
    },
Now let's add this event listener serviceWorkerUpdateEvent in our application. Inside App.vue
created() {
    document.addEventListener(
        'serviceWorkerUpdateEvent', this.appUpdateUI, { once: true }
    );
  },





Let's add some data used and appUpdateUI function.
data: () => ({
    registration:null,
    isRefresh: false,
    refreshing: false,
  }),
  methods:{
    appUpdateUI:function (e){
      this.registration = e.detail;
      this.isRefresh = true;
    }
  }

When the updated event inside registerServiceWorker.js triggered then serviceWorkerUpdateEvent will be triggered which calls the appUpdateUI to show the button to update. Let's add a simple button inside the template as a user interface to update the app. You can use a nicer snack bar instead.
<button v-if="isRefresh" @click="update">Update</button>
Let's add update() inside methods.
update(){
     this.isRefresh = false;
     if (this.registration || this.registration.waiting) {
       this.registration.waiting.postMessage({type:'SKIP_WAITING'});
     }
   },
Now when the user clicks the update button then it will send the post message of type 'SKIP_WAITING' to communicate with the service worker.

If you are using GenerateSW mode then make sure this post message matches the message listener inside the service worker. You can verify it by building your app. Once the app is built then under dist/ folder you can find the service-worker.js to verify.

If you are using injectManifest mode then, use the message listener as below inside service-worker.js:
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});
Now, this listener will be triggered and it will do skip waiting. The last thing is we need to reload the application to reflect the content change.



For this, we can use 'controllerchange' listener in our application. Under App.vue inside created use the following listener.
created() {
    navigator.serviceWorker.addEventListener(
        'controllerchange', () => {
          if (this.refreshing) return;
          this.refreshing = true;
          window.location.reload();
        }
    );
  },
This is the idea to notify the user of the App update.
Share:

VueJs: How to Get the App Version from package.json

This is a quick tutorial on how we can access the app version.

While building applications, there may be a different phase of development. We need to have a clear vision that which version of the application is on the server.

In the VueJs application under package.json file, you can see the one property called version. We can use this version while deploying to indicate the different versions of the application.


So, what we can do is simply increase the value for a different version of development.

The version can be accessed in our application by simply importing this file as below:

import {version} from '../../package'
Make sure it's accessible. Here, e.g '../../' will give the access for the package which is used under /src/somefolder/component.vue. As the package.json file is under the app root directory. If you want it inside App.vue you can use '../' instead.
data: () => ({
    appVersion:version
  }),
Now access in your template or can set in the store and access it.

<h1>{{appVersion}}</h1>

If you want the package version inside npm script:

const version = process.env.npm_package_version
Share:

How to Use and Customize Service Worker in VueJs Progressive Web Apps(PWA)

 1. Introduction:

What exactly a service worker? What is the need of service worker in our web application?

The service worker is the script that runs in the browser in the background. This means the service worker will run in a separate thread and is independent of our web pages. Service worker can't access the DOM directly.

The service worker is very handy for the caching strategy, push notification, background sync. This means we can manage which files need to be cache and which are not.

Also particularly for mobile app, when it is not opened and needs to send the push notification As well as if the app is not opened and needs to send the request to the server.

Please visit our previous articles on PWA:


2. Default Implementation of Service Worker in VueJs PWA:

VueJs application with Vue CLI uses the default configuration to set up and use the service worker.



If you build your application then, you can see the service worker file generated.
yarn build
 

There are two webpack plugin mode, one is GenerateSW mode which will generate the complete service worker. Vue CLI uses this as a default mode.

Another is InjectManifest mode, which allows us to customize and organize as our requirement and we do have full control over service worker.

If you want to know when to use and when not to use these modes please visit Workbox webpack Plugins

You can see the default service worker generated after building the application as shown in the figure above.

We are going to use the InjectManifest mode so that we can have control over the service worker.

3. Register the Service Worker:

The service worker registration is done by Vue CLI by default. You can see the registerServiceWorker.js under /src folder, the file looks as below:
/* eslint-disable no-console */

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)
    }
  })
}
Note: make sure to change the service worker name if you use a different name for it.





Here, the service worker is enabled only for production, enabling service worker in development mode is not encouraged, as it will not reflect the current changes in development, instead it will use cached resources. All the events will be triggered in different cases. 

4. Customize Service Worker with InjectManifest Mode:


Let's copy the service worker service-worker.js file from the dist/ folder or create a new  service-worker.js file under the src/ directory.


Now, let's configure the config to notice that we are using the InjectManifiest mode and provide the newly created service worker path to use that service worker.

For this, create a vue.config.js file under the app root directory. Make sure to have the same name mentioned so this config file will be used by Vue CLI. The file looks as below.


Now, lets set up the config:
 pwa:{
        workboxPluginMode: "InjectManifest",
        workboxOptions:{
            swSrc:"./src/service-worker.js",
        }
    }



Add the above PWA configuration inside the vue.config.js file. Here, we are using plugin mode as InjectManifest and give the path of the newly created service-worker.js file.

The custom service worker file needs to be as shown below:

workbox.core.setCacheNameDetails({prefix: "vue-pwa"});

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

self.addEventListener('message', (event) => {
    if (event.data && event.data.type === 'SKIP_WAITING') {
        self.skipWaiting();
    }
});

Let's change the cache name from "vue-pwa" to "vue-pwa-test" and build the application. If you look into the service-worker.js under the dist/ folder and if you see the changes there, you are good to go.

Also, you can see some import scripts added at the beginning of the file by Vue CLI which looks something like below.
importScripts("/precache-manifest.7b241a43a2278739512d45eb32884cc1.js", "https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
The precache-manifest has a different json config for different files to cache. Note, the file name to be cache will be different in each build. Now, build and deploy the application.

Note: each change in the application will be reflected in the browser after new content is updated and the app is reloaded or refreshed.



Now, click on "skipWaiting" and reload the page which will reload our application with new changes. We will do this skipWaiting from the application in the next tutorial by giving the user control of the app update. Or if you do it right away especially for testing you can add the following inside service-worker.js.
workbox.core.skipWaiting();

You can see the caching files under the cache storage tab.



The life cycle of the service worker is implemented by default. You can handle each event/hooks inside registerServiceWorker.js file as mentioned in step 3.

Now, you can especially handle different push notifications, background sync, using indexdb inside this custom service worker created.

5. Service Worker Life Cycle Event:

If you want to implement the lifecycle event on your own you can use them inside the service-worker.js file itself. Make sure to unregister the service worker from the registerServiceWorker.js file and register your service worker. It can be done in the main.js file.  Some of the life cycle events are below: 
self.addEventListener('install', (event) => {
  console.log("Installing ....................");
});
self.addEventListener('activate', (event) => {
  console.log("activateing ....................");
});
self.addEventListener('fetch', (event) => {
  console.log("fetching ....................");
});
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});
If you want to know more about these events please look Service Workers: an Introduction.

Share:

Wednesday, December 16, 2020

VueJs Progressive Web Apps(PWA): How to Change the App Name, Icon, Color, Display for Mobile Devices.

In this tutorial, I will show you how to create and change the Manifest file. The manifest file will allow the way of displaying our application, especially on mobile devices i.e showing app name, app icon for different size mobile screen, the color of the app, etc.

Please visit our previous articles on PWA:

Create a Simple VueJs Progressive Web Apps (PWA) and Deploy to Firebase


Create a Manifest file.

The default manifest file will be created when you build your application with Vue CLI. Let's build our application.

yarn build
Now you can see the manifest.json file under the dist/ folder. This is the file that we are going to modified according to our requirements.



To change this file first copy the file inside the public/ folder. On each build, all the files under the public folder will be copied to the dist/ folder so we have our changes in production.


 The manifest.json file looks like below:
{
  "name": "vue-pwa",
  "short_name": "vue-pwa",
  "theme_color": "#4DBA87",
  "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"
    },
    {
      "src": "./img/icons/android-chrome-maskable-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable"
    },
    {
      "src": "./img/icons/android-chrome-maskable-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "background_color": "#000000"
}

We will discuss each property used here. If you have difficulties generating this file make sure to create one with this structure.

If you deploy with this default configuration and open it into your mobile then you can see the below display.

Note: we are using the default vue CLI application for testing.


name :

This will be the name displayed on the screen(splash screen) before the application load the CSS. Please change the name you want for your application. When you click the icon then you will see this name and icon as a first screen.

short_name:

This is similar to the name property but displayed under the launcher icon as shown above.

theme_color:

The default theme color of the application.

icons:

Different icons used for different screen mobile devices. For e.g the different launcher icon size for the different screen for the android device looks as below:


Make sure to put different size image icon for your app under public/img/icons folders or if you want to use in a different folder inside public/ then use the same path on manifest.json file.

By providing different size icons, the icon will be used according to the different screen size devices.

start_url:

This will be the URL for the entry point when you add the app to the home screen.

display:

"that determines the developers’ preferred display mode for the website. The display mode changes how much of browser UI is shown to the user and can range from the browser (when the full browser window is shown) to fullscreen (when the app is full-screened)."

background_color:

This defines the background color of the splash screen before the application CSS is loaded. When you click the app on your device, initially it will load the background color with icons before the app is loaded.

For other properties and more descriptions please visit Web App Manifest. 

Finally, make changes to the properties under manifest.json and build the application and deploy. You can see the desired changes in your mobile devices.



Share:

Monday, December 14, 2020

How to Test Our VueJs Progressive Web Apps(PWA) Locally over HTTPs.

In this tutorial, I will show you how we can test our PWA application locally. The PWA needs an HTTPS connection to work properly. So, it's better to test the application over HTTPs locally.

Make sure you have a sample running PWA locally. I am using vuejs sample PWA application for testing purposes.

1. Build our application:


yarn build
This will create the dist folder which is deployment-ready.



2. Install an http-server package:

First, install http-server package globally, which helps to run the dist folder. For this, open a terminal or command prompt to run the following command.

For npm package manager:
npm install http-server -g

For yarn package manager:
yarn global add http-server

Make sure to refresh your terminal or command prompt after installing the package.

Now, run the application using this package.
http-server dist/
Where dist/ is the folder created while building the application. This will run the application. If you open the application, you will see that our application is not working properly as no service worker is registered.



3. Install and setup Ngrok to run the application.

Here, we are using the third-party service called Ngrok which is free for testing.

What it will do is it will simply tunnel our local server with a specific port over HTTPS which is what we want to test locally. 

Download it from Ngrok download.

Go to the downloaded folder and extract it. You can see the executable binary file. In order to run the file please follow as below.

For Windows:

Simply double click that .exe file. Which will open in the command prompt.

Now, you are ready to tunnel your local server. Use the following command to tunnel your server.
ngrok.exe http 8080
Make sure your application is running in port 8080 otherwise, use your own port instead.


You can see similar to the above. Now you can open the HTTPS tunneled URL.

If you are getting an Invalid Host header issue then you can simply run the below command instead which resolves the issue.
ngrok.exe http 8080 -host-header="localhost:8080"
For Linux: Go to the extracted Ngrok file directory and use the following command.
./ngrok http 8080




If you get the issue with an Invalid Host header then use the following command instead:
./ngrok http 8080 -host-header="localhost:8080"
Once, you open the URL, you can see the service worker for PWA will be working as below.





Share:

Sunday, December 13, 2020

How to Deploy VueJs Application to Firebase for Different Environment

In this tutorial, we are going to deploy our Vue application to the firebase server for different environments.

Before putting any project into production it needs to develop, QA first.

So, for different cases, we may need different configurations and need to use different server resources.

According to this requirement, we need to set up different configuration files for different environments. So while deploying, it can take a specific config for the corresponding environment.

Generally, what we are going to do is:

  1. Create different projects for different env in firebase
  2. Set up firebase hosting in our application
  3. Configuring test config file for different environment
  4. Deploy the application for different environment

1. Create projects in firebase for different environment

Go to the "https://console.firebase.google.com/" and create a project.

Here we are creating two sample projects for develop and qa environment.

- Give the name of the project, we are giving "develop-vue-test" to develop and "qa-vue-test" to qa environment








Note: Create two different projects for two different environments.

2. Set up a firebase hosting in our application.

Here, we are considering you already have your vuejs application. Go to the project directory and initialize the firebase.

- Install Firebase CLI:

For npm package manager:
npm install -g firebase-tools
For yarn package manager:
yarn global add firebase-tools

- Initialize your project:

firebase login
This will redirect you to login with a Google account. Use the same account to login which is used to create for the different firebase projects previously.


Now, initialize the firebase project using the following command:

firebase init




The above process will create the following two different files in your project directory:

- .firebaserc:

{
  "projects": {
    "default": "develop-vue-test"
  }
}
As we use default firebase project as "develop-vue-test" while doing firebase init.

- firebase.json
{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}
This is the firebase config file where you can see the setup we did previously. For e.g "public": "dist" as we choose dist as public.

3. Configuring test config file for the different environment:

Now let's create some config files in the project directory for different env.

For production:

.env.production

For develop:

.env.develop
VUE_APP_ENDPOINT=https://develop.com
You can create whatever config key-value pair here with the respective environment. We are using VUE_APP_ENDPOINT test sample.

For qa:

.env.qa
VUE_APP_ENDPOINT=https://qa.com
You can access that config file property anywhere by using:
process.env.VUE_APP_ENDPOINT



Now let's add a qa-vue-test firebase project inside firebase.json
{
  "projects": {
    "default": "develop-vue-test",
    "qa": "qa-vue-test"
  }
}
Let's go to the package.json file and add and change the build script to use this config file.

"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "develop": "vue-cli-service build --mode develop",
    "qa": "vue-cli-service build --mode qa"
  },
Here, we added two more scripts for develop and qa environment.

"develop": "vue-cli-service build --mode develop",
"qa": "vue-cli-service build --mode qa"

4. Deploy the application:

For develop:
yarn develop
Which will build the application for develop env.
firebase deploy


as inside the firebase.json file, the default project is selected as develop-vue-test so it will simply deploy to develop.


For qa:
yarn qa
firebase deploy -P qa
Make sure the name "qa" needs to same as the name of the project defined in firebase.json. This will simply deploy the build folder to "qa-vue-test" firebase project.

Finally, we have successfully deployed our vuejs application to firebase for different environments.

If you want to track the hosting inside the firebase console then you can go to the Hosting tab in the console.




Share: