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.
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.jsunder /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.
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:
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.
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:
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.
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.
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.
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.
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:
Create different projects for different env in firebase
Set up firebase hosting in our application
Configuring test config file for different environment
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.
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.
In this tutorial, we are going to create a simple VueJs PWA application and also show you how to deploy it to firebase. As we know that PWA is being more famous these days due to its very fast performance and can be used for different platforms with a single code base as well as the offline functionality and caching support.
1. Install Vue CLI
If you haven't installed the Vue CLI, open the command prompt or terminal and run the following command to install it globally.
- For npm package manager:
npm install -g @vue/cli
- For yarn package manager:
yarn global add @vue/cli
2. create a VueJs PWA project:
vue create vue-pwa
Now, select the manual option
Select Progressive Web App (PWA) Support option from the list. As you need to go to that option using the down arrow on the keyboard and hit the spacebar to select that option. Also select the other option if you are going to use them like Router, Vuex, etc.
Now, go to the project directory and run the application.
cd vue-pwa
yarn serve
Vue CLI created a sample demo application for us so, we are using the same for this tutorial. If you look into the Application tab by doing the inspect element of the above running project, there you can see the Service Workers. The main heart of the PWA is this service worker. As if we run the PWA application locally the service worker will not work, as it required an HTTPS secure connection.
The service worker is the script that will run in the background separately from the application which helps to install, activate, caching of our application. There are more thing about service worker, will discuss in the future article.
So how we can test the PWA application. As we can use some third-party services as well as we can simply deploy to firebase.
3. How to test our PWA application locally:
- Build the application in production mode:
yarn build
This will create the deployment-ready dist folder.
First, run this locally using http-server package. In order to do the show first install it globally.
npm install http-server -g
Now, run the dist folder:
http-server dist/
Which will run the application. Now what we need to do is tunnel our local server with HTTPS. Please follow this Tunnel local server to the public internet with HTTPS using Ngrok. This will tunnel our local server over HTTPS. Now open the tunneled URL. You can see the service worker as follows.
Also, you can see the + icon to install your PWA app in the browser.
If you run the same tunneled URL on the mobile then you will get the following screen to install your PWA application.
Add vue-pwa to Home screen if you click this, it will add the application to the home screen so that you can later open it by simply clicking it.
4. Deploy to firebase.
Now, let's deploy the build dist folder in the firebase server.
- Go to the firebase console "https://console.firebase.google.com/"
- Create a project by giving the project name.
- Installing firebase in our system.
Open the command prompt or terminal and install firebase globally.
npm install -g firebase-tools
Initialize the project:
Make sure to go to the project directory.
firebase login
This will ask for a google login. You can authenticate the google account where your firebase console project is created.
If you want to logout use the following command.
firebase logout
Now, initialize the project:
firebase init
This will ask a couple of question make sure you insert the right as below:
We are simply using it for hosting our application so chose the same option.
Make sure the above setting. The public directory will be dist in our case, as we are deploying the dist folder.
This will create two files in our project:
- .firebaserc
where you can find the project's configuration. Make sure you have the same project name in the "default" section to that create on the firebase console. While deploying it, will use the same firebase console project created. In my case, it is "vue-pwa-7ed80". The config file looks like below.
{
"projects": {
"default": "vue-pwa-7ed80"
}
}
- firebase.json
where all the hosting configuration is done. The config file looks like below.
This will deploy our application to the firebase server. You can see the deployment history and track from the console under the Hosting section inside the firebase console.
Firebase gives the live HTTPS URL which you can see in the firebase console. If you run that URL you will see the service worker will register and can be run the application as a PWA application.
Finally, we created a simple VueJs application with PWA support and successfully deployed it to the firebase.
The HTML file used will show the camera image button to capture the photo. Here, we are using canvas height and width for the photo size. You can always adjust the different size photo by adjusting canvas height and width.
This function simply toggles the camera to capture the photo. And start streaming the video. Let's implement the function used inside this toggleCamer().
startCameraStream() {
const constraints = (window.constraints = {
audio: false,
video: true
});
navigator.mediaDevices
.getUserMedia(constraints)
.then(stream => {
this.$refs.camera.srcObject = stream;
}).catch(error => {
alert("Browser doesn't support or there is some errors." + error);
});
},
The above function will start the camera by using the navigator mediaDevices interface which will access to the connected media input device, in our case its camera. And asign the streaming to canvas dom element to show the video. Here we are setting the constraints as audio is false because we don't need the audio to capture the photo.
When a user clicks the camera button, then it will take the video streaming dom context and captured the 2d photo with the given width and height. We are using the setTimeout because video streaming will take some time to stream.
Let's implement the self.addToPhotoGallery() used in the above function. This is to preview the captured photo. For this, we are using the "vue-picture-swipe" library. So first let's add this to our application.
Finally, using self.uploadPhoto() we can upload the captured picture to the server.
uploadPhoto(dataURL){
let uniquePictureName = this.generateCapturePhotoName();
let capturedPhotoFile = this.dataURLtoFile(dataURL, uniquePictureName+'.jpg')
let formData = new FormData()
formData.append('file', capturedPhotoFile)
// Upload api
// axios.post('http://your-url-upload', formData).then(response => {
// console.log(response)
// })
},
generateCapturePhotoName(){
return Math.random().toString(36).substring(2, 15)
},
dataURLtoFile(dataURL, filename) {
let arr = dataURL.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type: mime});
},
generateCapturePhotoName() will generate the unique name for each captured picture, and to send to the server, first we are converting the dataUrl value to file using dataURLtoFile().
The overall implementation of the component Camera.vue looks like as below:
In this tutorial, we are going to learn how to create a library and a web component of the Vuejs application, so that we can reuse them as a library in a different application and a custom HTML element in different webpages.
Using VueCli 3.x it's very easy to build our application. It gives some command to create them.
1. Create a sample Vuejs application:
Open the command prompt or terminal and use the following command:
vue create vue-build-target-app
You can either select the Default option so that you don't manually setup. This will default use the yarn package manager so, make sure to have package manager installed. Also, you can manually select features option.
Now, go to the project directory and run the application using the command:
cd vue-build-target-app
yarn serve
If you open the project, you can see the default component called HelloWorld.vue. We are using the same component to test.
2. Build as a Library:
Note: In lib mode, Vue is externalized. This means the bundle will not bundle Vue even if your code imports Vue
While building as a library even if we are importing the Vue in the component it will not use that in the bundle.
This will build the single component HelloWorld.vue as the library. So, what you need to do is place the above command inside the package.json file under scripts.
This command will build the target files inside dis folder.
dist\HelloWorld.umd.js is the UMD bundle that can be served in the normal HTML file. As you can see the sample use case inside the dist folder contain the following demo.html file:
Here, we are using different types of string value to test whether it is null or empty. In order to test we are simply creating the isNullOrEmpty(String str) method, which will return true if the string is null or empty and false if it is not. If the first condition is satisfied it will not test the second one because we are using OR logic. So, even if the "str" is null it will not throw an error.
The reason behind using trim() is to remove any leading or trailing white space from the given string. So that isEmpty() method will not consider the empty string with white space as a non-empty string.
Basically, isEmpty() will test the length of the string to return the boolean value. So, if the given string contains white space, even if the string is empty it will return false.
This is a short tutorial to show how to convert the list of strings into the
comma-separated string.
1. In Java 8 and later:
- Using String.join()method.
import java.util.Arrays;
import java.util.List;
public class JavaStringJoin {
public static void main(String[] args) {
List <String> stringList = Arrays.asList("apple","banana","grapes");
String joinedString = String.join(",", stringList);
System.out.println(joinedString);
}
}
Output:
apple,banana,grapes
This will simply join each element of the list with the delimiter provided. Here, we are providing "," as a delimiter. If the element present in the list is null then it will join the "null" to the string. If the delimiter is null then, it will throw Null Pointer Exception.
- Using stream API:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStringJoin {
public static void main(String[] args) {
List <String> stringList = Arrays.asList("apple","banana","grapes");
String joinedString = stringList.stream().collect(Collectors.joining(","));
System.out.println(joinedString);
}
}
- Using StringJoiner:
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
public class JavaStringJoin {
public static void main(String[] args) {
List <String> stringList = Arrays.asList("apple","banana","grapes");
StringJoiner stringJoiner = new StringJoiner(",");
for (String element : stringList){
stringJoiner.add(element);
}
System.out.println(stringJoiner.toString());
}
}
Actually, String.join() uses this StringJoiner mechanism.
The output will be the same as the previous example.
2. You can use StringBuilder to build the concatenated string:
import java.util.Arrays;
import java.util.List;
public class JavaStringJoin {
public static void main(String[] args) {
List <String> stringList = Arrays.asList("apple","banana","grapes");
StringBuilder stringBuilder = new StringBuilder();
int size = stringList.size();
for (int i = 0; i < size; i++) {
stringBuilder.append(stringList.get(i));
if (i < size -1){
stringBuilder.append(",");
}
}
System.out.println(stringBuilder.toString());
}
}
3. If you are using Apache's commons library, you can use StringUtils.join() method.