Optimization
If you've been writing applications targeting the web platform for many years, you'll have seen just how many changes the web has gone through. What started off as a simple document viewer now sees us having to deal with complex build steps, state management patterns, continuous review of performance and compatibility, and much more.
Thankfully, the popularity of JavaScript and subsequent tooling means that there are templates and tried-and-tested techniques that we can use to optimize our application and deployment.
In this chapter, we'll take a look at the following topics:
- The vue-pwa template from the Vue CLI
- Features of Progressive Web Applications
- Using ngrok to view localhost applications on any device
- Using Firebase hosting to deploy web applications
- Continuous Integration and what it means for large-scale projects
- Automatically running tests on each Git commit
- Automatically deploying to Firebase hosting on each Git commit
Progressive Web Applications (PWAs)
PWAs can be defined as applications that use the capabilities of the modern web to deliver thoughtful, engaging, and interactive experiences. My definition of PWAs is one that encompasses the principle of progressive enhancement. We could certainly take advantage of everything that PWAs have to offer, but we don't have to (or at least not all at once).
This means that not only are we continuing to improve our application over time, but adhering to these principles forces us to think in the perspective of a user who has bad internet connectivity, wants an offline-first experience, needs home-screen accessible apps, and so on.
Once again, the Vue CLI makes this process easy for us, as it provides a PWA template. Let's create a new Vue application with the appropriate template:
# Create a new Vue project
$ vue init pwa vue-pwa
? Project name vue-pwa
? Project short name: fewer than 12 characters to not be truncated on homescreens (default: same as name)
? Project description A PWA built with Vue.js
? Author Paul Halliday <[email protected]>
? Vue build runtime
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Airbnb
? Setup unit tests with Karma + Mocha? No
? Setup e2e tests with Nightwatch? No
# Navigate to directory
$ cd vue-pwa
# Install dependencies
$ npm install
# Run application
$ npm run dev
Throughout this chapter, we'll be looking at the benefits that this template gives us, and ways we can make both our application and operations more progressive.
Web application manifest
You may have seen the benefits of applications that use a web app manifest already—if you've ever been on a website that asks you to install this on your home screen or if you've noticed that the color of the address bar change from default gray to a different color on Android Chrome, that's a progressive app.
Let's head over tostatic/manifest.jsonand investigate the contents:
{
"name": "vue-pwa",
"short_name": "vue-pwa",
"icons": [
{
"src": "/static/img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#4DBA87"
}
We have the option to give our applicationnameandshort_name; these will be shown when installing on the home screen of a device.
Theiconsarray is used to provide varying sizes of our icon for a high-definition experience across devices. Thestart_urldefines the file to be loaded upon startup when installed on a user's home screen and thus points towardindex.html.
We can change how our application appears when running on a device as a PWA with the display attribute. There are various options available, such asbrowser,standalone,minimal-ui, andfullscreen. Each one changes how our application is displayed on the device;(https://developers.google.com/web/fundamentals/web-app-manifest/)
here's an example of both browser and standalone:
Display options—the web app manifest
We can also take advantage of thebackground_coloroption to change the color of the splash screen background when our PWA starts, as seen in the following screenshot:
If we want to change the color of the toolbar, we can use thetheme_coloroption (we'll look at an example as we move ahead).
There are other options you can pass to your web app manifest and you should customize these based on the needs of your project. You can find more information about the web app manifest on MDN athttps://developer.mozilla.org/en-US/docs/Web/Manifest.
Testing on a device
If we want to test our application on a device without worrying about deployment, we could use a tool, such as ngrok, to create a tunnel between our localhost and the outside world. This allows us to view our application on any device with a public URL, and once we close the connection, the URL and subsequent application disappear.
Download ngrok by navigating tohttps://ngrok.com/downloadand following the installation steps for your platform.
Ngrok also can be installed vianpmtyping :
npm install ngrok -g
As our Vue application is running on port8080, we can start ngrok and tell it to serve from that port. Run the following command in your Terminal with ngrok installed:
$ ngrok http 8080
We then get the following result in our Terminal:
We can then navigate to this URL on any device and see the following results on screen:
Isn't this much more of a native experience? Now we have a colored address/status bar by default. We also get access to much more with the power ofServiceWorkerin production mode. Before we dive into that, let's look at how we can deploy our application to a more permanent URL using Firebase.
Firebase deployment
Firebase is a platform by Google that allows us to take advantage of everything from real-time databases, remote configuration, push notifications, and much more. Perhaps more important for our use case is the potential for static file deployment, and this is something we'll be taking advantage of.
The platform has three different packages available, each offering different levels of service, with the first tier being free and then the following two tiers requiring payment.
Start off by navigating tohttps://firebase.google.comand logging in with a Google account by clicking onSIGN IN, and then, clickGO TO CONSOLEat the top right.
We can then create a new Firebase project by selecting +Add Projecton the Firebase dashboard and subsequently selecting a project name and country.
We will then navigate toProject Overview, where we can choose to add Firebase to our project and a variety of other options. We're looking for hosting, as we're interested in deploying our static content. From the left-side menu, click onHosting:
We'll be on this screen quite a bit, as it allows us to revert deployments as well as see other usage metrics. Since we haven't made our first deployment yet, the screen will look similar to this:
If we click onGET STARTED, we will receive a message stating that we need to download the Firebase tools. This is a CLI that allows us to manage our Firebase project from within the Terminal.
Install Firebase tools by running the following command in the Terminal:
$ npm install firebase-tools -g
We can then follow the steps outlined in the next step of the hosting wizard, but we won't be using the deployment step just yet. The wizard should look like the following:
Let's start off by logging in to the Firebase console by running the following in the Terminal:
$ firebase login
Select a Google account and give it appropriate permissions. You should then be provided the following screen:
We can then initialize a new Firebase project inside of ourvue-pwaproject. Run the following command in your Terminal:
$ firebase init
At this point, we can use the keyboard to navigate to hosting and select it with the spacebar. This should make the circle green and it tells Firebase that we'd like to set up hosting within our project.
We then have to match our local project with the one that's inside of our Firebase dashboard. Select the project you created earlier from the list:
It should then ask you questions related to the setup—answer them like so:
We've now got the ability to deploy to Firebase at will. We'll need to build our project for production to appropriately generate adistfolder with the contents of our application. Let's run the following command in the Terminal:
$ npm run prod
Then, to deploy to Firebase, we can run the following command:
$ firebase deploy
After a short while, you should be given a navigable URL that contains our application served over HTTPS:
Our Firebase dashboard has also been updated to reflect our deployment:
If we then navigate to the URL, we should get our project as expected:
Also, because we built our application using a production build, we can disconnect it from Wi-Fi or check the offline box inside of your Developer Tools. Upon doing so, we will find that our application still runs as expected because we have aServiceWorkerrunning on all production builds.
Continuous Integration (CI)
There are a variety of CI platforms available, such as Travis, GitLab, Jenkins, and countless others. Each platform often serves a common goal, that is, automating deployment and the challenges that come along with it.
Sure, we could deploy our site, run our tests, and continue with other items in our forever increasing build steps. Not only is this a tedious process, but it also gives us many opportunities to make mistakes. Furthermore, it also means that each step has to be documented for every member of the team, the documentation has to be kept up to date and is not exactly scalable across an organization.
For our examples, we'll be using Travis CI, and the first objective that I'd like to tackle is automatically running our unit tests. To do this, we'll need one or more unit tests inside of our project.
Unit tests
We covered testing our Vue.js applications in the preceding chapter, so wouldn't it be nice to automatically run our tests each time we push a new build? Let's quickly set up some tests inside of our project and integrate it with Travis:
# Install necessary dependencies
$ npm install jest vue-test-utils babel-jest vue-jest --save-dev
We can then add a new script that runsjest:
{
"scripts": {
"test": "jest"
}
}
Next, add thejestconfiguration to yourpackage.json:
"jest": {
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"moduleFileExtensions": [
"js",
"vue"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
}
}
Finally, we can update ourbabelconfiguration inside of.babelrc:
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": [["env", { "targets": { "node": "current" } }]],
"plugins": [ "istanbul" ]
}
}
}
We can then make a sample test inside ofcomponents/__test__/Hello.spec.jsthat simply checks whethermsginside of our data matches a string:
import { mount } from 'vue-test-utils';
import Hello from '../Hello';
describe('Hello.vue', () => {
it('should greet the user', () => {
const wrapper = mount(Hello);
expect(wrapper.vm.msg).toEqual('Welcome to Your Vue.js PWA');
})
})
As expected, we can then runnpm testto execute our tests:
Creating a Git repository
To use continuous integration with Travis CI, we'll need to upload our project to GitHub. If you haven't already got Git on your machine, download it fromhttps://git-scm.com/and subsequently create a GitHub account athttps://github.com.
Create a new repository for your project athttps://github.com/new, or by clicking on theNew repositorybutton by clicking on the+at the top-right corner of the screen.
We can then give our repository a name and make the visibility eitherPublicorPrivate:
Once we click on theCreate repositorybutton, we're greeted with a variety of ways in which we can upload our repository to GitHub. The only problem is that we haven't made our PWA project a Git repository yet.
We can do this inside Visual Studio Code or the command line. In Visual Studio Code, click on theNew repositorybutton. If you've just installed Git, you may need to restart your editor for this button to appear. This is how it should appear inside of Visual Studio Code.
We can then make a new commit with a simple message, such asFirst commit, and subsequently click on the tick:
We can then push these changes up to the repository on GitHub by following the steps highlighted inside...orpush an existing repository from the command linegiven in the following image:
Any future changes to our repository will be pushed to this remote repository. This is important because when we create our Travis account, it'll automatically get access to all of our GitHub repositories.
Connecting to Travis CI
Let's navigate tohttps://travis-ci.org/and click onSign in with GitHub.After giving Travis any necessary permissions, you should then be able to see a list of repositories attached to your account. We can tell Travis that we'd like it to watch for changes in this repository by flicking the switch to green:
Configuring Travis
The next thing to do is add an appropriate.travis.ymlconfiguration file to our project. This will tell Travis what to do each time we push a build to GitHub. As such, there are two distinct phases that happen when we build with Travis:
- Travis installs any dependencies inside of our project
- Travis runs the build script
We can hook into various stages of the build process such asbefore_install,install,before_script,script,before_cache,after_success,after_failure,before_deploy,deploy,after_deploy, andafter_script. All of these are relatively self-explanatory, but if it seems like a lot to take in—don't worry, we'll only be hooking into a select few of these stages.
Let's add a file named.travis.ymlto the root of our project and add options one step at a time. We can start off by defining the language of our project and as we're using Node, the subsequent Node environment version also:
language: node_js
node_js:
- "9.3.0"
Thenode_jsversion I've selected matches the same as my environment (this can be checked withnode -v), but if you need to target a specific version of Node (or more than one version), you can add them here.
Next, let's add that we'd only like to trigger builds on themasterbranch:
branches:
only:
- master
Then, we will need to tell Travis what script to run frompackage.json. As we'd like to run our tests, we'll be running the test script:
script:
- npm run test
Finally, let's state that we'd like to receive email notifications for every build:
notifications:
email:
recipients:
- [email protected]
on_success: always
on_failure: always
This gives us the following file:
language: node_js
node_js:
- "9.3.0"
branches:
only:
- master
script:
- npm run build
- npm run test
notifications:
email:
recipients:
- [email protected]
on_success: always
on_failure: always
If we then push these changes to our repository and sync it with the origin, we should be able to watch our Travis console as it runs our tests. It may take a few minutes for Travis to start the build as follows, so be patient:
If we scroll down to the bottom of the log, you can see that our project was built forbothproductions and our tests run:
Awesome! We can now run our tests and hook into various stages of the build process with Travis CI. Given that we're building our project for production on Travis, we should be able to deploy this build to Firebase automatically.
Let's change ourHello.vuecomponent to have a new message (and also make our test fail):
export default {
name: 'hello',
data() {
return {
msg: 'Welcome to Your Vue.js PWA! Deployed to Firebase by Travis CI',
};
},
};
Service worker
When building our application for production using thevue-pwatemplate, it includesServiceWorker. This is essentially a script that runs in the background and allows us to take advantage of offline-first approaches, push notifications, background sync, and more.
Our application will now also prompt our user to install the application on their home screen, as follows:
If we are disconnected from the internet, we'd also get an offline-first experience, as the application still continues to function. This is one of the major benefits we get when using thevue-pwatemplate, and if you'd like to read more aboutServiceWorkerand see how you can customize this to your needs, Google has a great onboarding guide athttps://developers.google.com/web/fundamentals/primers/service-workers/.
Summary
In this chapter, we investigated the PWA template from the Vue CLI and subsequently looked at how we can automatically deploy and test our application as it continues to grow. These principles allow us to continually ensure that we can spend more time developing features and less time maintaining deployment documentation and following rudimentary tasks each time.
In the following chapter, we'll cover Nuxt, a framework that allows us to create server-side rendered/static applications using Vue. Nuxt also has an interesting folder-based routing structure, which gives us a lot of power when creating Vue applications.