Visual Studio Code with NPM and TypeScript (Part 3 : Gulp)

Previously, we setup TypeScript but had two problems. The first one was that we couldn’t move the vendor library and the second that we couldn’t test the generated TypeScript file since we do not have a web server running. We will tackle the first problem by using Gulp. Gulp is like MsBuild, it’s only goal is to help you automate some tasks.

To be able to use Gulp, we need to download gulp. It’s convenient since we can get it from npm by executing the install command.

npm install gulp --save-development
//or
npm install gulp -g

Create a Gulp’s configuration file : gulpfile.js at the root, sibling to TypeScript’s configuration file, and typings’ configuration file. We will need some additional node modules to help us working inside Gulp. You can get the one we will use by typing:

npm install gulp-typescript --save-development
npm install typescript --save-development
npm install del --save-development
npm install gulp-sourcemaps --save-development

This file is pure JavaScript that use Node’s module to execute JavasScript for specific tasks. The task runner is Gulp. The goal is to be able in the console to write:

gulp clean
//or
gulp build

The Gulp file that we will build is simple for the case of learning how to use Gulp to do:

      Clean up previous build file
      Use TypeScript to compile
      Move vendors (third-party) libraries

Before creating these 3 Gulp’s tasks, we need to instanciate some node’s modules that will help us doing the work.

var gulp = require('gulp');
var tsc = require('gulp-typescript');
var del = require('del');
var sourcemaps = require('gulp-sourcemaps');
var tsProject = tsc.createProject('tsconfig.json');

The main one is Gulp which is the runner. This will create entry point that we can invoke by the command line. Gulp-typescript will read our tsconfig.json and use TypeScript to build the code. Del is a library to delete files, which we will use to delete old files. Gulp-sourcemaps is used to create .map.js file, for debugging purpose. Finally the last line just load the TypeScript configuration by using gulp-typescript module that we just loaded.

The next step is to define some constants to help us having a cleaner Gulp code.

var paths = {
    webroot: "./",
    node_modules: "./node_modules/",
    typescript_in: "./src/",
    typescript_out: "output",
    typings: "./typings/",
    typescript_definitions: "./typings/main/**/*.ts"
};
paths.allTypeScript = paths.typescript_in + "**/*.ts";
paths.modulesDestination = paths.webroot + "vendors/";

Here start the fun. Let’s create the first Gulp task to delete previous generated JavaScript file and mapping file from TypeScript. This is required because even if TypeScript will overwrite previous JavaScript generated, if you delete a TypeScript, the JavaScript will hang in the folder which can cause size problem once we bundle all JavaScript.

gulp.task("clean", function (callback) {
    var typeScriptGenFiles = [
        paths.typescript_out + "/**/*.js",
        paths.typescript_out + "/**/*.js.map"
    ];

    del(typeScriptGenFiles, callback);
});

The syntax is the name of the task, followed by an optional depencency array (not present in this example) and a callback function. The purpose of this callback is to notify Gulp that the task is done.

In our simple case, we pass an array of file patterns to a node’s module to delete the file. Nothing complex. Let’s move on to the vendor copy task.

The second task is to copy vendors library. This time, we use Gulp’s functions that will get a list of library, get the code, pipe the result into a new destination.

gulp.task("copy", function () {
    var modulesToMove = {
        "jquery": "jquery/dist/jquery*.{js,map}"
    }

    for (var destinationDir in modulesToMove) {
        gulp.src(paths.node_modules + modulesToMove[destinationDir])
            .pipe(gulp.dest(paths.modulesDestination + destinationDir));
    }
});

Finally, the biggest task : building. This need to create the TypeScript and if needed definition files. We use the tsProject variable that come from the tsconfig.json, get all the source, generate the source map, compile. After, we take all definition file and write everything at the destination path. Then, we do the same with JavaScript file where we write the source map and source in the destination folder. Here how it looks:


gulp.task("build", function () {
    var sourceTsFiles = [paths.typescript_in, paths.typescript_definitions];
    var compilationResults = tsProject.src()
        .pipe(sourcemaps.init())
        .pipe(tsProject())
    compilationResults.dts.pipe(gulp.dest(paths.typescript_out));
    return compilationResults.js
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(paths.typescript_out));
});

So far, we can go in the console and use : gulp clean or gulp copy or gulp build. We saw that we can have a second parameter that is an array of task name, we could have a task that execute these three tasks we just created which will allow us to execute gulp buildall and have the clean, copy and build executed.

gulp.task("buildall", ["clean", "copy", "build"], function (callback){
    callback();
});

Gulp’s tasks could be even more complex, do JavaScript minimization, bundle, etc. The idea is that you need to find existing node modules (or create your own) and use it.

Visual Studio Code and Debugging Gulp Script

Microsoft Visual Studio Code (VSCode) has the capability to debug TypeScript, JavaScript and a lot of other languages. One interesting thing is that Visual Studio Code can also debug Gulp script (written in JavaScript). This is very useful since writing code that become complex is easier with good step through capabilities.

To do so, we need to add a launch configuration for VSCode. This is done by adding inside the root of your project a folder called “.vscode” and adding a file named “launch.json”.

This file is used by Visual Studio when you hit “F5” or when you go in the left panel, under “debug” and click “Play”.

The configuration contains few item that you must have, and some that you need to configure.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Debug Gulp",
            "program": "${workspaceRoot}/node_modules/gulp/bin/gulp.js",
            "stopOnEntry": true,
            "args": [
              "copy"  
            ],
            "cwd": "${workspaceRoot}/",
            "outFiles": [],
            "sourceMaps": true,
            "runtimeExecutable": null,
            "env": {
                
            }
        }
    ]
}

The type, request are required to be “node” and “launch” which said to VSCode that we will debug a node application. The “name” property is the name that will show in the debugger. In the screenshot you see it’s written “Debug Gulp” which is the name specified here. The very important part is the “program” which must point to Gulp. So far, we said to VSCode to execute node with the program Gulp.

“StopOnEntry” is not required but it will stop right when it loads the program. I found it handy to have it stop, which allow me to go set my breakpoint into the Gulp’s task I want to debug. In regard of which task we debug, it is defined under the args. In my example above, I am debugging the task named “copy”. The “cwd” is where the gulpfile.js is located, this is where the task to debug is located. It’s white to use the workspace root keyword to start from a good unchangeable root.

And that’s it! You will have the possibility to step through all the Gulp’s task code.

Visual Studio Code with NPM and TypeScript (Part 2 : TypeScript)

In the previous article, we got introduced to NodeJs and npm. This time, we will create two basic TypeScript file and have them to be executed by the main HTML file.

We need a HTML file to host the JavaScript files produced by TypeScript. We could directly load the JavaScript produced by a script tag in the HTML, but that won’t be good in the long run. The problem doing so is that the first script will refer the second script by module which will need require with EcmaScript 5 and below. While the specifications are out for EcmaScript 6, and that we can use the syntax with TypeScript, the output resulted must be downgraded in EcmaScript 5 which require an AMD loader, like require.js. TypeScript alone can generate JavaScript files at the right place, but JavaScript files from npm package will be located at the wrong place : in node_modules. Ideally, we want to take the needed one into a specific path, for example under “vendors” folder. First step, let’s configure TypeScript to generate the JavaScript file into “output” folder. To do so we need to have a tsconfig.json that specify few options. Options are read by Typescript when tsc command line is executed in the folder that has the json file. Before going any further, make sure you have installed TypeScript and have in your path the bin folder. At this time, I have downloaded TypeScript in the official website and have in my machine path : C:\Program Files (x86)\Microsoft SDKs\TypeScript\2.1.

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "module": "amd",
    "outDir": "./output"
  },
  "include": [
      "src/**/*"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

The compiler options are the sourcemap which will allow you to debug directly the TypeScript file, the target that indicate which version of EcmaScript will be written in TypeScript. Specifying a module tell TypeScript that we will substitute the module import/export by AMD which will be requirejs. OutDir is where the compiled TypeScript will output the JavaScript. Includes is the list of file to compile, excludes what to not touch. If you create 2 TypeScript file named file1.ts and fileToInclude.ts with the following code and compile you will see generated file in the right output folder.

The next step is to use these scripts in Html. But foremost, two scripts will be needed as we normally do by using script tag. The first one is to get requirejs. This will allows to setup require but also allow to call the entry point in the JavaScript (for us it’s file1.js). The second script is JQuery. I am using JQuery directly in script because, often if not most of the app, needs JQuery but won’t use it as a module. This way, we will be able to use it anywhere even in situation without AMD.

<html>
    <head>
        <title>Test</title>
    </head>

    <script src="/vendors/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'
            }
        });
        //Startup file
        requirejs(['file1']);
    </script>
</html>

To make it more realistic, let’s change the FileToInclude.js to use JQuery. Since JQuery uses the dollar sign and that this one is not known by TypeScript, it will cause problem. We need to shim the JavaScript library to let know to TypeScript about the JavaScript. To do, we need another npm package called “typings”. To use Typings, we will need to invoke Typings, hence we need to make sure we can execute node_modules executable so we need to make the node_modules (global one or the project one) in your path.

System Path to add :  %AppData%\npm\node_modules

Once it’s done, download from npm typings, and execute the command to get the TypeScript definition file for JQuery.

npm install typings -g
typings install jquery --save --global

Next step, is to change TypeScript to be aware of the definition file. This is done by adding an entry at the index.d.ts file at the root of typings. This file contains the triple slashes that was required to be added in all TypeScript file before. Not, you can have TypeScript compiler option to handle it for you, hence keeping all your files cleaner. The TypeScript configuration looks like below. Notice the files property.

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "module": "amd",
    "outDir": "./output"
  },
  "include": [
      "src/**/*"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ],
  "files": [
    "typings/index.d.ts"
  ]
}

The file structures should look like:

The index.d.ts contains a link to the JQuery’s index.d.ts:

/// <reference path="globals/jquery/index.d.ts" />

Finally, let’s change the fileToInclude.ts to use JQuery:

export class ClassA {
    public method1(): void
    {
        console.log("ClassA>method1");
        let div = $("<div>");
        div.html("From JQuery");
        $("body").append(div);
    }
}

At this point, we have TypeScript compiling by simply typing “tsc” in the root of our project. TypeScript with Intellisense on a library not made with TypeScript (JQuery), and a file importing a second one (File1.ts->fileToInclude.ts). There is still two problems. The first one concern the location of JQuery which is inside the node_modules. The second one is that we are not running any web server for developing, hence cannot test the execution of what we are developing.

Concerning the first problem, having to move files, Gulp will help. Gulp mains goal is to automate tasks. It’s like MsBuild if you are from .Net ecosystem. Why we do not want to have a direct reference of the node_modules? Because most of the files in this directory won’t be needed in your website, so we won’t copy all those files in the deployment. A good pattern is to bring the library we need to use for the script, like JQuery, into a separated folder. In our case, we called that folder “vendors” where all third-party library will get referenced. That is why, we will create in the build task a sub-task to move JQuery into vendor folder. Then, we will tell requirejs to look into that folder every time we need JQuery. We will see in a future article more detail about how to work with Gulp.

Edit

You do not need to use Typing. You can use the gulp package @types/jquery and remove any dependency in tsconfig.json in files of index.d.ts. You need to be sure to have a reference into the types attribute of tsconfig.json.

npm install @types/jquery --save-dev
{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "module": "amd",
    "outDir": "./deploy/output",
    "types": [
      "jquery"
    ]
  },
  "include": [
    "app/scripts/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

nDepend 2017 New Features

I have been a fan of nDepend since many years now. nDepend is a tool that run in parallel of Visual Studio as well as in Visual Studio. Fully compatible from early version up to Visual Studio 2017. The role of nDepend is to improve your code quality and the newest version step up the game by having few new features. The three main new features are the called “Smart Technical Debt Estimation”, “Quality Gates” and “Issues Management”. In this post, I will focus on the first one “Smart Technical Debt Estimation”.

The feature goal is to give a number in term of cost. It also give grade to your code as well as an estimate effort in time to improve that rating. Everything is configurable for your preference.

First of all, if you are coming from nDepend version 6, when opening your old project with nDepend version 2017 you will get a notification. About dept not configured. You just need to click on it and you will get a message that will guide you on this new feature.

From there, you will get a first rating.

From here, you can click the rating, the effort or any numbers to get an idea how to improve. But before going too deep, you better configure your setting. For example, I ran this project on a project that I am phasing out where I’ll work about 1.5 hours for the next year per day. This can be configure!

Indeed, reducing the number of hour per day and running a new analysis, plunged the rating down in my case.

That said, the rating is meaningful if you have configured the rules to be along with what you believe to be a dept which mean that you have to setup the rules to fit your needs. For me, I never really modified the default values, always browsed the results and skipped those that wasn’t important for me. With this new feature, I am more encouraged to make the rule more like I want. For example, I do not mind about long method name, in fact, I like them.

I’ll post in few weeks the result of tweaking some rules, adjusting the code and so on. This is not an easy tasks, because it cannot be just changed blindly. Some private method that doesn’t seem to be used might be called by Entity Framework, some attribute classes may seem to be great sealed but they are also inherited by other classes. This is also true for other rules like static methods that can be converted, sometime it has some side effects. So far many features of this new version of nDepend seem promising. Not only for Visual Studio, but now with the integration to VSTS (Visual Studio Online) that can be used on each of your build.

Visual Studio Code with NPM and TypeScript (Part 1 : NPM)

Creating a new project that use TypeScript with Visual Studio code can be not as straight forward as expected. A quick search on the web shows dozen of different ways and none of them are the same. Most current example are out of date or use so many npm packages that it’s hard to follow for people coming from full blown IDE and framework. This article goal is to present the simplest possible way to have a TypeScript project up and running. Even if we want to be very simple, a lot of technologies will be required. We will try to use the minimum.

Before getting started, you need to have NodeJs. This is a requirement because we will use npm. Right there, you may wonder what these two words means. NodeJs is needed to use npm which is the biggest JavaScript libraries repository. For the simplicity of this article, see NodeJs as a system that allows you to run tools and npm is one of the tool. See npm like NuGet for .Net ecosystem, but this time for JavaScript. Installing NodeJs can be done directly on the website : https://nodejs.org/en/download/

Using npm needs to use Powershell or a command line. But before, let’s create a new directory where we will host the project and initialize npm.

mkdir tsWithCode1
npm init

The npm command creates a package.json file where information about which packages is needed. See this as a cart of library that you need and that later we will download and install. For your project, we want to use TypeScript, JQuery and Gulp. The first one is the TypeScript library, the second is a popular library that is not written in TypeScript and the third one is a task runner. We will go in more detail soon, just keep in mind that they are 3 different libraries that needs to be handle differently. One different is that TypeScript and Gulp are used at development time, while JQuery is needed in development and in production. We need to install differently because of this difference since we do not want to have libraries not needed in production.

npm install --save-dev typescript
npm install --save-dev gulp
npm install --save jquery

The output should have the init parameters provided (name, description, etc) and two sections.

{
  "name": "tswithcode1",
  "version": "1.0.0",
  "description": "TypeScript with NPM and VSCODE",
  "main": "index.js",
  "scripts": {
    "test": "test"
  },
  "author": "Patrick Desjardins",
  "license": "ISC",
  "devDependencies": {
    "gulp": "^3.9.1",
    "typescript": "^2.1.5"
  },
  "dependencies": {
    "jquery": "^3.1.1"
  }
}

At this point, you can look in your directory and see a new one generated named “node_modules”. This folder doesn’t need to be in your source control since you can simply invoke “npm install” in the directory to get the folder back with all the libraries. When using the install command, NPM looks in the package.json configuration file and get what needed. I suggest that you delete the “node_modules” and try the command. But before doing so, look at how many folder contains the “node_module”. At the time I am writing this article, the number if 162. The count is way more than just 3 (TypeScript, Gulp and JQuery) because each of these libraries have dependencies on other libraries that also have dependencies and so on. Since it’s an introduction article, I won’t go in too much detail, but it’s possible to install package globally in your computer (%AppData%\npm\node_modules). If you are developing several projects, you may want to install common utility tools globally, like TypeScript or Gulp. The advantage is that you avoid having in all project the same files, hence saving disk space.

Before going to the next article that will setup the HTML file and create the first TypeScript file, let’s add an additional library: requirejs. This library will be used to handle TypeScript module that we will see soon.

npm install --save requirejs

How to use Visual Studio 2015 with ASP.NET MVC5 and TypeScript 2.1+

TypeScript is a wonderful language for front-end developing. It helps by make front-end code feels like C#. At the end you compile the TypeScript code in JavaScript like if you had do without TypeScript. The first step is to setup Visual Studio to use TypeScript. On the official website, there is instruction for Asp.Net MVC4 which doesn’t work very smoothly with MVC5 and the latest version of TypeScript. In fact, following those instructions will lead you into a compilation problem that would tell you that VSTSC doesn’t exist. In this article, I’ll show you the quickest way to use TypeScript.

The first step is to download the latest version of TypeScript. This will install TypeScript in Program Files (C:\Program Files (x86)\Microsoft SDKs\TypeScript). Be aware that you may already have some older version of TypeScript (like 1.6 and 1.8) but you want to have 2.1.

Installing TypeScript should take about 3 minutes. Once it’s done, you need to add a tsconfig.json file at the root of your project. This second step add a file that gives configuration to TypeScript. For example, where to take the TypeScript and where to output the JavaScript result. Here is an example:

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "outDir": "./Scripts/App"
  },
  "files": [
    "./src/app.ts"
  ]
}

That said to take the file app.ts from the src folder and create the corresponding JavaScript in the outDir. In this example, we take the file in /src/ and output the result in /Scripts/App/ which is the default JavaScript folder in Asp.Net MVC. It could have been any other folder as long as in your .cshtml you refer to this one. That said, we need to change the .cshtml where we want to consume the JavaScript. We need to add the script tag like we would do normally.

<script src="~/Scripts/App/app.js"></script>

Before going any further, let’s talk about the tsconfig.json. The option are very basic, the first one indicate that we want sourcemap which allow you to debug directly the TypeScript file instead of the JavaScript. The second parameter is the target. It indicates in which version of JavaScript (EcmaScript) to output. The third one if where to save the JavaScript files compiled. Files is the input.

From here, you just need to have a TypeScript file called app.ts and write some code. Do as normally with C#, go in Visual Studio’s menu under Build and do Build Solution. This will output JavaScript. You may not see the output file if you do not have “Show all Files” selected in the Solution Explorer.

At that point, you may ask yourself that it sounds cumbersome to manually add files if the project is big. This is why you can change the tsconfig.json to compile all TypeScript file of specific folders.

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "outDir": "./Scripts/App"
  },
  "include": [
        "src/**/*"
    ]
}

This will go through all .ts, .tsx, and .d.ts file and generate the right JavaScript.

You may fall into the problem that while writing your TypeScript that Visual Studio 2015 tells you that you are using a version different from the version specified in the tsconfig.ts.

This come with the problem of having the .csproject having the TypeScript options being disabled saying that two tsconfig.json exist.

The problem is that Visual Studio is having TypeScript configuration directly into the .csproj file. You can open with a text editor the .csproj and search for TypeScript.

There is two options here. The first one is to remove the tsconfig.json file and configure from Visual Studio project property. However, you will be limited in term of options. The second is to remove all TypeScript entries inside the .csproject and keep the tsconfig.json. You may have to restart Visual Studio to have Intellisense to work again.

How to use multiple TypeScript files

TypeScript allows you to use EcmaScript import syntax to bring code from another file, or multiple files. This is very useful if you do not want to have all your code into a single file, or if you want to reuse code in different files.

For example, let’s have 2 files. app.ts and fileToInclude.ts which will contain a class that we want to use in App.ts.

//app.ts content:
import { ClassA } from "fileToInclude"

const a = new ClassA();
a.method1();

//fileToInclude.ts content:
export class ClassA {
    public method1(): void
    {
        console.log("ClassA>method1");
    }
}

As you can see, the way to import a class is to specify the class name and from which file to import it. On the other side, the class that you want to import must be marked as export to be imported. The export and import are not TypeScript specific, but something EcmaScript version 6 allows you to use instead of using a custom AMD loader library like Require.js.

So while this is supported since EcmaScript 6, some browser doesn’t support this feature. However, with TypeScript, you can style use EcmaScript, except for module loading. So, if you compile using EcmaScript and go to Chrome you will end up with an unexpected error if you do not.

Uncaught SyntaxError: Unexpected token import

By changing the target of the tsconfig.json to use a module loader the generated code will be using the module loader syntax instead of the EcmaScript syntax. A popular one is Require.js. to do so, the tsconfig.json file needs to have a module entry.

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es6",
    "module": "amd",
    "outDir": "./Scripts/App"
  },
  "include": [
        "src/**/*"
    ]
}

Without specifyin the module, the code generated was:

import { ClassA } from "./fileToInclude";
const a = new ClassA();
a.method1();

With the module to AMD, this will output a JavaScript that will wrap the module with require. For example:

define(["require", "exports", "./fileToInclude"], function (require, exports, fileToInclude_1) {
    "use strict";
    var a = new fileToInclude_1.ClassA();
    a.method1();
});

Finally, you cannot call directly the .js file in the .cshtml. Instead, we need to use the script tag with a src to requirejs and call a specific method to indicate which module to load (which file).

<script src="~/Scripts/require.js"></script>
<script>
    requirejs.config({
        baseUrl: '/Scripts/App/'
    });
    requirejs(['app']);
</script>

In our case, we want to execute app.js, so we write “app” without the extension “.js”. However, before doing so, we need to setup require requirejs to know that the root of all JavaScript file are located into the Script folder.

JavaScript Navigation Performance Understanding with Application Insights

Application Insights has a table with performance details. It’s called “browser timings”. You can have a glimpse of what it contains by executing

browserTimings
| where timestamp >= ago(1d)
| where totalDuration  > 10000
| order by totalDuration desc nulls last 

The most interesting columns are these following four:

  • networkDuration
  • sendDuration
  • receiveDuration
  • processingDuration

To understand what it means, you can look at Azure Application Insights documentation. It has a good image (https://docs.microsoft.com/en-us/azure/application-insights/media/app-insights-javascript/08-client-split.png), in short, Application Insights is categorizing the official processing model from the navigation timing. Nine steps is heavy and some steps are not directly the cause of the code. The segregation in 4 categories help to focus of where you should spend your time to fix your performance issue.

Reading the navigation timing can be confusing in term of what needs to be improved. Most of the time, you do not need to understand every step to improve the overall performance.

The first interesting column of the browsertiming table is networkDuration. This column includes 4 of the navigation timing processing step that include mostly the network call. It includes redirection, if the fetched resource result is an HTTP redirect (3xx). It also has DNS and TCP delays. What it means is that it contains all the time before users reach the Asp.Net code. It’s the time to translate the domain into an IP address, the time between different hops that separate the user and the machine that host the HTTP server and the time the http request move from the machine to the HTTP server (IIS, Apache, etc). This time tend to be huge if the HTTP server is sleeping. For example, if you release a new version on Azure Website and do not warm the server, the first hit will be slow. This will translate in Application Insights by having the networkDuration higher than usual. That is why, it’s always good to remove from the statistic very high time, let say 1 minute. That said, I currently experience very long query above 5 minutes from GoogleBot that need to be investigated.

browserTimings
| where timestamp >= ago(12d)
| where totalDuration  < 300000
| where networkDuration  < 10000
| order by totalDuration desc nulls last 

The second column is sendDuration. The starting point is when the browser starts sending the first byte, the ending point the server sent the first byte back to the browser. In other word, it is when the browser receives the whole response from the HTTP server. In other words, it’s the time spent in your Asp.Net MVC controller. If you want to isolate long request to identifier Asp.Net MVC Controller’s action problem, you can change the Application Insight query to order by the sendDuration and find all every duration above 2 seconds (or what ever is your desired maximum time on the server).

browserTimings
| where timestamp >= ago(12d)
| where totalDuration  < 300000
| where networkDuration  < 10000
| where sendDuration > 2000
| where url !startswith "http://localhost"
| where url !contains "azurewebsites.net"  
| order by sendDuration desc nulls last 
| project timestamp , url, sendDuration

While exploring the data, I realized that I was sending development localhost into Application Insights. Only on for the client side since the code was injected and didn’t take in consideration the C# flag “TelemetryConfiguration.Active.DisableTelemetry”. That is why you can a new clause that get rid of any development requests. Also, I am using multiple Azure’s slots which mean I want to remove the experimental slot too by removing “azurewebsites.net” from the data.

browserTimings
| where timestamp >= ago(12d)
| where totalDuration  < 300000
| where networkDuration  < 10000
| where sendDuration > 2000
| where url !startswith "http://localhost"
| where url !contains "azurewebsites.net"  
| order by sendDuration desc nulls last 
| extend urlWithoutNumber =  replace(@"([^?]+).*", @"\1", replace(@"([a-z0-9]{8})\-([a-z0-9]{4})\-([a-z0-9]{4})\-([a-z0-9]{4})\-([a-z0-9]){12}", @"x", replace(@"(\d)", @"x", url)))
| project timestamp , urlWithoutNumber, sendDuration

The third column is the receiveDuration which is the time it tooks to download the data from the server. This can be long if you send a big HTML back for example. You can lower this metric by having a single page application where most request download only the data and not UI details. This metric is important to keep low especially on mobile where the connection is slow and users have limited data plan.

The last and forth column is the processingDuration. This is the time it takes for the browser to render the received data. It contains several JavaScript events. domLoading, domInteractive, domContentLoaded (JQuery DocumentReady), domComplete, loadEventStart and loadEventEnd. Quick recaps of these rendering events.

  • domLoading: The document has been downloaded from the server, the browser is ready to work on it.
  • domInteractive: The browser parsed the HTML and built the DOM.
  • domContentLoaded: The CSSOM is built (browser analyzed CSS). Browsers is not blocked by any JavaScript.
  • domComplete: The browser doesn’t have anymore images or any resource to download.
  • loadEventStart and loadEventEnd: Browser rendered the DOM to the user.

It means that you can reduce the processingDuration by having simpler CSS and faster JavaScript code. You can get this information in Application Insights by showing the percentiles of the processingDuration. I added some filtering to reduce the amount of result.

browserTimings
| where timestamp >= ago(7d)
| where networkDuration < 5000
| where totalDuration > 5000
| where url !startswith("http://localhost")
| where url !contains("azurewebsites.net")
| extend urlClean = replace(@"([^?]+).*", @"\1", replace(@"([a-z0-9]{8})\-([a-z0-9]{4})\-([a-z0-9]{4})\-([a-z0-9]{4})\-([a-z0-9]){12}", @"x", replace(@"(\d)", @"x", url)))
| summarize 
      percentiles(processingDuration, 50, 95) 
    , percentiles(totalDuration, 50, 95) 
    by urlClean
| where percentile_processingDuration_50 > 2000
| order by percentile_processingDuration_50 desc nulls last 

It’s good to note that some external libraries can increase the processingDuration. This is especially true with Google Adsense or third party that download CSS/Font/Script and execute them on your page.

Application Insights BrowserTimings is very useful to get insight of what is going on on your webpage in term of performance and figure out where to optimize your code. To conclude, here is a recapitulative of the 4 mains property of the Application Insights BrowserTimings.

  • networkDuration = Contact the server, can be slow if you just deployed (on the first hit).
  • sendDuration = Time on the server (Asp.Net Controller code).
  • receiveDuration = Time for the browser to download the data from the server.
  • processingDuration = Time for the browser to draw the downloaded data to the UI for the user to see it.