The original repository is a stand-alone game, meaning it does not require a web server to execute, just a browser. You can right-click the index.html file and choose to open it in your favorite browser. You can still do this after registering a service worker and may not notice any differences. But if you open the browser console (F12 Developer Tools), you will most likely see an error.
This error can be attributed to service worker requirements. Service workers, like most new APIs supported by browsers, require HTTPS protocol. This requirement raises the default security level and gives the browsers a minimum level of trust in your site ownership.
The service worker specification relaxes this requirement for localhost addresses. Localhost is a common way to reference your local machine, which is typically a development environment. Because it is unlikely you are going to hack yourself, browsers tend to let you do what you want—except when you open files directly from the file system.
When localhost is used to load an asset, the browser is making a traditional network request, which requires a web server to respond. This means you, the user of the local machine, has gone through the effort of launching a local web server. This is not something the average consumer knows how to do.
A file, opened from the file system, is different. Anyone can send you an index.html file that loads scary code, designed to steal your identity or worse show endless loops of cat videos! By not honoring the direct file system, access browsers are protecting you from registering a malicious service worker script. Trusting a localhost web server makes development easier by avoiding the messy process of registering a localhost SSL certificate.
There are a variety of local web servers you can run. In recent years, my preference is node connect, which I execute as a Grunt task (https://love2dev.com/blog/make-a-local-web-server-with-grunt-connect/). Because connect is a node module, you can launch it directly from the command line or a custom script. There are modules for your favorite task runner, such as Gulp and so on. Besides, node is cross-platform, so everyone can use connect.
If you are familiar with installing node modules, you can skip ahead. If node and connect are new to you, this section will serve as a simple primer to get you up and running to run all the samples applications in this book on your local machine.
The first step to loading a node module is to install them from https://www.npmjs.com/ or one of the emerging package manager sites. You can manage this from the command line if you like, or you can define the modules needed in a package.json file.
You can read more about the package.json format here (https://docs.npmjs.com/files/package.json). For our purposes, grunt and the grunt-contrib-connect module are devDependencies. You could also define a dependencies section if this were a node application.
Grunt is a task runner that gained popularity several years ago and is still my preferred task runner. Task runners, and there seems to be a new one every week, help you organize repeatable tasks into repeatable recipes. I use Grunt and custom node scripts to build and deploy my PWAs. Think about your task runner as a command-line control panel to manage your application:
{
"name": "2048",
"version": "1.0.0",
"description": "2048 Progressive Web App",
"author": "Chris Love",
"private": true,
"devDependencies": {
"grunt": "*",
"grunt-contrib-connect": "*"
}
}
Both Grunt and the Grunt connect module are node packages and must be downloaded in order to execute. The package.json file gives npm a configuration so it can manage your packages. This way, you can quickly set up your project on any machine without having to maintain your node dependencies as part of the source code.
If you have cloned the sample repository, you will note that the node modules were excluded from the source code. That's because they are not part of the application itself. They are a dependency and npm helps you recreate the desired environment.
To install the packages, you need to open a command line and change to your source code's folder. Next, you must execute the following command:
>npm install
This kicks off the npm installation process, which downloads your modules and their dependency chain. When completed, you have everything you need to run or build your application.
Next, you will need to create a gruntfile.js. This is where you tell Grunt what tasks you want to run and how you want them to run. If you want to know the details of using Grunt, visit their website (https://gruntjs.com/):
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-connect');
// Project configuration.
grunt.initConfig({
connect: {
localhost: {
options: {
port: 15000,
keepalive: true
}
}
}
});
};
Since we are only using the connect module, the 2048 gruntfile is very simple. You need to tell Grunt to load the connect module, then register the task to run in the initConfig function.
2048 is a very simple application, which keeps our customization to a minimum. I arbitrarily chose port 15000 to serve the application and chose to have keepalive open. There are many options you can define. More details are available on the grunt-contrib-connect npm page (https://www.npmjs.com/package/grunt-contrib-connect).
The only task left to do is start the connect web server. This is done from the command line. If you still have the command line open from when you performed the npm install, you can reuse it. If not, repeat the process of opening a command line and changing to the project's folder:
>grunt connect
Running "connect:localhost" (connect) task
Waiting forever...
Started connect web server on http://localhost:15000
Execute grunt connect and you should see the preceding example output. Note that the command continues to execute. This is because it is a server, listening to requests on port 15000. You cannot execute additional commands at this prompt.
You can now load the 2048 game in your browser by entering http://localhost:15000 in the address bar.