x
Tic-Tac-Toe with Javascript ES2015

Part 1: Set up the project with webpack

This is a part of the series: Tic-Tac-Toe with Javascript ES2015

In this tutorial you will learn how to set-up a new project with npm and webpack. webpack is a module bundler. It allows you to use Javascript’s modules (import/export statements) in addition to other useful features including compiling scss files, minifying code, etc..

View a demo or visit the project’s github page.
Installing webpack

To get started, first make sure you have npm installed on your device. Create a new folder anywhere on your device then open your terminal/cmd and navigate to your folder using:

 cd path/to/folder 

Inside your directory in the terminal run:

npm init

npm init command will ask you a bunch of questions like projects name, description, version, etc.. It will also create package.json file for you. This file stores information about your project in addition to other npm dependencies. You can read more about it here.

We now have npm set up in our folder, it’s time to install webpack. Inside our folder directory we will install webpack V2 by running:

npm install webpack@2.2.0-rc.0 --save-dev

This command will install webpack in our folder and –save-dev will add webpack to the list of npm dependencies inside package.json file.

Next, add build command to your scripts property in package.json file, this allows you to run specific commands when typing npm run build. Currently we will set build to run webpack command. Our package.json file should look something like this:

{
  "name": "tic-tac-toe",
  "version": "1.0.0",
  "description": "Tic Tac Toe implementation with Javascript ES2015",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "author": "themegasm",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^2.2.0-rc.0"
  }
}

 

Configuring webpack

webpack uses a file called webpack.config in the root folder for its configuration. Initially this file will contain the entry point and the output files as so:

var path = require('path');

module.exports = {
  entry: {
  	bundle: './src/index.js',
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  }
}

In the above code we specified an entry point called bundle, in webpack entry points uses relative paths, so ‘./src/index.js’ means we will create a folder in our root directory called src inside it a file called index.js. The output’s path however,  will receive an absolute path, thus, we will use a nodejs global variable __dirname to get the absolute path to our folder on the device.

Additionally, we will require a node module called path which we will use to create a path that is the result of concatenation between the folder path and a folder we will call dist that will contain our compiled js code. So path.join(__dirname, 'dist') will result in an absolute path to a dist folder in our root directory compatible with both window and unix machines.

Finally, filename: '[name].js' is the name of the file that will contain our compiled js code in the dist folder, and [name] is a placeholder for the entry point name which is bundle in our case.

In our root folder, create a file called index.html. In this file we will import our compiled JS file:

<!DOCTYPE html>
<html>
<head>
	<title>Tic Tac Toe with Javascript</title>
</head>
<body>
	<script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>

To test our configuration, add alert(true) statement in src/index.js, then in the terminal type npm run build. This should run webpack which will create dist/bundle.js. By opening index.html in our browser, we should find the alert message.

 

Using Babel with webpack

webpack has a feature called loaders, loaders allow you to pre-process files before they are built into your destination folder. Loaders can transform files from a different language like, CoffeeScript to JavaScript. In this tutorial we will use loaders to transform javascript ES2015 to ES5 so we can support wider range of browsers.

To do that, first we will need to install babel-core and babel-loader, the first module is just babel’s core library while the latter connects babel core with webpack:

npm install --save-dev babel-loader babel-core

Secondly, in our webpack.config.js file, we will define a new rule which informs webpack to apply babel-loader to all js files except node_modules folder.

var path = require('path');

module.exports = {
	entry: {
		bundle: './src/index.js',
	},
  	output: {
	    path: path.join(__dirname, 'dist'),
	    filename: '[name].js'
  	},
	module: {
		rules: [
			{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
		]
	}
}

Finally, we need to let babel know which preset we want to use. There are a lot of presets available for our case we will install preset-env which includes all the latest js features:

npm install babel-preset-env --save-dev

In order to enable the preset we have to create a file called .babelrc in our root folder and then add the following:

{
  "presets": ["env"]
}

 

Compiling SASS files

In order to compile css in webpack we can use css-loader and style-loader. css-loader will resolve all @import and url() statements in your css file while style-loader will add these styles inline in your <head> tag. To add multiple loaders in one rule you can assign an array and loaders will be applied from right to left:

npm install --save-dev css-loader style-loader
rules: [
    {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
    }
]

You can then add a sass compiler to this pipeline using a third-party library called sass-loader. sass-loader will compile scss files before the other loaders come in. This loader requires node-sass to be installed:

npm install sass-loader node-sass --save-dev 
rules: [
    {
        test: /\.scss$/,
        use: [ 'style-loader', 'css-loader', 'sass-loader' ]
    }
]

In this approach, you may have noticed that we add styles in the HTML directly in an in-line manner. This might not be the best approach especially for large CSS chunks. To tackle this, webpack has a feature called plugins. Plugins can be used to perform some operations outside the webpack entry and output pipeline. In our case, we need the CSS loaders output to compile in a seperate file. To do this, we can use a plugin called extract-text-webpack-plugin. This plugin will take the output from a certain rule and save it into a separate file. The final webpack.config.js file will look like this:

npm install --save-dev extract-text-webpack-plugin@2.0.0-rc.3
var path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSass = new ExtractTextPlugin('style.css');

module.exports = {
	entry: {
		bundle: './src/index.js',
	},
  	output: {
	    path: path.join(__dirname, 'dist'),
	    filename: '[name].js'
  	},
	module: {
		rules: [
			{ 
				test: /\.js$/, 
				exclude: /node_modules/, 
				loader: 'babel-loader' 
			},
			{
	            test: /\.scss$/,
	            loader: extractSass.extract({
	                loader: ["css-loader", "sass-loader"]
	            })
	        }
		]
	},
	plugins: [
        extractSass
    ]
};

First we import the plugin and define a new instance with the file name we want (style.css) in our case. Then we add the plugin instance to a plugins array property inside our exported object. Finally, we let the plugin know which loaders to use through extractSass.extract as you notice we no longer need the style-loader.

Finally, we will import the css file in the html file:

<!DOCTYPE html>
<html>
<head>
	<title>Tic Tac Toe with Javascript</title>
	<link rel="stylesheet" type="text/css" href="dist/style.css">
</head>
<body>
	<script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>

 

Using webpack development server

Running npm run build after every change is obviously not a good approach to compile our code. It takes some time and it compiles everything; however, we only need to compile the files we changed when we save them. To do this, webpack provides a Node.js Express server. This server will allow you to view changes in a split second in the browser. To install it, run:

npm install webpack-dev-server --save-dev

In package.json, add a new script “serve”: “webpack-dev-server” so we can run npm run serve to launch our server:

"scripts": {     
    "build": "webpack",     
    "serve": "webpack-dev-server" 
}

Also webpack requires a property called publicPath that allows the server to know where our static files are. So to add this, open webpack.config.js and update the output object as follows:

output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: 'dist/'
 },

Finally run npm run serve and you will be given a localhost url at a certain port that you can open in your browser and start developing.

All right, now that we have everything set to start coding, let’s start building our little game in the next part!

Ali Alaa

Front-end developer from Egypt. Telecommunications Engineering graduate. Been working in web development since graduation.