Hello guys! We are going to develop a [JavaScript](https://hackernoon.com/tagged/javascript) plugin/library in step by step manner. At the end of the article we will finish building a Js plugin which will generate a UI for playing Tic-Tac-Toe game. Also after this workshop is finished you will have efficient knowledge of the following: * Most used [ES6(es2015)](https://en.wikipedia.org/wiki/ECMAScript) core features * How to convert your [ES6 code](https://hackernoon.com/tagged/es6-code) into a library which can be consumed through script tag * A Build system width npm and webpack * Knowledge of building any Js Plugin using next generation JavaScript with [singleton design pattern](https://www.dofactory.com/javascript/design-patterns) > You can find the code base for this workshop at [https://github.com/debabrata100/tic-tac-toe.git](https://github.com/debabrata100/tic-tac-toe.git) Let’s have look on the final version:  Our library would be capable of generating a user interface for Tic-tac-toe game to play on a web server. We are going to use our library as below after building it: In the above `**index.html**` file, an external script `**_game-lib.js_**` (we are going to generate eventually) would expose a global object **Game**. Following code snippet in the `index.html` file would initialize the game using **Game** object: Game.init({ container:"game\_container", cellHeight: 100, cellWidth: 100 }); * **container**: This takes name of the css id selector of the html element which will contain the game UI provided by the game library. * **cellHeight**: This takes the height of each cell of game in pixels * **cellWidth**: This takes the width of each cell of game in pixels Steps to follow: * Project directory structure * Setup webpack * Develop Library ### Directory Structure: We will create our project with following directory structure \+ -- app | +-- index.js | -- build | +-- game-lib.js | +-- game-lib.min.js | +-- index.html The **app** folder contains source files/modules required to generate the library. The **build** folder contains **index.html** which we discussed above and two library files lib.js and lib.min.js which are generated after bundling up the source files. ### Setup Webpack Before ES6(2015), there were so many module systems came into place to achieve modularity in JavaScript. Let’s have look at the [evolution of JavaScript modularity](https://github.com/myshov/history-of-javascript/tree/master/4_evolution_of_js_modularity). In order to achieve modularity in native JavaScript, I believe ES6 Module system is most brilliant discovery so far. But most of its features are supported by [only a few modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Browser_compatibility). There comes the role of most popular tool called [**webpack**](https://webpack.js.org/)**,** a javascript module bundler which takes the modules with dependencies as input, resolve all dependencies and generates a static Javascript file, in this case game-lib.js/game-lib.min.js.  Webpack module bundler There is another pain point. Most of the ES6 features notably **Arrow function expression, spread operators, destructuring** are not supported by all browser. Therefore we need a transpiler to convert our ES6 code to a lower version which can be supported by all browsers. **Babel** does this job in a most effective way. It comes as a extension of webpack also called as [**loader**](https://webpack.js.org/concepts/loaders/#using-loaders)**.** Both babel and Webpack are together used by popular JavaScript frameworks such as [Angular](https://angular.io/), [React](https://reactjs.org/), [Vue js](https://vuejs.org/). ### Develop Library **Getting started** Webpack conventions: * Webpack works best with NPM * Uses a module system (ES6, [CommonJs](http://www.commonjs.org/), [AMD](http://requirejs.org/docs/whyamd.html#amd)) Before going forward, make sure you have installed node and npm in your system. In case you have not, check this [link](https://nodejs.org/en/). To check whether node and npm installed $ node -v $ npm -v Let’s start our work by creating the project directory as ‘tic-tac-toe’ and initialize npm $ mkdir tic-tac-toe $ cd tic-tac-toe $ npm init -y { "name": "learn", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \\"Error: no test specified\\" && exit 1" }, "keywords": \[\], "author": "", "license": "ISC" } $ **npm init -y** command creates a node project with a package.json file with default configurations. This file is a json object. We will install our dependencies which will be mapped to this json object. Install Webpack $ npm install webpack --save-dev Now open your project in a editor. It would be looking like this  project opened in atom editor Now within root folder create a folder called **build**. Within build create our first file called index.html. Quickly insert html tags. Provide a title Tic-Tac-Toe to the title tag. And in the head section include a script tag and mention a relative path to the src attribute as _game-lib.js._ Aslo provide a container(game\_container) for the game as shown below <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Tic Tac Toe</title> <script src="game-lib.js" type="text/javascript"></script> </head> <body> <div id="game\_container"> </div> </body> </html> Create another folder **app** in the root directory. Within app create a file called **index.js** and write our first JavaScript code as shown below let fun = ()=> { console.log("We are ready for Tic-Tac-Toe"); } fun(); Now before setting up [webpack](https://webpack.js.org/) let’s install a couple of things here $ npm install babel-core babel-loader babel-preset-es2015 webpack-dev-server babel-polyfill --save-dev Here **babel-loader** will actually transform ES6 code, **babel-preset-es2015** allows us to specify a preset that allows ES6 conversion, **webpack-dev-server** allows us to have automatic live code updates. To understand [**babel-polyfill**](https://babeljs.io/docs/usage/polyfill/), have a look about these great articles [what is polyfill](https://remysharp.com/2010/10/08/what-is-a-polyfill) and [shim](https://stackoverflow.com/questions/6599815/what-is-the-difference-between-a-shim-and-a-polyfill), you will have a concrete knowledge on these. Now to get webpack working we need to add a very specific file called **webpack.config.js** in the root directory. Add the following code into this file In the above config file there is an object called **config**. It holds 5 properties. Let’s discuss one by one **entry**: ‘./path/to/my/entry/file.js’. In our case entry file is index.js, as we have mentioned the relative path as ‘./app/index.js’ **output**: Here we need to mention the options related to how webpack emits results. We mentioned name of the final compiled file (game library) as **_filename_** property and location of the file in **_path_** property. The value should be a **absolute path**. Here _\_\_dirname_ is a global variable in the current module scope which provides absolute path of the parent directory of current module. **module**: Here we need to mention the configuration regarding modules. We have given configuation for loader. We have used babel-loader to transpile our code. **_test_** property takes a regular expression which tells which kind of file will run through this loader and **_exclude_** is which files the modules should exclude. We have added node\_modules to exclude. **presets**: This lets us use es2015(ES6). We can mention [react](https://reactjs.org/) if we want to parse jsx code. **devserver**: This is used create a webpack development server which allows us to run a web server at [http://localhost:3000](http://localhost:3000). **inline** property as true allows us to run automatic live code updating. Now we are ready with webpack. Run the following command and see the magic $ webpack You will be able to see a new file called **game-lib.js** under build folder which is a compiled version of our code written in index.js file under app folder The above code is not a minified version, We will create a minified version at the end of this workshop by introducing a webpack-production-config.js file. > If you want to learn more about webpack, [go here](https://webpack.js.org/configuration/) and learn about latest webpack-4.0 features and configuration Now let’s run the following code $ webpack-dev-server This will generate a dev server. Navigate to [http://localhost:3000/](http://localhost:3000/) and open up the browser console. You will be able to see the message ‘_We are ready for Tic-Tac-Toe_’ in the browser console. > If you are following my git repository the then run the following codes to see the version the code so far we have reached > $ git clone [https://github.com/debabrata100/tic-tac-toe.git](https://github.com/debabrata100/tic-tac-toe.git) > $ cd tic-tac-toe > $ git checkout b350603 #### Adding a library template Now open you ‘index.js’ file in editor. We are supposed to create a **Game** object and add a **init** method to it (function(window){ let \_init = ()=>{}; window.Game = { init:\_init } })(window) In the above code we used an IIFE(Immediately-Invoked Function Expression). This pattern is often used when trying to avoid polluting the global namespace, because all the variables used inside the IIFE (like in any other normal function) are not visible outside its scope. Therefore we are storing _Game object_ to **window** variable because window variable is globally available. If you are confused with **let**, visit this [link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) to get an inside about ES6 magic keyword _let_ against _var_ So we added a Window object and init method to init. But we are supposed to receive some parameters at the game initilization. Let’s receive container param in init method in the ES6 way (function(window){ const \_init = ({container = ''})=>{ let gameBody = document.getElementById(container); if(gameBody === undefined) gameBody = document.getElementsByTagName("body")\[0\]; console.log("Game Initialised"); } window.Game = { init:\_init } })(window) You will be wondering about receiving the param container=’ ’ instead of receiving like container: ‘ ’ inside an object. So this is the Es6 syntax aka [**destructuring**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) which accept the the param as a variable. Here we have assigned a default value as empty string. We are getting a DOM reference of this element as _gameBody_ and we are also checking that in case this is undefined, we take document body as a reference where we can push the game UI. Update your index.js with the above code. #### Initializing Game Open index.html and initialize the game in the body section <script type="text/javascript"> Game.init({ container:"game\_container" }); </script> Then run $ webpack-dev-server Navigate to [http://localhost:3000](http://localhost:3000), you will be seeing a message ‘Game Initialised’ in the console > At this point your code should be matching with the following commit of my repository $ git checkout 74c3dac #### Prepare a playing board with html table We will create a html table element with document.createElement() method and adding tbody, rows and columns to it using plain javascript const \_init = ({container = '',cellHeight = 50, cellWidth = 50})=>{ let gameBody = document.getElementById(container); if(gameBody === undefined) // check whether element exist gameBody = document.getElementsByTagName("body")\[0\]; const tbl = document.createElement("table"); const tblBody = document.createElement("tbody"); for (let i = 0; i < 3; i++) { var row = document.createElement("tr"); for (let j = 0; j < 3; j++) { let cell = document.createElement("td"); cell.setAttribute("width",cellHeight+"px"); cell.setAttribute("height",cellWidth+"px"); //setting styles for table cells cell.style.textAlign = "center"; cell.style.cursor = "pointer"; cell.style.fontSize = (cellHeight\*0.4) + 'px'; row.appendChild(cell); // insert each cell to row } tblBody.appendChild(row); } tbl.appendChild(tblBody); gameBody.appendChild(tbl); // insert table to dom tbl.setAttribute("border", "1"); // setting styles for table tbl.style.borderCollapse = 'collapse'; tbl.style.border = '2px solid #000'; tbl.style.height = "auto"; tbl.style.width = "auto"; tbl.style.margin = "0 auto"; } In the above code we have created 9 columns and applied some styles to it. We have added height and width of each cell to cellHeight and cellWidth variable which are other two parameters we receive during game initialization. We have set font size as 40% of cellHeight. Open index.html file and update the initialization Game.init({ container:"game\_container", cellHeight: 100, cellWidth: 100 }); Run $ \`webpack-dev-server\`now and on the browser window you will notice a table created  table for tic-tac-toe game created by the game library > At this point your code should be matching with the following commit of my repository $ git checkout 0fdebc2 #### Create webpack build and dev server with npm NPM provide a excellent tool to execute script. We can run both $ webpack and $ webpack-dev-server command replacing with a single command Open package.json and under script property write the following commands "scripts": { "start": "webpack && webpack-dev-server" } Now run $ npm start You will notice our build has been created and a web server started at [http://localhost:3000](http://localhost:3000) To learn more about npm scripts visit [https://docs.npmjs.com/misc/scripts](https://docs.npmjs.com/misc/scripts) > At this point your code should be matching with the following commit of my repository $ git checkout c7d5ca7 #### Updating board on click event let’s initialize three variables // Put this code above outer for loop let gameState = 0; let cellIndex = 0; let inputArray = \[\]; _gameState_ will be incremented on every click on a cell, which can give us the info about which player (‘X’ or ‘0’) has clicked. // Put this code inside inner 'for' loop cell.setAttribute("index",(cellIndex++)); cell.addEventListener("click",()=>{ let inputState = gameState % 2? 0: 1; let cellText = inputState == 1? 'X':'0'; cell.innerHTML = cellText; inputArray\[index\] = inputState; gameState++; }) In each cell we stored index of each cell as attribute which is equal to gameState of the current cell. **inputArray** is used to store state of each cell when clicked. Both **cellIndex** and **inputArray** will be used to determine the winner. Run $ npm start, at this point you should be able to enter 0 or X into the board  Next we will determine the winner. > At this point your code should be matching with the following commit of my repository $ git checkout 5c944a0 #### Declaring Winner Create a new file called winner.js under app folder. This will be a new ES6 module. We calculate the winner here in this module. We will export this module to use it inside index.js, where we can create instance of this module and use it to determine the winner. We will make use of another excellent feature of ES6 i.e class. > In order to present the concept of classes in ES6, I have used class here, Otherwise to maintain Singleton design pattern we should avoid classes. Here is a nice [atricle](http://www.dofactory.com/javascript/singleton-design-pattern). Let’s create Winner class class Winner { constructor(){ this.\_name = null; this.\_score = 0; } } export default Winner In the above code we have create a class called Winner and added two properties \_name and \_score which will be eventually storing name(0 or X) and score of the winner There are two types of export in ES6 * Default Export * Named Export > If you want to learn more about ES6 import, export [here](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) is a [great article](https://hackernoon.com/import-export-default-require-commandjs-javascript-nodejs-es6-vs-cheatsheet-different-tutorial-example-5a321738b50f) Add getters to access name and score get name(){ return this.\_name; } get score(){ return this.\_score; } Now go to index.js file and write code for declaring winner Import the module **winner** at top as follows import Winner from './winner'; Now Create a instance of winner module (function(window){ let W = new Winner(); \--- \--- \--- cell.addEventListener("click",()=>{ let index = cell.getAttribute("index"); if(inputArray\[index\] !== undefined || W.name) return; let inputState = gameState % 2? 0: 1; let cellText = inputState == 1? 'X':'0'; cell.innerHTML = cellText; inputArray\[index\] = inputState; gameState++; let winner = W.findWinner(inputArray); if(winner.state == 0 || winner.state == 1){ console.log("Winner",W.name); } }) We are determining the winner in this statement let winner = W.findWinner(inputArray); This means, we need to define a _findWinner_ method inside winner class which takes inputArray as param findWinner(inputLines){ const winningLines = \[ \[0, 1, 2\], \[3, 4, 5\], \[6, 7, 8\], \[0, 3, 6\], \[1, 4, 7\], \[2, 5, 8\], \[0, 4, 8\], \[2, 4, 6\], \]; for (let i = 0; i < winningLines.length; i++) { const \[a, b, c\] = winningLines\[i\]; // console.log(inputLines); if (inputLines\[a\] !== undefined && inputLines\[a\] === inputLines\[b\] && inputLines\[a\] === inputLines\[c\]) { this.\_name = inputLines\[a\] == 1 ? 'X': '0'; this.calculateScore(inputLines,inputLines\[a\]); return {state:inputLines\[a\],lines:\[a, b, c\]}; } } return {state:null,lines:\[\]}; } calculateScore(inputLines,player){ for(let i=0;i<inputLines.length;i++){ if(inputLines\[i\] == player){ this.\_score++; } } } In the above code winningLines stores all the 8 combinations of winning cells. We have traversed the winningLine array. For every iteration we are storing each three winning lines to a,b,c variables by applying destructuring const \[a, b, c\] = winningLines\[i\]; We have defined calculateScore() method which takes two params as ‘inputLines’ and ‘player’ and update the score of the player in the following line this.\_score++; findWinner() method will update the name of the winner in the following line this.\_name = inputLines\[a\] == 1 ? 'X': '0'; and returns both state of the winning lines (0 or 1) and winning lines as an object as shown below return {state:inputLines\[a\],lines:\[a, b, c\]}; Now run $ npm start and play the game. You can see the winner printed in the console > Ideally you should not put any code in the entry module **index.html** which involve game play. This module should only contain the code meant for exposing the Game Api(Game.init). Try separating this code to a separate module called **GameBoard** which will be eventually be imported in the winner module used for determining the winner. In that case no need of passing **inputArray** param to the **findWinner** method because this can be available through **GameBoard** module. I leave this work for you. We have only one task left now that is Update a score board because we are supposed to see the score on the webpage itself instead of browser console #### Update Score Board Create a new file called score-board.js and Write a **ScoreBoard** module inside as shown below const ScoreBoard = { drawScore: ()=> { }, declareWinner: ()=> { } }; export default ScoreBoard; This will have two method drawScore and declareWinner. One should tell which cells are the winning lines and the later should print a score to the webpage Check the following code for method definition drawScore: (table, inputArray, winner)=>{ table.style.opacity = "0.5"; let cells = table.getElementsByTagName("td"); let cellIndex; for(let c = 0;c < cells.length;c++){ cellIndex = parseInt(cells\[c\].getAttribute("index")); if(inputArray\[cellIndex\] == winner.state && winner.lines.indexOf(cellIndex)!=-1 ){ cells\[c\].style.backgroundColor = "#eee"; } } }, declareWinner: (W)=>{ let scoreboard = document.createElement("div"); scoreboard.style.margin = "auto"; scoreboard.style.height = '100px'; scoreboard.style.lineHeight = '110px'; scoreboard.style.border = 'dotted'; scoreboard.style.marginTop = '10px'; scoreboard.style.width = (window.innerWidth-window.innerWidth\*0.02)+'px'; scoreboard.style.backgroundColor = "transparent"; scoreboard.style.textAlign = "center"; scoreboard.innerHTML = "Winner: "+W.name +", Score: "+W.score; document.body.appendChild(scoreboard); } The code above is self explanatory. Import this module in index.js module and update the score board as shown below let winner = W.findWinner(inputArray); if(winner.state == 0 || winner.state == 1){ ScoreBoard.declareWinner(W); ScoreBoard.drawScore(tbl, inputArray, winner); } We have successfully created a TIC-TAC-TOE game library at this point. One task is left. We need to create a minified version of our library. Let’s create it. #### Create a minified library Open your terminal and install these two dependencies $ npm install yargs strip-loader --save-dev **Yargs** helps you build interactive command line tools, by parsing arguments and generating an elegant user interface. **strip-loader** is a webpack loader which helps you strip custom functions or debug statements Now create a new file within root folder called webpack-production.config.js and add the following code var WebpackStripLoader = require('strip-loader'); var devConfig = require('./webpack.config.js'); var stripLoader = { test: \[/\\.js$/, /\\.es6$/\], exclude: /node\_modules/, loader: WebpackStripLoader.loader('console.log') } devConfig.module.loaders.push(stripLoader); module.exports = devConfig; In the above code we have written how to strip down console.log statements from your library by using webpack strip loader. devConfig = require('./webpack.config.js'); The above statement includes webpack.config inside production-config, this means in production mode, we will be using webpack-production.config Open your webpack.config.js file add the following In the above code the uglify plugin hepls to minify the library and yargs helps to determine whether current excution in production mode, if so then uglify takes care of minifying during the webpack compilation and bundling. Let’s update the package.json to accept production config as shown below "scripts": { "build": "webpack --config webpack-production.config.js --env dev && webpack --config webpack-production.config.js --env build", "serve": "webpack --env dev && webpack --env build", "start": "webpack-dev-server" }, We have added two more script commands * **build**: To run in production mode * **serve**: To run in development mode We can run the new npm commands in the following way $ npm run build $ npm run serve I hope now, you will be definitely ready to write a standard **javaScript** plugin. You can clone my repository to see the final version. $ git clone [https://github.com/debabrata100/tic-tac-toe.git](https://github.com/debabrata100/tic-tac-toe.git) Thank you :)