Category Archives: JavaScript

Websockets with JavaScript

Let’s create a JavaScript websocket server.

To start with carry out the following steps…

  • Create a folder, mine’s wsserver and cd to it
  • Run yarn init -y
  • Run tsc –init
  • Run yarn add ws @types/ws
  • Add a file (mine’s server.ts) for our server code
  • Add another file this time for a sample client (mine’s client.ts)
    • Now we will add the scripts, so add the following to package.json

      "scripts": {
        "server": "node server.js",
        "client": "node client.js"
        "build": "tsc"
      }
      

      Let’s add some code, in the server.js put the following

      import WebSocket from "ws";
      
      const wss = new WebSocket.Server({ port: 4000 });
      
      wss.on("connection", ws => {
        ws.on('message', message => {
          console.log('received: %s', message);
        });
      
        ws.on("close", () => {
          console.log("Close connection");
        });
      
        ws.send("Server says Hi");
      });
      

      In the above code we create a new websocket server on port 4000 then we handle any connection’s (once a connection is made the server sends back the message “Server says Hi”. The ws.on “message” will output any messages sent from the client. It should be fairly obvious that the “close” is called when a connection is closed.

      Let’s now put the following in the client.ts

      import WebSocket from "ws";
      
      const ws = new WebSocket("ws://localhost:4000");
      
      ws.onopen = () => {
        ws.send("Client says Hi");
      };
      
      ws.onerror = error => {
        console.log(error);
      }
      
      ws.onmessage = msg => {    
        console.log(`Client onmessage: ${msg.data}`);
      }
      
      ws.onclose = () => {
        console.log("Close");
      };
      

      In the above we open the connection to the web socket server, when the connection is open (onopen) we send a message “Client says Hi” to the server, obviously any errors are sent to the onerror function and any message from the server are routed to the onmessage function, finally onclose is called if the server closes the connection.

      Now run the script command yarn build and then in one terminal run yarn server and in another terminal run yarn client.

      We can also send specific commands to the server, for example in the client add the following to the onopen function

      ws.send("getData");
      

      Within the server add the following

      ws.on("getData", msg => {
        console.log("getData called")
      });
      

      So now when the server receives a getData messages it’s routed to this server function.

      If we have multiple client’s connecting to a server, we can send messages to each client using code, like the following

      wss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
          client.send("Broadcasting a  message);
        }
      });
      

      We can also extend the server “connection” function like this

      wss.on("connection", (ws, request) => {
        console.log(request);
      }
      

      The request parameter allows us to check the request.url if we want to change take different actions depending upon the query part of the websocket URL.

      It’s often useful to implement ping/pong capabilities which would allow us to check if the client still exists, here’s rather simplistic example of this type of code.

      wss.on("connection", (ws, request) => {
        ws.isAlive = true;
      
        ws.on("pong", () => {
          console.log("Pong called");
          ws.isAlive = true;
        });
      
        setInterval(function ping() {
          wss.clients.forEach(function each(ws: any) {
            if (ws.isAlive === false)  {
              console.log("Terminated client")
              return ws.terminate();
            }
              
            ws.isAlive = false;
            console.log("Ping client")
            ws.ping();
          });
        }, 10000);
      });
      

JavaScript tagged templates

If you’ve seen code such as the one below (taken from https://www.styled-components.com/docs/basics)

styled.section`
  padding: 4em;
  background: papayawhip;
`

You might be interested in the styled.section code. This is a function and uses template literals as input via template literal syntax. In this usage its known as a tagged template or tagged template literals.

Let’s create our own function to show how this works.

function tt(literals: any, …substitutions: any) {
console.log(literals);
console.log(substitutions);
}

Note: I’m using TypeScript, hence the use of the any keyword, but just remove this for JavaScript code.

If we now run the following code

const name1 = "Scooby";
const name2 = "Doo";

tt`Hello ${name1} World ${name2}`

The following will be logged to the console

[ 'Hello ', ' World ', '' ]
[ 'Scooby', 'Doo' ]

The first values are an array of the literals passed to our function, the second are the substitutions.

Literals will always be an array of substitutions.length + 1 in length. Hence in the example above the literals contains an empty string item at the end to ensure this is the case.

Note: The last item in the literals array is an empty string but ofcourse if we had a string after the ${name2} then this would be the last item, hence to combine these two arrays into a resultant string would require us to ensure we merge all items.

We can therefore combine our two arrays to form a single result using a simple loop, like this


function tt(literals: any, ...substitutions: any) {
  let s = "";

  for (let i = 0; i < substitutions.length; i++) {
    s += literals[i] + substitutions[i];
  }

  return s + literals[literals.length - 1];
}

In the above we’re simply returning a string representing the merge of the two arrays. Remember literals.length will be substitutions.length + 1, hence we simply append that after looping through the smaller of the arrays.

Ofcourse this it not really that useful, if all we wanted to do was return a string we could just create a template literal. Let’s look at a couple of ways of enhancing the functionality.

The first obvious requirement is that we should be able to pass functions into the templates. For example if we have something like this

const t = tt`
 firstName: ${name1};
 lastName: ${name2};
 preferred: ${choice => (choice ? name1 : name2)};
 `;

The choice value needs to be supplied by the calling code and in this example code there’s no easy was to pass this data into t. So first off we need to wrap the tt function within another function and return it, like this

 
function tt(literals: any, ...substitutions: any) {
  return function(options: any) {
    let s = "";

    for (let i = 0; i < substitutions.length; i++) {
      s += literals[i];
      s += typeof substitutions[i] === "function"
        ? substitutions[i](options)
        : substitutions[i];
    }
    return s + literals[literals.length - 1];
  };
}

In the above we’ve also added changes to the original tt function to detect functions within the substitutions. If a function is found whilst looping then it’s invoked by passing in the supplied options.

This implementation then returns a function which, when invoked by passing in some value (in this case named options), will loop through the literals and substitutions and invoking any functions by forwarding the supplied options.

Hence we can call the new tt method like this, for example

t({choice: true});

This would return a string and would return

firstName: Scooby;
lastName: Doo;
preferred: Scooby;

So now for the next enhancement, let’s instead of returning a string, return an object – all we need to do is split on semi-colons to get key/value items where the key will become the object’s property and the value obviously the value stored within the property.

We’ll make a slight change to the code above to this

function tt(literals: any, ...substitutions: any) {
  return function(options: any) {
    let s = "";

    for (let i = 0; i < substitutions.length; i++) {
      s += literals[i];
      s += typeof substitutions[i] === "function"
        ? substitutions[i](options)
        : substitutions[i];
    }

    return toObject(s + literals[literals.length - 1]);
  };
}

The toObject function has been introduced and it’s purpose is to…

  • Take a string which is semi-colon deliminated for each key/value pair
  • Extract each key/value pair which should be deliminated with colons
  • For each entry we will create a property with the name taken from left of the colon on an object and the value right of the colon will be assigned to the property as a value

Here’s the code for toObject

const toObject = (value: any): any =>
  value
    .split(";")
    .map(entry => {
        const e = entry.split(":");
        if(e.length == 2) {
            const key = e[0].trim();
            const value = e[1].trim();
            return [key, value];
        }
        return undefined;
    })
    .filter(entry => entry != undefined)
    .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1]}), {});

This is not a complete solution as we’re not ensuring validity of the key as a property name. For example you’ll have noticed in styled.component or even React’s styles, that hyphen keys, i.e. background-color or similar would be converted or expected to be backgroundColor. So a simply change would be to convert line 7 to this following

const key = ensureValid(e[0].trim());

and now we introduce a new function to handle all our checks, for now we’ll just ensure the hyphen’s or dot’s are removed and replaced by camelCase

const ensureValid = (key: string): string => 
 key.replace(/[-.]+/g, c => c.length > 0 ? c.substr(1).toUpperCase() : '');

Obviously this function is quite limited, but you get the idea. It can then be used in the toObject function, i.e.

// change
const key = e[0].trim();
// to
const key = ensureValid(e[0].trim());

Taking things a little further

The code below is based upon what was discussed in this post, but extended a little, to start with here’s a more complete implementation of the above code

const ensureValid = (key: string): string => 
    key.replace( /[-.]+([a-z]|[0-9])|[-.]$/ig, (_match, character, pos) => {
        if(pos == 0) {
            return character.toLowerCase();
        }
        else if(character == null) {
            return '';
        }

        return character.toUpperCase();
    });

const toObject = (value: any): any =>
  value
    .split(";")
    .map(entry => {
        const e = entry.split(":");
        if(e.length == 2) {
            const key = ensureValid(e[0].trim());
            const value = e[1].trim();
            return [key, value];
        }
        return undefined;
    })
    .filter(entry => entry != undefined)
    .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1]}), {});

function tt3(literals: any, ...substitutions: any) {
    return function(options: any) {
        let s = "";

        for (let i = 0; i < substitutions.length; i++) {
            s += literals[i];
            s += typeof substitutions[i] === "function"
                ? substitutions[i](options)
                : substitutions[i];
        }

        return toObject(s + literals[literals.length - 1]);
    };
}

const name1 = "Scooby";
const name2 = "Doo";

const t = tt3`
 -First-6name-: ${name1};
 last-Name: ${name2};
 preferred: ${options => (options.choice ? name1 : name2)};
 `;

console.log(t({choice: true}));

Now let’s have a bit of fun and refactor things to allow us to extract our object from alternate data representations. We’ll create an ini style way to define our objects

const camelCase = (key: string): string => 
    key.replace( /[-.]+([a-z]|[0-9])|[-.]$/ig, (_match, character, pos) => {
        if(pos == 0) {
            return character.toLowerCase();
        }
        else if(character == null) {
            return '';
        }

        return character.toUpperCase();
    });

type splitterFunc = (value: any) => [{key: any; value: any}|undefined];

const standardSplitter = (value: any):  [{key: any; value: any}|undefined] =>
    value
        .split(";")
        .map(entry => {
            const e = entry.split(":");
            if(e.length == 2) {
                const key = camelCase(e[0].trim());
                const value = e[1].trim();
                return [key, value];
            }
            return undefined;
        });

const iniSplitter = (value: any):  [{key: any; value: any}|undefined] =>
        value
            .split("\n")
            .map(entry => {
                const e = entry.split("=");
                if(e.length == 2) {
                    const key = camelCase(e[0].trim());
                    const value = e[1].trim();
                    return [key, value];
                }
                return undefined;
            });
    

const toObject = (value: any, splitter: splitterFunc = standardSplitter): any =>
    splitter(value)
      .filter(entry => entry != undefined)    
      .reduce((obj, entry) => ({ ...obj, [entry![0]]: entry![1]}), {});


function tt3(literals: any, ...substitutions: any) {
    return function(options: any, splitter: splitterFunc = standardSplitter) {
        let s = "";

        for (let i = 0; i < substitutions.length; i++) {
            s += literals[i];
            s += typeof substitutions[i] === "function"
                ? substitutions[i](options)
                : substitutions[i];
        }

        return toObject(s + literals[literals.length - 1], splitter);
    };
}

const name1 = "Scooby";
const name2 = "Doo";
    
const t = tt3`
 -First-6name-: ${name1};
 last-Name: ${name2};
 preferred: ${options => (options.choice ? name1 : name2)};
 `;

 const t1 = tt3`
 -First-6name- = ${name1}
 last-Name = ${name2}
 preferred = ${options => (options.choice ? name1 : name2)}
 `;

console.log(t1({choice: true}, iniSplitter));

Watching with eslint

If you have your dev environment set up like me, you’re used to having Jest in a terminal window of it’s own continuously running and watching for changes to test files, but what about eslint, there doesn’t appear to be the same option out of the box.

Whilst there are npm packages for adding this capability the easiest way is to simply use watch, although you’ll need to install it using npm install watch -g if not already installed. Our CLI command would then look something like this

yarn watch 'eslint --ext *.ts,*.tsx,*.js,*.jsx src' src

if we ignore the ‘eslint…’ section, basically we’re just telling watch to watch the folder src (the src text at the end of the command). Ofcourse if you’re working on a specific folder, for example src/components/mediaPlayer, you’ll want to watch that specific folder. Just don’t forget we’re running two separate commands, so it’s no good watching one folder but having lint run against a different folder.

Extension methods in TypeScript

Extension methods in C# are a great way to modularise functionality within a class in such a way (for example) to have a basic object with minimal methods and then extend this with further functionality that can be reference only if required.

Hence you might only have a need for the bare bones class in some cases and therefore only need to include that in your code base, alternatively you might also depend upon some advanced functionality that can be added when required. Another use case is adding functionality to third party libraries to extend their functionality.

Ofcourse we might simple extend/inherit from the class to add our new functionality but this ultimately mean’s we’re using a different type. With extension methods in C# we extend a String (for example) with extra functionality as opposed to created a subclass named something else, like ExtendedString.

So can we implement something similar to C#’s extension methods in TypeScript (and therefore JavaScript)? Yes we can, let’s look at a simple example, an Option class for handling defined/undefined values in a functional way. Here’s the Option.ts file

export class Option {
    value: any;

    constructor(value: any) {
        this.value = value;
    }

    isSome(): boolean {
        return this.value != null;  
    } 

    isNone(): boolean {
        return !this.isSome();
    }
}

Hence this is a bare bones implementation which we might extend further with further functionality. Let’s create a file for our extension methods, mine’s named OptionExtensions.ts, which might look something like this

import { Option } from './Option';

declare module './Option' {
    interface Option {
        ifElse(elseValue: any): any;
    }
}

Option.prototype.ifElse = function(elseValue: any): any {
    return this.isSome() ? this.value : elseValue;
}

In the above code we declare a module with the same name as the one which wish to extend and then declare an interface with our new methods. The interface in essences merges with the type to allow us to view our new methods as if they’re on the original Option type.

Finally we can start implementing our new functionality via the JavaScript prototype functionality.

In this example you can see we also have access to the this reference to allow our new functionality to hook into the Option fields etc.

Now let’s look at this in usage

import { Option } from "./Option"
import "./OptionExtensions";

const o = new Option(undefined);
console.log(o.ifElse(999));

That’s it, we pull in the extension methods via the import “./OptionExtensions”; when we want the extended functionality and we can call our extension methods as if they were written into the Option class itself.

Property based testing in JavaScript with fast-check

Property testing is a way to test functionality by automatically generating many different inputs.

We’re going to use the fast-check library

yarn add fast-check -D

Let’s create a rather contrived example function to test

export const divide = (a: number, b: number): number => {
  if(b === 0) {
    throw new Error("Denominator cannot be 0");
  }
  return a / b;
}

As you can see, this function simply divides a by b but will fails in the denominator is 0. This was done on purpose to ensure that there is a failing test available for a specific input value (I did say it was contrived).

Now to test this we might implement the following test

import * as fc from 'fast-check';

test("Divide property test", () => {
   fc.assert(
      fc.property(fc.nat(), fc.nat(), (a, b) => {
         return divide(a, b) === a / b; 
      })
  );
});

In this instance we create the assert which wraps the property generation code, i.e. the call to property, which itself generates two natural numbers properties as input to the lambda/fat arrow function.

We then call the code that we wish to test, passing in the generated values and then returning whether the expectation was true or false.

We can use Jest or the likes in place of the return divide(a, b) === a / b, i.e.
replacing it with if we prefer and just use fast-check to generate the properties

expect(divide(a, b)).toEqual(a / b);

Now the only problem with the property based testing like this is that it will randomly generate values as opposed to inspecting the flow of your code to generate values (like tools such as Pex for .NET). Hence these values may not always include the edge cases that we might not have coded for.

For example, executing this test in Jest I find that sometimes it will pass a 0 as a denominator and other times it will not, therefore we do not always get a clear idea of all possible inputs, but it’s a great starting point for proving your functions.

In the test we generated natural numbers, we can also generate restricted ranges of values, along with integers, floating point, doubles, strings and more, see Arbitraries.

Loading JavaScript objects from a string

As mentioned in a previous post – I’ve been working on dynamically loading TypeScript/JavaScript as required (i.e. like a runtime plugin system) and whilst investigating the process have come across several libraries that I felt I’d document in case I need them in the future. First up is require-from-string.

I’ll assume for this and any follow up posts, that you’ve created a basic set-up, i.e.

  • yarn init –typescript
  • tsc –init

Although I’ve added TypeScript in the above, for simplicity we’re going to start out just using JavaScript, but we’ve covered all bases with TypeScript’s inclusion.

Next create an index.js that looks like this

import requireFromString from 'require-from-string';

const classA = requireFromString('class A { output() { console.log("Remote class called") } } module.exports = A;');
new classA().output();

TypeScript constructor parameter properties

TypeScript offers a short-cut to creating properties/fields from the parameters declared on the constructor.

For example, if we declare our class and constructor like this

class Person {
    constructor(name: string, age: number) {
    }
}

let p = new Person("Scooby", 10);
p.name = "Doo";

The TypeScript transpiler will display the error “Property ‘name’ does not exist on type ‘Person'” and obviously the parameters name and age will not exist within the Person class as they’ve not been declared.

However if we prefix the parameters with either public, private, protected or readonly then TypeScript generates properties on the Person object automatically for us.

protected parameter properties

As you’d probably expect, with the accessor of protected properties are generated which are visible to the Person object and any subclass of the Person.

For example

class Person {
    constructor(protected name: string, protected age: number) {
    }
}

When we run this through the transpiler we get the following

var Person = /** @class */ (function () {
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    return Person;
}());

If we attempt to access the properties name and age from outside the class (using TypeScript) then we’ll get the error “Property ‘name’ is protected and only accessible within class ‘Person’ and its subclasses.”.

private parameter properties

If we now change the accessors to private, for example

class Person {
    constructor(private name: string, private age: number) {
    }
}

The transpiler will, again, create the same output as the previous JavaScript code, but the generated properties, from the TypeScript point of view, are only accessible from the Person class. Trying to access them from outside of the Person class will result in the following error, “Property ‘name’ is private and only accessible within class ‘Person’..

public parameter properties

Changing the accessors to public will, as you probably expected, create public properties/fields which are accessible outside of the Person class, here’s the altered source code.

class Person {
    constructor(public name: string, public age: number) {
    }
}

Ofcourse, the JavaScript code is unchanged.

readonly parameter properties

Finally, if we now change the accessors to readonly, for example

class Person {
    constructor(readonly name: string, readonly age: number) {
    }
}

The transpiler will generate, what appears to be, getters only. Hence trying to interact with these properties outside of the class will result in the following error “Cannot assign to ‘name’ because it is a read-only property.”

Whilst JavaScript can support the concept of readonly properties, the transpiler does not go this route (shown below)

Readonly properties in JavaScript

If we take the code generated by the transpiler, we could add the following

Object.defineProperty(Person.prototype, "name", {
    value: "name",
    writable: false
});

and when run (assuming we try to assign a value to name), we’ll get the following error “Cannot assign to read only property ‘name’ of object ‘#‘”.

Zero to web with TypeScript, webpack and more

This post is a little long but the aim is to cover creating a simple TypeScript/HTML website without using any frameworks but using a whole bunch of standard tools.

The website will be pathetically unimpressive because I want to solely concentrate on just getting the various technologies working together.

We’ll be using Visual Code as the editor. We’ll be using TypeScript, ESLint and Jest (as per previous posts on this topics) and we’ll be using webpack to both create a distribution of our code and to host our code.

Creating the basics

  • Create the project’s folder, mine’s zerotoweb
  • Open Visual code against the new folder
  • Use the key combination (on mine it’s CTRL + ‘ on Windows) to open the terminal within Visual Code or if you prefer open a command prompt and navigate to the the folder you created
  • run yarn init –yes within the terminal. This will create the package.json file
  • run tsc –init within the terminal to create the tsconfig.json file
  • Change tsconfig.json to the following contents
    {
      "compilerOptions": {
        "target": "es6",
        "outDir": "./public",
        "rootDir": "./src",
        "allowJs": true,
        "skipLibCheck": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "noImplicitAny": false
      },
      "include": [
        "src"
      ],
      "exclude": [
        "node_modules"
      ]
    }
    
  • Next create the src folder off of the root
  • Add a file named index.ts to src folder and add the following code
    class App {
        getSalutation() {
            return "Hello World"
        } 
    }
    
    let app = new App();
    console.log(app.getSalutation());
    
  • We’ll want to run from node, which currently doesn’t support es6 so we’ll need to add babel, so run
    • yarn add babel-cli -D
    • yarn add babel-preset-es2015 -D
    • yarn add babel-preset-env -D
  • Let’s now add a couple of scripts to package.json
    "scripts": 
    {
       "build": "tsc --watch", 
       "start": "babel-node --presets es2015 ./public/index.js"
    }
    
  • Now we need to add a configuration file for babel, so add a .babelrc file to the root folder and put the following within it
    {
       "presets": ["env"]
    }
    
  • Next we want to add ESLint (this section is a duplication of the previous post but is here for completeness), so run the following
    • yarn add eslint -D
    • yarn add @typescript-eslint/parser -D
    • yarn add @typescript-eslint/eslint-plugin -D
    • Add a .eslintrc.js file to the root folder, place the following into the file
      module.exports = {
          "parser": '@typescript-eslint/parser',
          "plugins": ['@typescript-eslint'],
          "extends": ['plugin:@typescript-eslint/recommended'],
          "rules": {
              "@typescript-eslint/no-parameter-properties": "off",
              "@typescript-eslint/no-explicit-any": "off"
          }
      };
      
    • Now add the following “lint”: “eslint ./src/*.ts” to the scripts section of the package.json
  • Now run yarn build
  • Lets see some output, so run yarn start. If all went well you should see Hello World output.

Adding tests

I’ve covered installing Jest for testing React applications previously but let’s see the steps to take to get everything installed for our non-React world

  • yarn add jest -D
  • yarn add @types/jest -D
  • yarn add ts-jest -D
  • yarn add @types/node -D (not sure about this one)
  • Add __tests__ under the src folder
  • Add TypeScript tests to the __tests__ folder, convention suggests {name}.test.ts for the filenames
  • Add “test”: “jest” to the scripts section of packages.json if you want to run the tests yourself (i.e. no plugin or watch)
  • Finally in the root folder add the file jest.config.js with the following code
    module.exports = {
        roots: ['./src'],
        transform: {
          '^.+\\.tsx?$': 'ts-jest',
        },
        testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
        moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
      }
    

In Visual Code the plugin for Jest (Use Facebok’s Jest With Pleasure) from Orta is very useful to have.

Test coverage

Jest includes an option for running code coverage, simply change your packages.json script to

  • “test”: “jest –coverage”

Adding webpack

Next up we’re going to create our basic web site, extending on what we’ve already covered.

  • Create folder name public off of the root folder
  • Add a file named index.html to public folder, here’s the HTML
    <html>    
        <body>
            <script src="./index.js"></script>
        </body>
    </html>
    
  • Run the following commands
    • yarn add webpack -D
    • yarn add webpack-cli -D
    • yarn add webpack-dev-server -D
    • yarn add babel-loader@7 -D (@7 was required for bable-core)
    • yarn add babel-core -D
  • Create a webpack.config.js in the root folder here’s mine
    var path = require("path");
    module.exports = {
       entry: {
         app: ["./public/index.js"]
       },
      output: {
        path: path.resolve(__dirname, "build"),
        filename: "bundle.js"
      },
      devServer: {
        port: 9000,
        contentBase: "./public"
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /(node_modules)/,
            use: {
              loader: "babel-loader",
              options: {
                presets: ["babel-preset-env"]
              }
            }
          }
        ]
      }
    };
    
  • Now replace the console.log line within the index.ts file with the following
    document.body.innerHTML = app.getSalutation();
    
  • Replace the previously created “start” script with “start”: “webpack-dev-server –open” in packages.json “scripts” section
  • Let’s run yarn start and if all went well you should see a browser window open and display our HTML page with the JavaScript created from our TypeScript file displayed

Time to create bundles

We’re going to use webpack to create some distribution bundles

  • Run the following commands
    • yarn add express -D
    • yarn add webpack-dev-middleware -D
    • yarn add html-webpack-plugin -D
    • yarn add clean-webpack-plugin -D
  • Change the webpack.config.json to
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    
    module.exports = {
      mode: 'development',
      entry: {
        app: './public/index.js'
      },
      devtool: 'inline-source-map',
      devServer: {
        port: 9000,
        contentBase: './dist'
      },
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: 'Demo'
        })
      ],
      output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/'
      }
    };
    
  • Add “bundle”: “webpack” to the scripts section of the packages.json file. This will create a dist folder with, both the HTML file and the JS files we’ve created and generated

Minifying

You’ll notice that the JavaScript file generated in the previous steps is not exactly small, containing comments, whitespace etc. So we’re going to minify it for distribution.

  • Run yarn add babel-minify-webpack-plugin -D
  • Within the webpack.config.js file, comment out devtool: ‘inline-source-map’,
  • Add this line to the top of the file
    const MinifyPlugin = require("babel-minify-webpack-plugin");
    
  • Add new MinifyPlugin to the file, so it looks like this
    plugins: [
       new CleanWebpackPlugin(),
       new HtmlWebpackPlugin({
          title: 'Demo'
       }),
       new MinifyPlugin()
    ],
    
  • Finally, run our script yarn bundle

Trying an alternate minify

Let’s try terser

  • Run yarn add terser-webpack-plugin -D
  • Add this line to the top of webpack.config.js
    const TerserPlugin = require('terser-webpack-plugin');
    
  • Add the following to webpack.config.js
    optimization: {
        minimizer: [new TerserPlugin({
          extractComments: true,
          test: /\.js(\?.*)?$/i,
        })],
      },
    

The optimization will need to be run webpack in production mode, i.e. webpack –mode=production or webpack-dev-server –open –mode=production or in webpack.config.js set mode: ‘production’.

Hence using yarn we can run yarn bundle –mode=production to see the bundle.js has been minified using terse. Obviously you can remove the new MinifyPlugin() also at this point if using TerserPlugin.

Creating a sample JavaScript package

In my previous post I covered some steps to use yalc to create local packages. Let’s look at creating a very simple package.

We’ll create a simple little mathematics package which will include functions to add, subtract, divide and multiply.

  • Create a folder for our package, for example Math
  • Add an index.js file which should look like this
    'use strict';
    
    module.exports = {
        add,
        subtract,
        divide,
        multiply
    }
    
    function add(a, b) {
        return a + b;
    }
    
    function subtract(a, b) {
        return a - b;
    }
    
    function divide(a, b) {
        return a / b;
    }
    
    function multiply(a, b) {
        return a * b;
    }
    
  • Now, as we’re going to want to turn this into a package, run
    yarn init --yes
    
  • Edit the package.json file to look like this
    {
      "name": "Math",
      "version": "1.0.0",
      "license": "MIT",
      "private": true
    }
    

Let’s look at what we’ve done, the use of index.js as opposed to say Mathmatics.js is this will then make referencing the file much simpler within the code importing the file, for example we can import like this

import Math from 'Math';

var result = Math.add(2, 5);

We’ve used strict mode to restrict the some JavaScript features but also enhances prevention of silly mistakes.

Next we need to export (at the module level) our functions. In the example we export multiple functions. We could also use the following syntax

module.exports = {
   add: function(a, b) 
   {
      return a + b;
   },
   subtract: function(a, b) 
   {
      return a - b;
   }
   // etc.
}

Another alternative syntax is

exports.add = function(a, b) {
   return a + b;
}

exports.subtract = function(a, b) {
   return a - b;
}
// etc.

Now you can package this up using yalc (as per my previous post on yalc).

Generators in JavaScript and TypeScript

Generators within JavaScript (and TypeScript) are similar to C# IEnumerable’s such that you can yield a value multiple times from a generator function (in either JavaScript or TypeScript), i.e.

function* someValues() {
    yield 1;
    yield 2;
    yield 3;
}

or within a TypeScript class we can write

export default class MyClass {
    *someValues() {
       yield 1;
       yield 2;
       yield 3;
    }
}

To use the someValues function we can loop using

for(let i of someValues()) {
    console.log(i);
}

Each item returned is a type of { value, done }, so for example

var values = someValues();

console.log(values.next());
console.log(values.next());
console.log(values.next());
console.log(values.next());

which would output

{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }