Creating Your First Vue.js PWA Project
In our previous article, Why Progressive Web Apps, we have identified a few benefits that PWA provides to improve web applications for online and offline usage. With a bit of responsive design, Progressive Web Apps would be perfect for both mobile and desktop markets.
In this article, we will cover how to build our first PWA project with the Vue.js framework by implementing the PWA minimum requirements, configure Webpack to build a caching services worker for offline support and run the Google Lighthouse audit tool to identify improvement points.
Creating the Workspace
Anywhere on your computer, let’s create a directory named pwa-vue-app-1
.
All work will be performed within this directory so with our preferred choice of editor and terminal, open this directory.
Visual Studio Code is my choice of editor. It comes with an integrated terminal so I will not need to use an external terminal application. This article does not need anything fancy long as you can create files, folders, and execute terminal commands.
Before writing code, we need to perform a few pre-setup tasks. The first task is to create the folder structure to organize source and distribution code. Structures will vary per project and even user preference.
For this project, we will keep the structure simple. In the root directory, we will create directories dist
, src
, and static
.
dist
— The directory that contains distribution files and will be hosted on an external hosting service, for example, Google Firebase.src
— The directory that contains un-built application source code, for example, JS and Vue files.static
—The directory contains static files used within the application. The build process copies these files into thedist
folder. Example files are images, icons, third-party libraries, PWA manifest, and service worker.
Additionally, we will create the components
directory inside the src
directory. The components directory contains all of the individual components view, styling, and logic that our application uses.
Installing NPM Dependencies
The second pre-setup task is to initialize our project with NPM and install dependencies.
To initialize our project with NPM, in the pwa-vue-app-1
directory, execute in a terminal the command:
$ npm init
The initialize process will ask a few questions about the project. For this article, default values are OK. The package.json
file is created once completed. The values can be customized, later, from the package.json file.
Once initialized, we can start installing the build and third-party dependencies. For the build dependencies, we will execute the following command in the root directory:
$ npm i -D @babel/core @babel/preset-env babel-loader clean-webpack-plugin copy-webpack-plugin css-loader html-webpack-plugin vue-loader vue-style-loader vue-template-compiler webpack webpack-cli webpack-dev-server
Build dependencies consist of:
- Babel and Babel’s preset-env — used for converting newer ECMAScript code into a backward compatible version for older browsers support.
- Webpack, Webpack plugins and loaders — used as our module bundler.
- Vue Template Compiler — pre-compiles our Vue templates into render functions to remove runtime-compilation.
Next, third-party dependencies, which are used by the application code, will be installed with the following command in the root directory:
$ npm i vue vue-router
Configuring Webpack
In the root directory of our project, create a file called webpack.config.js
and add the contents of the configuration posted below. This will allow us to build and preview our application.
I will point out a few of the options that are important to know but not cover all configurations detail.
entry
is the property that contains the file(s) which Webpack starts from when bundling. In this example,app.js
as our entry point. If the entry file name or path is customized, this property must be updated. You can see this option on line 12 of the sample configuration file.
entry: './src/app.js',
CleanWebpackPlugin
plugin is used to delete thedist
directory before each build, to remove old and unused files. You can see this option on line 55 of the sample configuration file.
new CleanWebpackPlugin(['dist']),
resolve.alias
is the property that simplifies writing import paths. In this example,@
alias is added to shorten paths to our source code. You can see this option on line 50 of the sample configuration file.
'@': path.resolve(__dirname, 'src')
Writing Example Code
Now that we have our structure, dependencies, and build tool configured, we can begin adding our application code.
index.html
First, create the file index.html
in the static
directory with the content below.
There are two important things about this file.
- The div element, inside the body, has an id of
app
. The Vue initializer uses this id as a target to render in. If the id is modified, the Vue initializer options must also be updated. We will cover the initializer in theapp.js
file. - The script tags to load the application’s JavaScript is not hardcoded in this file. This file is used as a template by the
HtmlWebpackPlugin
during the build process. The plugin injects the script tags automatically and places the generatedindex.html
file into thedist
directory.
app.js
In the src
folder, create the file app.js
and add the contents below.
The app.js
file is our applications entry file which initializes an instance of our Vue app.
During the instance creation, we pass in the targeting element, routes, accessible components, and templates. I will focus on the element and router options.
el
is a selector string or HTML element to an existing DOM element. The app will mount to this element. In our example, we passed in a selector string of#app
. As mentioned previously, if the id inindex.html
was customized then this option must also be updated.router
is an instance of VueRouter that contains a mapping of routes to components.
router.js
In the src
folder create the file router.js
and add the contents below.
This file contains a collection of known URL routes and maps to its associated component. We also provided a fallback component for unknown routes. This handles the “Page Not Found” use case.
App.vue
In the src
folder create the file App.vue
and add the contents below.
This file is the base template of the application. It consists of router-link
(s) and a single router-view
. Once a link, the router-link, is clicked, the associated component loads into the router-view element.
Component Pages
Create the next three files in the src/components/
directory with its respective content. These files are fillers to provide a working example of routing. The difference between these files is the header text and color.
- src/components/Home.vue
- src/components/Page1.vue
- src/components/PageNotFound.vue
Previewing & Auditing for PWA with Chrome
Now that we have finished adding the code to the project, we can preview and audit the application.
To compare your code with the covered material, you can view the source code on GitHub.
Note:
For the covered material up to this point, please make sure to view theno-pwa
branch.
To preview the application, we need to first add NPM scripts. In the package.json
file, update the property scripts
with the following:
"scripts": {
"dev": "webpack-dev-server --progress"
},
The dev
script uses the webpack-dev-server
dependency to start a development web server.
Let’s preview the application, by running the npm run dev
command in the project’s root directory. It should automatically open your default browser to https://localhost:9000
. If you need to change the port, you can modify the server configurations in the webpack.config.js
file.
Webpack development server is perfect for viewing and testing application code during development!
Google Chrome — Lighthouse Audits
For auditing, I recommend deploying the application to a hosting service such as Firebase. Running an audit against your application on a hosted service can provide a more accurate result. This article will not cover how to deploy but will display the results from each audit.
One of the PWA requirements is that the application is hosted and served from an HTTPS protocol with valid SSL certificates. We had configured webpack-dev-server to use a self-assigned certificate but, it still does not meet the PWA requirements. This tool is strictly for development and testing and will always lack the features and settings from that a production ready web server provides.
To run Google Lighthouse for auditing, we need to open the DevTools. If you are a Mac user, you can use the following shortcut command Command+Option+I
. If you use Window, you can press either F12
or Control+Shift+I
. Next click on the Audits
tab at the top. You should see something like this:
Next, click on the Run audits
button at the bottom and watch it perform. Once the audit is complete, it will point out areas that need improvement for a higher PWA score as well as performance, accessibility, best practices, and SEO.
Comparing the two screenshot above, we can see that our application on Firebase has a higher PWA, performance, and best practices score then locally. Firebase hosting takes care of some of the server side requirements such as HTTP redirect to HTTPS.
Below, is a list of items where the application failed to meet the requirements for a high PWA score.
In the next sections, we will implement the minimum requirements to make our application PWA as well as covering the items from the PWA checklist.
Implementing the Minimum PWA Requirements
Let’s start adding the minimum PWA requirements and correction to increase our PWA score.
manifest.json
First, we will add the manifest.json
file in the static
directory with the following content:
This file contains the necessary information for installing to the home screen, creating a custom splash screen, and details about the application.
Next, add in the head
tag of the index.html
file the following line:
<link rel="manifest" href="/manifest.json" />
Icon
In the manifest.json file, we defined our application icons. In the Google Developers Web Fundamentals documentation, it is recommended that both 512 x 512 px icon and 192 x 192 px icons are provided. These icons are used for the home screen, install notification, and custom splash screen.
For this example, I made the icons with Photoshop and placed them in the static
directory. You can get mine from here:
Service Worker
To simplify building our service worker for caching, we will use the Webpack plugin sw-precache-webpack-plugin
. This plugin automatically creates a service worker file with a collection of the file paths that had been created by Webpack.
- Install New Development Dependency
In the root directory of the project run the command.
npm i -D sw-precache-webpack-plugin
- Update
webpack.config.js
Add to the top line:
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
Add in the plugins
option array the plugin usage:
new SWPrecacheWebpackPlugin({ cacheId: 'my-pwa-vue-app', filename: 'service-worker-cache.js', staticFileGlobs: ['dist/**/*.{js,css}', '/'], minify: true, stripPrefix: 'dist/', dontCacheBustUrlsMatching: /\.\w{6}\./})
Below plugin:
new CopyWebpackPlugin([{ from: path.resolve(__dirname, 'static'), to: path.resolve(__dirname, 'dist'), toType: 'dir'}]),
Adding noscript
If for any reason an end user has JavaScript disabled on their browser, we need to notify, with the noscript
tag, that our application requires JavaScript.
To fix this:
Open the file static/index.html
and add to the body
element line:
<noscript>To run this application, JavaScript is required to be enabled.</noscript>
Set Address Bar Background
Open the file static/index.html
and add to the head
element line:
<meta name="theme-color" content="#FFFFFF" />
Second Lighthouse Audit
Let’s run the second audit to see how our application scores after implementing the minimum PWA requirements and corrections from the first audit.
To compare the PWA implementation code with the covered material, you can view the source code on GitHub.
Note: The current material is on the
pwa
branch.
Conclusion
As you can see, creating a PWA project with the Vue.js framework is very easy. The initial setup of the workspace, dependencies, and build configurations only takes a couple of minutes of our time, but after that, it all application code.
Additionally, with the Google Lighthouse audit system, we can periodically test our application to pinpoint areas that need attention and get access to resources that give detail explanation of each issue and possible solutions.
Lastly, using a bundler tool such as Webpack provides many great advantages. Some of these advantages are simplifying and speeding up the development and building. As we saw in this example, we used the pre-cache service worker plugin create our service worker and the clean plugin to keep our distribution package clean.
Hope you find this useful and gives you a great starting point for your first PWA project.
Update 2019/09/02: All dependencies and related webpack
configurations, in the sample project, were updated. This included using the latest version of vue
and vue-router
.