Transpiling and Bundling

The standard on which JavaScript is based is known as ECMAScript, and maintained by the ECMA General Assembly. It has been under continuous development since 1997.

ES6 Features

Version 6, also known as ECMA 2015, adds some extremely desirable functionality, including import/export and syntactic sugar for declaring classes.

Import/Export

ES6 supports modularizing code with import/export functionality. Essentially, methods, classes, and variables intended to be used outside of a code file are exported with an export statement:

// example.js export function foo() {} export const G = 9.8 export class Frog {}

These can then be imported into another code module for use with an import statement:

import {foo, G, Frog} from './example'; foo(); console.log('Gravity is ' + G ' m/s^2'); var kermit = new Frog();

You can also define a default export (only one per code module):

// vector.js export default class Vector { construtor(x, y) { this.x = x; this.y = y; } }

which is the default import from the module:

import Vector from './vector'; var v = new Vector(10, 10);

Class Definitions

ECMA also supplies syntactic sugar for defining classes, including constructors and methods. ECMA6 classes still use prototypical inheritance, but look more familiar to many programmers:

class Bear { constructor(name) { this.name = name; } growl() { console.log("Grrr"); } } class Grizzly extends Bear { constructor(name, weight) { super(name); this.weight = weight; } growl() { console.log("GRRRRR!!!"); } }

String Template

ECMA 6 also introduces a new string template syntax using tick marks which can simplify concatenation:

var name = 'Timmy'; console.log(`Hello ${name}, would you like to play a game?`);

Any arbitrary JavaScript code can be placed inside the ${}, and it will be converted to a string and concatenated into the the template string at runtime.

Transpiling ECMA6 to ECMA5

Most browsers support the full functionality defined by ECMAScript version 5, but lag behind on implementing highly-desirable features of version 6 and later. Where new features are syntactic sugar, or are implementable with shims, we have the possibility of transpiling (compiling a language into the same language) JavaScript code to an form using only syntax supported by ECMA version 5.

The tool we will use for this is webpack, which provides both transpliling and bundling functionality (bundling refers to merging all code to a single release file). It also has a lot of functionality for working with CSS files, images, etc. that may be useful. Transpilation is actually accomplished with the Babel compiler.

Setting up a Node Project

The first step in setting up our project is to create a directory and initialize a Node package in it. We can do this from the command line (assuming Node has been installed):

> mkdir myGame > cd myGame > npm init

The last command will launch a wizard that will prompt you with questions used to configure a package.json file in the directory. This file describes to the Node virtual machine how to run the project.

We'll also want to create two directories - one for our source code (src) and one for our distribution (dist):

> mkdir src > mkdir dist

The index.html File

We'll create an HTML file much like we have for earlier games, in the dist directory:

<!doctype html> <html> <head> <title>Webpack Game Framework</title> </head> <body> <script src="bundle.js"></script> </body> </html>

The biggest difference is the bundle.js reference - this will be the transpiled javascript file that webpack builds for us.

The index.js File

We also need to define an index.js file in our src directory. This is the entry point to our program - it will be the first code interpreted, and any import statements it contains will draw additional files into the list to be transpiled, as will the imports in those files, and so on. For now we can just log a message to the console:

console.log("Hello World!");

Installing and Configuring Webpack

Since we're already using Node, we can also use it to install Webpack:

> npm install webpack --save-dev > npm install webpack-cli --save-dev > npm install webpack-dev-server --save-dev

We use the --save-dev flag to save each of these libraries as development dependencies. If you check the package.json file after running these commands, you'll see each package listed there.

We also need to add a webpack.config.js file to the project, at the same level as our package.json file. It will look like this:

const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, devServer: { contentBase: path.resolve(__dirname, "./dist"), watchContentBase: true } };

Note we define our entry as the ./src/index.js and our output as ./dist/bundle.js. Thus, we compile index.js into bundle.js, which our index.html file uses.

We can trigger the transpilation directly at the command line using:

> webpack --config webpack.config.js

Once the command completes (providing we had no errors), the file bundle.js will be created in our dest directory.

The devServer section of our configuration file sets up a development server - a server that can run our webpage and automatically reload as we change our source code files. This can be launched with the command:

> ./node_modules/.bin/webpack-dev-server

The script will also open a web browser tab to localhost:8080, which is the default address the development server uses.

Amending package.json

We can add both of these to our package.json's script section:

{ "name": "webpack-game-framework", "version": "1.0.0", "description": "A basic game framework using webpack", "main": "index.js", "scripts": { "build": "webpack --config webpack.config.js", "test": "echo \"Error: no test specified\" && exit 1", "start": "./node_modules/.bin/webpack-dev-server" }, "author": "Nathan H. Bean", "license": "MIT", "devDependencies": { "webpack": "^4.19.1", "webpack-cli": "^3.1.0", "webpack-dev-server": "^3.1.8" } }

Now we can trigger the rebuilding of the bundle.js file with:

> npm run build

and launch the dev server with

> npm run start

or

> npm start