Sending Telemetry from GraphQL under NodeJS without Spamming

I am running a GraphQL server hosted with NodeJS. Under the hood, it is an Express server with Apollo Middleware. I am collecting different information along with errors. The way it works is that I have an Elastic Search server fronted by a simple REST API facade. The endpoint on the REST accepts a single telemetry payload or a collection of them. The latter is recommended. When I use the REST facade for the web, I am collecting all call to the telemetry and batch the request every 5 seconds or when the browser send a beacon (when leaving the page). It reduces the load on the server by limiting the number of HTTP requests. For example, if there is 24 different telemetry within a few seconds, it performs a single HTTP request with 24 entries.

Telemetry Information flow

Under NodeJS, I could do something similar with a timer, but while reading how the DataLoader library handles batching I thought I could code a similar pattern. Instead of leveraging on time, I could batch every telemetry on a single NodeJS event loop. In the NodeJS world, this is called a “tick”. There are two ways to accomplish the batching, and I leaned on setImmediate.

NodeJS Event Loop

The idea is that NodeJS runs in an infinite loop. It is possible to mention to the system to prepare the execution later, on the next loop with setImmediate which execute when the “poll phase” is completed. setImmediate is different from the setTimeout because it does not rely on a time threshold. Often, libraries use process.nextTick. it processes the task after the event loop. I avoided using process.nextTime because in some situation it can cause an infinite loop with recursivity. setImmediate is enough to delay the execution. In fact, after using it for more than two weeks, every telemetry collected within a single GraphQL request are batched together which is perfect in my case.

The code in the NodeJS server is short. There is a class that consists of a boolean field that indicates if we have batched information. By default, the value is false until we invoke the first time the function to send the telemetry. When the flag is true, we keep calling the code that will add into an array all the telemetry but we do not call the function performing the HTTP request to the API; we wait that the setImmediate function callback is executed. When this one is executed and returned with a successful HTTP code, we copy the content of the array, flush the data from the list of telemetry, send the information and turn back the flag to false. Ready for the next round of batching. While the code is sending the telemetries, other telemetries can be collected. The data is added to the array to be sent. In case of failure, the data is added back to the next batch.

public send(data: TelemetryPayload): void {
    const dateToSend = { ...data };
    this.listDataToSend.push(dateToSend);
    if (!this.isTransmittingQueuedPayload) {
        this.isTransmittingQueuedPayload = true;
        setImmediate(() => {
            this.send(); // Perform HTTP requests with all the this.listDataToSend
        });
    }
}

Overall, the code is pretty clean and under one hundred lines of code. It reduces drastically the number of HTTP requests while being easy to read once we get the setImmediate detail clarified.

My Other GraphQL Blog Posts

How to setup a TypeScript, NodeJS, Express Apollo Server to easy debugging with VsCode

There is a lot of keyword in the title but this is not a clickbait, we will setup without too much burden a simple configuration that will allow Visual Studio Code (VsCode) to hook into a GraphQL installation. The idea is that everytime a TypeScript file is saved that automatically the file is transpiled into JavaScript and to have Node reboot. The solution I propose can do the transpilation, the schema transportation and the restart of NodeJS under 2 seconds.

NPM

The first step is to get some NPM packages. The first one is named concurrently which will allow from a single line, a single NPM command to execute multiple commands. This is required to have TypeScript in watch mode, having a file watcher for the GraphQL schemas and restarting node if any of the previous two changes. The second is the package cpx which can watch for file and copy them if something changes. The third is TypeScript that will watch all TypeScript file for changes and build into the output folder. The fourth package is nodemon that monitor changes in file. If a file change, it restart Node.

"concurrently": "^4.1.0",
"cpx": "^1.5.0",
"typescript": "^3.2.2",
"nodemon": "^1.18.8"

Then few NPM scripts are required.

"dev": "concurrently \"tsc -w\" \"npm run watchgraphql\" \"nodemon build/dist/index.js\"",
"debug": "concurrently \"tsc -w\" \"npm run watchgraphql\" \"nodemon --inspect build/dist/index.js\"",
"watchgraphql": "cpx 'src/graphql/schemas/**/*.graphql' build/dist/graphql/schemas/ -w -v"

There are two main scripts. The dev and debug. I mostly run the second one because it does the same as the first one with the addition of opening a port for VsCode to connect to debug the NodeJS (Express) server. What it goes is to start concurrently TypeScript in watch mode (-w), run the watchgraphql and nodemon to watch every file (produced JavaScript and GraphQL schema files. The GraphQL’s schemas have there own extension “.graphql” and are not moved like TypeScript during the transpilation. Hence, it requires a separate process to move the file when we edit the file.

Visual Studio Code

Finally, within Visual Studio you need to create a debug launch configuration. The creation occurs in the fourth button of the menu, the one with a bug. It is possible to select “Add Configuration” in the dropdown to create a new debugging configuration. Here is the one I am using:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to node",
            "type": "node",
            "request": "attach",
            "restart": true,
            "port": 9229
        }
    ]
}

It will attach to an existing instance. It means that if you want to debug the startup of the NodeJS server that it does not work. You will need to change the way to avoid using nodemon and to have the VsCode debugger starting the NodeJS server. It is not a use case that I need, hence I do not have it configured.

Once you have these scripts in place and the VsCode configuration saved. You can click the play button or F5 to start debugging. It takes about 1-2 seconds to hook to the process. Any breakpoint you have set will stop the process and gives you time to explore the variables. If you do a change during the debug, NodeJS will restart and the debugging will stop and restart as well.

HTTP Request Debugging

I am using Axios, but other libraries allow also to shim a proxy to inspect HTTP request and response. It is very valuable when debugging an Apollo GraphQL server because you cannot do like with a web application and use Chrome’s network tab. A trick with Axios is when you configure the AxiosRequestConfig to set a proxy in the HTTP header of the request that point to your computer.

config.proxy = {
    host: "127.0.0.1",
    port: 5555
};

Then, installing a tool like Postman at the specified port is enough to receive every request with the proper HTTP headers in place.

Summary

I am far from being an expert concerning developing server side application with NodeJS. I was impressed of the quick result. Within an hour, I had a development environment that was efficient to develop and to debug. The experience of debugging directly in TypeScript is awesome and to see every request and response swimming through the proxy tool is priceless when it is the time to understand what is coming out and in the GraphQL’s resolvers.

Some other GraphQL articles

Unit Tests and Coverage Report in Jenkins using Jest from Create-React-App

Since I left Microsoft Visual Studio Online (VSTS) has an employee I have been using Jenkins which is the continuous integration (ci) platform Netflix uses. I configured two Jenkins jobs for the project I am leading. One is handling every pull request done against master and the second one is executed during the merge of any pull request into master. For many months, I didn’t have the unit tests running on the platform. The reason is that I am, yet, used to how Jenkins works and even after several months feel VSTS more intuitive. Regardless, recently I took the time and setup to have my TypeScript code using Create-React-App to run my unit tests in these two Jenkins tasks. I am using Create-React-App, which come with the best testing framework I have experimented so far which is Jest. My goal was to have all the unit tests ran as well as to see the coverage.

Here are the steps required to have Jenkins handle your test. First thing is to install a dev dependency to “jest-junit”. The reason is that we need to convert the format of Jest into Junit.

npm install --save-dev jest-junit

The next step is to download a Python script in your repository. I have mine in “tools”. The reason is also about converting. Jest coverage file is not in the right format. The Python script converts the locv into Cobertura format. You can download once the script at this address.

wget https://raw.github.com/eriwen/lcov-to-cobertura-xml/master/lcov_cobertura/lcov_cobertura.py

Few configurations are required in the package.json. The first one is to create a test command that Jenkins execute instead of the default test command. The command calls the react-scripts. I am using TypeScript, hence I have to use the react-scripts-ts command. The next parameter is the “test” command which we still want to execute. The change starts with the test results processor. This is where you specify the jest-junit to execute once the tests are done. I set my coverage to be positioned into the “coverage” folder which is the folder I have ignored in the .gitignore and where I have normally my local coverage file outputted. Here are the three commands I have. The first one runs the test, the second run and coverage for the ci (this is the new stuff) and the last one is when I want to run locally the coverage.

"test": "react-scripts-ts test --env=jsdom",
"test:ci": "react-scripts-ts test --env=jsdom --testResultsProcessor ./node_modules/jest-junit --coverage --coverageDirectory=coverage",
"coverage": "react-scripts-ts test --env=jsdom --coverage",

Finally, you need few jest-unit configurations. This can be in your package.json. I have some coverage folder that I want to exclude which you can do in the jest configuration under collectCoverageFrom. I had these before doing the task we are doing of configuring Jenkins. Then, the coverage reported must be lcov and text. Finally, the new configurations are under “jest-junit”. The most important configuration is the “output” which is again in the coverage folder. You can change the destination and file as you wish. However, remember the location because you will need to use the same in a few instants inside Jenkins.

  "jest": {
    "collectCoverageFrom": [
      "**/*.{ts,tsx}",
      "!**/node_modules/**",
      "!**/build/**",
      "!**/definitionfiles/**",
      "!**/WebWrokers/**",
      "!**/*.mock.ts",
      "!src/setupTests.ts"
    ],
    "coverageReporters": [
      "lcov",
      "text"
    ]
  },
  "jest-junit": {
    "suiteName": "jest tests",
    "output": "coverage/junit.xml",
    "classNameTemplate": "{classname} - {title}",
    "titleTemplate": "{classname} - {title}",
    "ancestorSeparator": " > ",
    "usePathForSuiteName": "true"
  },

In Jenkins, you need to add 2 build steps and 2 post-build steps. The first build step is to run the unit test with the script we just added in the package.json. The type of build step is “Execute Shell”.

npm run test:ci

The second step is also an “Execute Shell”. This one calls the python code that we placed in the “tools” folder. It is important to change the path of your lov.info and coverage.xml. Both are in my “/coverage/” folder. The “base-dir” is the directory of the source of your code.

python tools/lcov_cobertura.py coverage/lcov.info --base-dir src/ --output coverage/coverage.xml

The next two steps are “Post-Build”. This time, two different types. The first one is “Publish JUnit test result report”. It has a single parameter which is the XML file. Mine is set to “coverage/junit.xml”. The second task is a “Publish Cobertura Coverage Report”. It also takes a single parameter which is the coverage.xml file. Mine is set to “coverage/coverage.xml”.

At that point, if you push the modification from the package.json and the Python script you will see Jenkins running the unit tests and doing the conversion. It is possible to adjust the threshold of how many tests your allow to fail to not break the build as well as setting the percentage of coverage you expect. You will get a report on the build history that allows you to sort and drill into the coverage report.

NPM locally to increase coding velocity between two projects

One advantage having a big repository is to be able to change a part quickly and see the result right away. Recently, I moved a piece of code into another library. The reason was to reuse the library on several systems. The concept of breaking apart into different cohesive library make sense, however, it comes with the price that a quick one line change can become more demanding. I found that it’s roughly 5 to 10 times slower. The reason is that a single line of change require to save the file and the code is ready to use. The same change in another repository needs to package the source code and to fetch the new package. The major problem is that everyone using the package sees the version bumping and the release may not even be ready to share. Ideally, a library is self-contained, and a group of unit tests ensures that the quality is as expected. However, in reality, it appears that a shareable version may require some checks directly on the browser.

NPM provides a solution. The solution is to share the library code locally to a local project. The beauty is that no code modification is required. The solution tells NPM to link locally instead of getting the package from the remote server.

The first step is to have your project that consumes the library and the library locally on your computer. Both projects can reside anywhere.

The second step is to go at with your command line at the location of the package.json of your library. NPM has a command called “link”. The execution of the command will specify if the creation is a success or not. If it is a success, you can use your command prompt to move to the project that consumes the library. Again, at the level of the package.json the command “npm link” must be executed. The difference is the argument that needs to specify which library to link. The name of the library is the name specified in the package.json of the library that we “npm link” at the second step. This command succeeds with an output that shows that node_modules points to the local directory.

Finally, once you are done and want to use the node_module library, you can unlink. The command to unlink is “npm unlink ” where the parameter is the parameter of the library linked. The library can also be unlinked by going back to the library and executed “npm unlink”.

As a recap:

// 1) At the library level
npm link
// 2) At the project level (consumer)
npm link my-library-name
// 3) Stop using the local version
npm unlink my-library-name
// 4) Stop sharing locally my-library-name (must move back to library level)
npm unlink

The technique works with TypeScript. The compilation of the library needs to occur since the link to the library read the package.json and will look for the “files” property which is mostly pointing to the build folder.

Before closing on the subject, make sure that both libraries are running on the same NodeJS and npm version. Each NodeJS version links to a different folder. You can confirm the location of the link by using “node -v”. Another tips is for people using “create-react-app”. In that case, you may have to close and open the development server on each change. The reason is that Webpack does not notice the change in node_modules folder and will serve you the same files of the startup.

NPM Useful Commands

This article will be pretty slim but can be helpful for more than just myself so I am sharing. Here are some commands available with NPM that you may not know that can be useful.

To know packages that are installed globally:

npm list -g --depth=0

To know where the packages are installed. It gives the global location if no node_modules folder in the direct folder parent tree:

npm root
npm root -g // The global folder

To know your NPM version and the actual released version

npm root

To know all available version of a library:

npm show react-native versions

To get all your direct dependencies current version and latest:

npm out --depth=0

NodeJs and MongoDb on Windows : Connecting and Inserting

MongoDb is an interesting choice of permanent persistence when using NodeJs since it stores document which is ideal of JSON document to get stored.

You can download a free version directly on MongoD : https://www.mongodb.com/download-center#community
Once it’s downloaded, it’s best to be sure that the system environment variable is set to have an entry in the path to point to the bin folder of the installation path of MongoDb.

Before working out MongoDb with NodeJs, I recommend to download RoboMongo for free: https://robomongo.org/download. This tool allows to query MongoDb and explore the data. Before using RoboMongo or to use the MongoDb library, we need to run the MongoDb server. To do so, go in the development folder you are working and execute the mongod command with the dbpath. For example, the following command will store the MongoDb in the “data” folder in the development folder.

mongod --dbpath=.\data

Inside your NodeJs project, you needs sto have the mongodb library. If you are using TypeScript, you can get the type definition too.

npm install mongodb --save
npm install @types/mongodb --save-dev

At this point, you can start using the library to access the information. First step, connecting to the server. Second step, connecting to the collection. The first step is the same as any other database, the second one is just that every documents are stored into a collection. Think about it as a table.

From here, we need to import some classes.

import { MongoClient, MongoError, Db, InsertOneWriteOpResult } from "mongodb";

MongoClient is the main class to connect to Mongo. MongoError is the class that wrap the error which we will use to get information about the connection’s error. Db is the class that hold information about MongoDb once connected. We need it to properly close the connection, but also to select the collection in which we want to invoke the action (find, insert, delete). The InsertOneWriteOpResult is the result on an insert.

Here is the connection code:

MongoClient.connect(url, (errMongo: MongoError, db: Db) => {
    if (errMongo) {
        console.log(errMongo);
    } else {
        console.log("Connected successfully to server");
    }
});

To insert something in you need to get the collection name and use the insert method. Something I haven’t yet figure out perfectly is how to handle Date from a .json file. In my case, I was opening file (.json) and inserting them into MongoDb. The Json parse method was returning the date as string, hence I needed to assign the value back with an instance of date


// To have a real date format in MongoDb
objToInsert.fullDate = new Date(objToInsert.fullDate);

// Access the collection we want to insert
const collection = db.collection("documents"); // "documents" can be anything you want your collection to be named

// Insert with a callback that has an error or the result data
collection.insert(objToInsert, (err: MongoError, result: InsertOneWriteOpResult) => {

});

The code above will add a new entry and alter the object to add an “_id” with a GUID for the object. This way, every entry has a unique identifier automatically.

Resizing an Image with NodeJs

This is the second post about project of creating a search tool for local pictures. As mentioned in the first post, this tool needs to use a web service to get information about the picture. This mean we need to upload the image that Microsoft Cognitive Vision/Face service will analyze and return a JSON object with information about the picture. Like most service, there is some constraints in term of the minimum and maximum of the size of what you can upload. Also, even for us, we do not want to send a 25 megs picture when it is not necessary. This article discuss about how to resize picture before sending a request to the web service. This will not only allow to be withing the range of the acceptable values, but also speed up the upload.

I decide to take the arbitrary value of sending picture with the widest side of 640px. This produce in average a file 30kb which is tiny but still enough for the cognitive service to give very good result. This value may not be good if you are building something similar where people are far or if you are not using portrait pictures. In my case, the main subjects are always close range, hence very easy to get detail at that small resolution.

Resizing a file requires to use a third-party library. This is something easy to find with JavaScript and NPM has a library named “Sharp” that do it perfectly. The TypeScript definition file is also available, so we are in business!

npm install --save sharp
npm install --save-dev @types/sharp

Before anything, even if this project is for myself, I defined some configuration variables. Some rigor is required when it’s cheap to do! The three first constant is the maximum size we want to output the image. I choose 640 pixel. The directory name is the constant of the folder where we will save the image we will send and where we will late save the JSON file with the analysed data. We save the resized image because on the website later, we will use this small image instead of the full resolution image. The website will be snappy and since we have the file, why not using this optimization for free. At 30kb for 2000 images, we only use 58 megs. The last constant is the glob pattern to get all underscore JPEG pictures. We will talk about glob very soon.

const maxSize = 640;
const directoryName = "metainfo";
const pathImagesDirectory = path.join(imagesDirectory, "**/_*.+(jpg|JPG)");

The second pre-task is to find the images to resize. Again, this will require a third-party library to simplify our life. We could recursively navigate folders, but it would be nicer to have a singe glob pattern that handle it.

npm install --save glob
npm install --save-dev @types/glob

From there, we need to import the module. We will bring the path and fs module of NodeJs to be able to create proper path syntax and to save file on disk.

import * as g from "glob";
import * as path from "path";
import * as sharp from "sharp";
import * as fs from "fs";

The first function that we need to create is the one that return a list of string that represent the file to resize. This will be all our underscore aka best pictures. We want to be sure that we can re-run this function multiple times, thus we need to ignore the output folder where we will save resized images. This function returns the list in a promise fashion because the glob library is asynchronous. Here is the first version which call the module function “Glob” and add everything into an array while sending in the console the file for debugging purpose.

function getImageToAnalyze(): Promise<string[]> {
    const fullPathFiles: string[] = [];
    const promise = new Promise<string[]>((resolve, reject) => {
        const glob = new g.Glob(pathImagesDirectory, { ignore: "**/" + directoryName + "/**" } as g.IOptions, (err: Error, matches: string[]) => {
            matches.forEach((file: string) => {
                console.log(file);
                fullPathFiles.push(file);
            });
            resolve(fullPathFiles);
        });
    });
    return promise;
}

This can be simplified by just returning the matches string array and returning the promise instead of using a variable. At the end, if you are not debugging you can use :

function getImageToAnalyze(): Promise<string[]> {
    return new Promise<string[]>((resolve, reject) => {
        const glob = new g.Glob(pathImagesDirectory, { ignore: "**/" + directoryName + "/**" } as g.IOptions, (err: Error, matches: string[]) => {
            resolve(matches);
        });
    });
}

As mentioned, the quality of this code is average. In reality, some loves are missing around the error scenario. Right now, if something is wrong, the rejection promise bubble up.

At this point, we can call the method with :

console.log("Step 1 : Getting images to analyze " + pathImagesDirectory);
getImageToAnalyze()
    .then((fullPathFiles: string[]) => {
        console.log("Step 2 : Resize " + fullPathFiles.length + " files");
        return resize(fullPathFiles);
    })

The code inside the “then” is the one executed if the promise is resolved successfully. It will start resizing the list of pictures and pass this list into the function that we will create in an instant.

The resize function is not the one that will do the resize. It will call the function that does the resize only if the picture has not been yet resized. This is great if something happen to fail and you need to re-run. The resize function will check in the “metainfo” folder, where we output the resized picture and only resize this one if not present. In both case, this function return a promise. The type of the promise is a list of IImage.

export interface IImage {
    thumbnailPath: string;
    originalFullPathImage: string;
}

This type allows to have the detail about the full path of the thumbnail “resized” picture and the original picture. When we have already resized, we just create an instance, when we do not have an image we create this one and then return a new instance. This method waits all resize to occur before resolving. This is the reason of the .all. We are doing so just to have a clear cut before moving to the next step and since we are launching multiple resizes in parallel, we are waiting to have them all done before analyzing.

function resize(fullPathFiles: string[]): Promise<IImage[]> {
    const listPromises: Array<Promise<IImage>> = [];
    const promise = new Promise<IImage[]>((resolve, reject) => {
        for (const imagePathFile of fullPathFiles) {
            const thumb = getThumbnailPathAndFileName(imagePathFile);
            if (fs.existsSync(thumb)) {
                listPromises.push(Promise.resolve({ thumbnailPath: thumb, originalFullPathImage: imagePathFile } as IImage));
            } else {
                listPromises.push(resizeImage(imagePathFile));
            }
        }
        Promise.all(listPromises)
            .then((value: IImage[]) => resolve(value));
    });
    return promise;
}

This function use a function to get the thumbnail path to lookup if it’s been already created or not. This function call another one too, and both of these methods are having the same goal of providing a path. The first one, the getThumbnailPathAndFileName get the original full quality picture path and return the full image path of where the resized thumbnail is stored. The second one is a function that will be resused in some occasion and it gives the metainfo directory. This is where the resized picture are stored, but also the JSON file with the analytic data are saved.

function getThumbnailPathAndFileName(imageFullPath: string): string {
    const dir = getMetainfoDirectoryPath(imageFullPath);
    const imageFilename = path.parse(imageFullPath);
    const thumbnail = path.join(dir, imageFilename.base);
    return thumbnail;
}

function getMetainfoDirectoryPath(imageFullPath: string): string {
    const onlyPath = path.dirname(imageFullPath);
    const imageFilename = path.parse(imageFullPath);
    const thumbnail = path.join(onlyPath, "/" + directoryName + "/");
    return thumbnail;
}

The last method is the actual resize logic. The first line of the method create a “sharp” object for the desired picture. Then we invoke the “metadata” method that will give us access to the image information. We need this to get the actual width and height and do some computation to get the wider side and find the ratio of resizing. Once we know the height and the width of the thumbnail we need to create the destination folder before saving. Finally, we need to call the “resize” method with the height and width calculated. The “webp” method is the one that generate the image. From there, we could generate a buffered image and use a stream to handle it in memory or to store it on disk like we will do with the method “toFile”. This return a promise that we use to generate and return the IImage.

function resizeImage(imageToProceed: string): Promise<IImage> {
    const sharpFile = sharp(imageToProceed);
    return sharpFile.metadata()
        .then((metadata: sharp.Metadata) => {
            const actualWidth = metadata.width;
            const actualHeight = metadata.height;
            let ratio = 1;
            if (actualWidth > actualHeight) {
                ratio = actualWidth / maxSize;
            } else {
                ratio = actualHeight / maxSize;
            }
            const newHeight = Math.round(actualHeight / ratio);
            const newWidth = Math.round(actualWidth / ratio);
            const thumbnailPath = getThumbnailPathAndFileName(imageToProceed);
            // Create directory thumbnail first
            const dir = getMetainfoDirectoryPath(imageToProceed);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir);
            }

            return sharpFile
                .resize(newWidth, newHeight)
                .webp()
                .toFile(thumbnailPath)
                .then((image: sharp.OutputInfo, ) => {
                    return { thumbnailPath: thumbnailPath, originalFullPathImage: imageToProceed } as IImage;
                });
        }, (reason: any) => {
            console.error(reason);
        });
}

This conclude the resize part of the project. It’s not as straight forward as it may seem, but noting is space rocket science either. This code can be optimized to start resizing without having analyzed if all the image are present or not. Some refactoring could be done around the ratio logic within the promise callback of sharp’s metadata method. We could also optimize the write to remain in memory and hence having not to reload the thumbnail from the disk but working the on the memory buffer. The last optimization wasn’t done because I wanted every step to be re-executed what ever the state in which they were stopped. I didn’t wanted to bring more logic to reload in memory if already generated. That said, it could be done. The full project is available on GitHub : https://github.com/MrDesjardins/CognitiveImagesCollection

Create a Local Search Tool for Pictures in NodeJs

I recently searched for a specific picture of my daughter on my local drive with some issue. First, I am taking a lot of picture and it was hard to find. Second, I have some good pictures and some average, but I keep them all, hence I have thousand and thousand of picture that are not easy to find. However, I always had since 2003 got a systematic way to store my picture which is a main folder that contains one folder per year and every year has many folder per event. The event folder always have the format “yyyy-mm-dd-EventDescriptionIn2words”. I also have the habit to prefix the best pictures with an underscore inside these folders. Still, the picture name are always the sequential number of my camera and they are not consequent in time. There is no way I can search for “Alicia happy in red dress during summer 2015” for example.

Here come the idea that I started few weeks ago: having a training set of pictures that will serve as a base for the system to figure out who is in my picture and having a service that analyse what is in the picture. On top of the data, a simple website that let me query the database of pictures and return me the best match with a link to the actual full quality picture. Before going any further, a word of caution, the idea of this project is not to develop something that will scale, or a stellar code, hence the quality of the code is very average, but workable solution. Everything is developed with NodeJs, TypeScript, Microsoft Cognitive Api, MongoDb and doesn’t have any unit tests. I may refactor this project someday, but for the moment, let’s just get out head around how to do it.

I’ll write several posts around this project. In fact, at the moment I am writing this article, I have only done half way through the first phase which is analyzing a little subset of my picture. This article will serve more as a description of what will be build.

First thing we need to do is to read a sample of all the images. For me, instead of scanning and analyzing my whole hard drive for picture, I will analyze only picture between a specific range of date. At this date, I have 34 000 pictures taken since 2009 (since I met my wife) and in this population 2 000 have been identified with an underscore which mean that I really like them. For the purpose of having a smaller set of search and not having to analyze for too long time I will only use pictures with an underscore. Second, in these pictures, I can stay that roughly 75% of people are my wife, my daughter or me. Hence, I will only try to identify these people and mark others as “unknown”. Third, I want to be able to know the emotion and what is going on in the picture. This will require a third party service and I will use Microsoft Azure Cognitive API. I’ll get more in detail in the article about the api.

Once the picture will be analyzed, the data will be stored in a MongoDB, which is a JSON based storage. This is great because the result of all the analysis will be in a JSON format. It will allow us to query the content to get results to display in the website. To simplify this project, I will mark the first milestone as scanning the picture and create one JSON file per underscore file inside a “metainfo” folder. The second milestone will be to hydrate the MongoDB and the third one to create a simple web application that will communicate and display the result from MongoDB.

I’ll stop here for the moment. You can find the source code of the progress of this project in this GitHub repository : https://github.com/MrDesjardins/CognitiveImagesCollection

Using TypeScript, React and WebPack

I created an open source project to bootstrap TypeScript and React few months ago. You can see the first article about TypeScript/React/Gulp before this article. It wasn’t bundling the code, and was using Gulp which is in mid-2017 not the preferred tool to package JavaScript code. At this moment, Webpack is the most popular tool allowing to do everything Gulp or Grunt was doing but avoiding to rely on the middle man of having Gulp’s package (or Grunt’s package) to invoke the actual library. Webpack is also very smart in term of exploring the code and figure out dependencies. This article will focus to migrate from Gulp to Webpack for a TypeScript and React project.

First of all, we need to change index.html. The file was using RequireJs and was not referring to any bundles. The change is dual. We need to remove RequireJs. We will use Webpack to handle to load dependencies between modules. We also need to refer to bundles.

Before:

<html>
    <head>
        <title>TS + React Boilerplate v1.01</title>
    </head>

    <body>
        <div id="main"></div>
    </body>
    <script src="vendors/requirejs/require.js"></script>
    <script src="vendors/jquery/jquery.js"></script>
    <script>
        requirejs.config({
            //Every script without folder specified before name will be looked in output folder
            baseUrl: 'output/',
            paths: {
                //Every script paths that start with "vendors/" will get loaded from the folder in string
                vendors: 'vendors',
                jquery: '../vendors/jquery/jquery',
                react: "../vendors/react/dist/react",
                "react-dom": "../vendors/react-dom/dist/react-dom"
            }
        });
        //Startup file
        requirejs(['file1']);
    </script>

</html>

After:

<html>
    <head>
        <title>TS + React Boilerplate v1.01</title>
    </head>
    <body>
        <div id="main"></div>
    </body>
    <script src="vendorbundle.js"></script>
    <script src="appbundle.js"></script>
</html>

RequireJs’ configuration and the startup file are gone. The complexity will move into Webpack’s configuration file that we will see soon. So, at this point, you see that we won’t be using AMD. This mean that we need to build our TypeScript to use something else. We will use CommonJS.

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "module": "commonjs",
    "outDir": "./deploy/output",
    "jsx": "react",
    "noImplicitAny": true
  },
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

since Webpack will read the EcmaScript syntax used in each file of each module, it will transpile in CommonJS format. The JavaScript produced is read by Webpack and this one will bring all the file into a single one (bundle). This remove the need to load asynchronously (like AMD) was doing.

Changing to CommonJS made the code to require a change. If you want to load a relative to the file that want to import a module, it needs to start with “./” instead of directly the name. For example, you won’t be able to write :

import { Component } from "component1";"

but

import { Component } from "./component1";

The next change was around JQuery. The file that was using JQuery didn’t had any reference to JQuery, but now we explicitly mention the library.

import * as $ from "jquery";

Before going in Webpack configuration, we had with AMD a lazy loading file that was loading and using a specific file after 2 seconds. This is to simulate the “load on-demand” files that we may want not to load initially. The scenarios are multiple. This can be justify because the user is rarely using the feature, hence no need to load this one. This can also be that the user doesn’t have the authorization to do this kind of action, thus no need to load code that won’t be used.

Here is the AMD solution we had before:

import foo = require("folder1/fileToLazyLoad");
export class ClassB {
    public method1(): void {
        console.log("ClassB->method1");
        setTimeout(() => {
            requirejs(["folder1/fileToLazyLoad"], (c: typeof foo) => {
                const co = new c.ClassC();
                co.method1();
            });
        }, 2000);
    }
}

The first line is to tell TypeScript the type we want to lazy load. It was using “require” which we will still use. This time, we can use the relative path. So far, not much as change. However, we can see that we were using requirejs directly inside the timer. This time, we will use CommonJS and load the module. It’s almost the same thing — using a different library.

import foo = require("./fileToLazyLoad");
export class ClassB {
    public method1(): void {
        console.log("ClassB->method1");
        setTimeout(() => {
            System.import("./fileToLazyLoad").then((c: typeof foo) => {
                 const co = new c.ClassC();
                 co.method1();
            });
        }, 2000);
    }
}

We are at the point where bigger change will occurs. The change start with NPM module that we need to use. As we saw, we can remove RequireJS from the dependencies list. We also need to bring many libraries for Webpack, loader and utility library to clean and move files. Here is the complete list of dependencies:

"devDependencies": {
    "@types/express": "^4.0.35",
    "@types/jquery": "^2.0.46",
    "@types/react": "^15.0.26",
    "@types/react-dom": "^15.5.0",
    "@types/systemjs": "^0.20.2",
    "awesome-typescript-loader": "^3.1.3",
    "copyfiles": "^1.2.0",
    "del-cli": "^1.0.0",
    "express": "^4.15.3",
    "file-loader": "^0.11.2",
    "html-webpack-plugin": "^2.28.0",
    "source-map-loader": "^0.2.1",
    "typescript": "^2.3.4",
    "webpack": "^2.6.1",
    "tslint": "^5.4.2"
  },
  "dependencies": {
    "jquery": "^3.2.1",
    "react": "^15.5.4",
    "react-dom": "^15.5.4"
  }

The next step is that we won’t use Gulp to invoke action. If we want to delete previous generated deploy files, build TypeScript or run the server, we need to use the CLI of each of the tool we are using. We could use directly the TypeScript’s CLI, named tcs, and use xcopy to move file, etc. The problem is that it is not easy to remember. NPM allows to have custom script which can be invoked with “npm use ABC” where “ABC” is the name of your script. Here is the script we need to add to replace the Gulp tasks we had.

  "scripts": {
    "clean": "del-cli deploy/**",
    "package": "./node_modules/.bin/webpack --config webpack.config.js --display-error-details",
    "copy": "copyfiles -u 1 ./app/index.html ./deploy",
    "build": "del-cli deploy/** &amp; SET NODE_ENV=development &amp; webpack --config webpack.config.js --display-error-details &amp; copyfiles -u 1 ./app/index.html ./deploy/",
    "server": "node bin/www.js",
  },

The “clean” script use the “del-cli” to delete the deployment folder. This could be use a native Windows or Linux command, but using this tool allows to be cross platform. The “package” allows to run webpack with a specific configuration file and for debugging purpose to display verbose detail. The principle is the same for all others script. The “build” one is using the clean + package + copy. So, in practice, you should use only build and server.

The final step is to configure Webpack. This is done in the file webpack.config.js. You can rename it the way you want, you just need to specify it in the webpack command after –config. Webpack can use many NPM package to accomplish its job. For sure, you need at least the “webpack” package.

var path = require('path');
var webpack = require('webpack');

Webpack needs to have an entry point. In the example we are working on, the main file is the one that was used in the index.html with “requirejs([‘file1’]);”. This time, we do not have any indication in the HTML file. However, Webpack needs one, or many, entry point and will navigate through all the dependencies to make the main bundle.

module.exports = {
    entry: {
        app: "./app/scripts/file1.tsx"
    },

Entry may be the entry point, Output will be where the bundles goes. The filename uses the square bracket which will be replaced by the key provided by each entry point. In our example, we have “app” in the entry, and we will have a file produced with the name “appbundle.js” in the output. The directory is provided at the “path” property, which in that case is “deploy”.

    output: {
        path: path.resolve(__dirname, 'deploy'),
        filename: '[name]bundle.js'
    },

The next configuration is to tell which extension Webpack should care of. For us, it’s TypeScript

    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.jsx']
    },

This property allows to have source map. This give the possibility to debug TypeScript in Chrome on the real individual file even if it’s bundled.

    devtool: "source-map",

Webpack work with rules. Every “test” evaluate a condition to execute a loader. We use two different ones. One to call the TypeScript loader that will transpile TS and TSX file. The second one is to generate source map. Even if we have the devtool to provide source map, we need a central place to handle third-party JS library too.

    module: {
        rules: [
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
        ]
    },

The last piece is a plugin called CommonsChunkPlugin. It comes from Webpack and its role is to great additional bundle. In that case, we create a bundle name “vendorbundle.js”. The minChunk can be a number of time we see the reference to join the bundle. For example, if we have a module that we use often and that we want them to be in a common bundle, we can say “5” and if more than 5 modules reference than instead of being in the “app” one, it would go in this one. For us, we want to have all vendors module, which mean they are from node_modules directory. To do so, the minChunks allows to pass a function. When it contains the node_modules in the path, it goes into that bundle instead of the main one (app).

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",
            filename: "vendorbundle.js",
            minChunks: function(module) {
                return module.context &amp;&amp; module.context.indexOf('node_modules') !== -1;
            }
        })
    ]
};

You can find the exact code from this commit in GitHub. In this article, we saw how to remove Gulp to use Webpack. Not only it removes dependencies to Gulp and Gulp’s packages, it also bring a powerful tool to bundle smartly. The next step will be to bring an auto-reload when the code change to have TypeScript compile automatically to get JS deployed.

Visual Studio Code with NPM and TypeScript (Part 8 : SASS & CSS)

Transforming SCSS into CSS is a matter of using less than 5 lines of code. NPM has a package that you can use with Gulp. In less than 5 minutes, you can have SCSS configured to compile all your files into CSS.

The first step is to get the gulp sass package. You need to install the dependency has development since you won’t need it at the browser level.

npm install gulp-sass --save-dev

The next step is to create a step that will take all you scss files, pipe the files into the sass compiler and pipe the output into your output folder, where you will references them from your HTML file to serve the style. Here is the Gulp task.

gulp.task('scss', function() {
  gulp.src('sass/**/*.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(gulp.dest('./css/'));
});

You can find all changes for SCSS inside this commit[1] for the project we are building up. You may see some differences in the commit compared to this blog post. For example, instead of relying on string directly inside the task for path, I opted to use a constant. It’s always better to have in a centralized way in case of change or in case that it can be reused in another task.

Another change that you might consider is to add this new created task in the dependency of tasks for the build task or the watcher.

Here is a screenshot of the output where the SCSS generates CSS that modify the HTML.

SCSS:

body{
    font-size:36px;
    span{
        font-size:6px;
    }
}

CSS:

body {
  font-size: 36px; 
}
body span {
    font-size: 6px; 
}

HTML Output:

[1]:https://github.com/MrDesjardins/TypescriptNpmGulp/commit/02410d535a12cb48b167ff45b18970d312776270