File bundling with Gulp

As the project is moving forward there are new files appearing. There are few javascript files now, and I know there are going to be more to come. This is bit of an issue – more files mean more requests to server, which directly causes slower loading time. Browsers can only do so many concurrent requests, if you will require more files than browser limit, you will have to wait for previous request to complete. On server it is also more stressing to serve dozen requests for different files than to give one file and be done with it.

With Visual Studio 2015 comes built in support for task running. There are few task systems available, most popular being Grunt and Gulp. They support various javascript written tasks and you can always write your own one, doing what you need. They may be used for anything, but I will get them to do bundling for me.

Bundling is process of merging multiple files into one resource, that can then be used on page. In my case I want to get all my javascript files bundled, but css can also be merged if you want. I’ve picked Gulp as my poison of choice.

First thing that has to be done is to create packages.json file – Visual studio has template file to support that. Second – gulpfile.js – in this file I will be defining my tasks, gulp automatically looks for this file for list of tasks. So does task runner explorer (you can turn its window on in View-Other Windows-Task Runner Explorer, or by pressign Ctrl+Alt+Backspace).

What I need is some task definitions downloaded by npm – node js package manager. To do this I write what I need in packages.json

{
    "version": "1.0.0",
    "name": "ASP.NET",
    "private": true,
  "devDependencies": {
    "gulp": "3.9.1",
    "gulp-concat": "2.6.0",
    "gulp-concat-css": "2.2.0",
    "del": "2.2.0"
  }
}

DevDependencies is the section of interest here. I will be using gulp to run tasks, gulp-concat for javascript files and del for removing unnecessary files. You can right on this file in Solution Explorer and restore packages. They will appear in node_modules directory.

Now it is time to write some tasks in gulp. First – it needs to import required tasks (the ones that were references through packages.json):

var gulp = require('gulp');
var concat = require('gulp-concat');
var concatCss = require('gulp-concat-css');
var del = require('del');

And after that tasks can be defined:

var bundlesOutputDir = "Bundles";

var bundles = [
    { scripts: ["Content/raim.js", "Content/PlayersList.js"], output: "raim_main.js"}
];

gulp.task('clean', function () {
    del(bundlesOutputDir + '/*');
});

gulp.task('bundling', function () {
    bundles.forEach(function (bundle) {
        gulp.src(bundle.scripts)
            .pipe(concat(bundle.output))
            .pipe(gulp.dest(bundlesOutputDir));
    });
});

Those are pretty basic. clean goes to defined output directory for bundles and removes all the files. bundling on the other hand iterates over my array of bundles I want to create (which at the moment only holds one thing), loads those files (or marks them as files to process), pipes (forwards) them to concat task, which handles merging files and creates new file with name passed as parameter. This newly created file is then piped to gulp.dest task, which outputs it to target directory.

When ran from task explorer it sure does create raim_main.js file in Bundles directory!

But bundling by hand is not what I want to do. This should be done automatically, each time I change any file. I want to have them ready for use the second I stop writing them. For this, gulp.watch is perfect:

gulp.task("watch", function () {
    bundles.forEach(function (bundle) {
        gulp.watch(bundle.scripts, ['clean', 'bundling']);
    });
});

gulp.task('default', ['clean', 'bundling', 'watch']);

Again, going through all bundles, I mark those files for watch process and each time any of those files change I want to trigger clean task and later bundling. Additionally, default task is created to run those tasks automatically when gulp is ran as parameter (e.g. from console or during build process on CI machine).

Triggering default task prepares working space for me, old bundles removed, new ones created and watch configured.

But what about newly cloned repository, if someone downloads it? Or if I restart visual studio – I don’t want to have to go to task explorer and trigger those tasks. Thankfully Visual Studio supports biding tasks to few events in VS, one of those being – project opened. It is done simply by providing special structure in comment at top of the file:

/// <binding ProjectOpened='default' />

There can be comma separated list of tasks to run on start, but I just need one at the moment. This way if I unload the project, kill task running in background, and reload main project again – default tasks kicks in automatically, preparing workspace. Neat!

What is left is to reference the bundle from html file:

<a href="http://../Bundles/raim_main.js">http://../Bundles/raim_main.js</a>

And it should be… wait – no. Scripts are in Bundles directory, but Nancy wont be serving those files. What it needs is some configuration to tell it there is static content there. One line in Bootstrap file:

nancyConventions.StaticContentsConventions.AddDirectory("Bundles");

And only now all is running smoothly.

List of players and security

Since the player registered and other players got his name back, it would be useful to show it to them. I imagine it can be useful to have list of players (or at least subset of them, leaderbord or something?) available. All the data is readily available so I threw a div onto page and wrote this great piece of code:

raim.client.registered = function (who) {
    var players = document.getElementById('playersList');
    var playerNameElement = document.createElement('span');
    playerNameElement.textContent = who;
    players.appendChild(playerNameElement);
};

Notice I try not to use jQuery. I want to see how far I can get without it (of course it is still there, SignalR depends on it), but mainly – I am a bit curious how far did browsers get with supporting the same flavour of javascript everywhere, how many differences are still there. How did they upped the game – now that javascript is only getting more popular. Also performance might be a reason to ditch jQuery, but I think I am very far from it – but if that was advanced game, I imagine going closer to the metal gives one more opportunities to optimize everything.

Next thing to notice is document.createElement. I’ve seen a lot of times when developers just modify innerHtml of an element. Append to the string, throw in few variables here and there. Heck – I’ve done it myself so many times. Not a good practice, that’s for sure. Hard to maintain, easy to throw in few bugs (unclosed elements). Why not depend on browser to manage DOM tree correctly – I can only assume it is extremely good at it. So I’ll let it create my element and append it to the list of elements already in the list.
And also I would expect it to perform better in some conditions, like when there are already quite a few elements – modifying innerHtml text will throw all those elements away and create new one, basically recreating whole tree node. Appending new element in the end will preserve all existing nodes and just throw a new one to the end.

And now spot the mistake. It is there, and it is big. Got it?

If the innerHtml is modified, content gets injected into page. And what if the player’s name is, by some coincidence <img src="x">? Try it in browser’s console window, modifying innerHtml. And if that wasn’t just harmless alert window? Let me just remind you of link. It wasn’t yet decided whether humanity is great or, well, not quite so good at all. So why take the risk? Also – always sanitize users’ inputs!

public void Register(string name)
{
    name = HttpUtility.HtmlEncode(name);
    ...
}

Setting up SignalR with Nancy

Time to connect client to server. After all it is supposed to be interactive game with many clients. SignalR seems to be interesting library that should be able to do what I need.

SignalR is from Microsoft, integrates with ASP.NET easily, but can also be used in other technologies. Cool stuff, I tell you. If you will look at the setup in docs, there are few steps only. First of those – install ASP.NET SignalR. Few minutes (seconds if you’re lucky) and we have it.

Second – in Startup map SignalR.

public void Configuration(IAppBuilder builder)
{
    ...
    builder.MapSignalR();
}

Bootstrapper needs to be created to configure Nancy so it servers javascript files as static content.

public class Bootstrapper : DefaultNancyBootstrapper
{
    protected override void ConfigureConventions(NancyConventions nancyConventions)
    {
        base.ConfigureConventions(nancyConventions);
        nancyConventions.StaticContentsConventions.AddDirectory("Scripts");
    }
}

And a little modification for index.html

<a href="http://../Scripts/jquery-2.2.1.min.js">http://../Scripts/jquery-2.2.1.min.js</a>
<a href="http://../Scripts/jquery.signalR-2.2.0.min.js">http://../Scripts/jquery.signalR-2.2.0.min.js</a>
<a href="http://../signalr/hubs">http://../signalr/hubs</a>

All very simple. We need jQuery (updated to latest version, SignalR by default uses 1.6 at the moment). We need SignalR. Third script calls to server to hubs. There is no script for that in my code – that’s internally handled by SignalR.

I pressed F5 to see if all is OK. And to my surprise i got 404 for the last script. Well, alright, I must’ve made some mistakes along the way. Checked once and twice. Found nothing worth fixing. So it must be something else – SignalR mapping must be broken. For some reason system does not recognize /signalr/hubs path.

Since I’m using Nancy, I guessed that it is probably something with it and SignalR not working very well. Well – the latter is MS product, built using MS stack and it works there from the get go.

Quick search on google and I found link app doing what I wanted – real time communication client to server with SignalR. Without going deep into code (it is simple and short though) I could notice some differences. First – there is no UseNancy registration in Startup, but it is replaced with web.config setup:

<httpHandlers>
  <add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
</httpHandlers>

OK, interesting. Tried that in my app, not expecting much. To my surprise – app started failing, saying it cannot find Nancy.Hosting.Aspnet.NancyHttpRequestHandler. Looking at the project references I knew there most be something missing. In fact – I found one difference. Default Nancy instalation uses Nancy.Owin assembly reference, however SignalR sample uses Nancy.Hosting.Aspnet. So next thing to try was – remove former, install latter. At this point Startup failed to compile due to missing UseNancy. But since it is configured in configuration file – there is no need for it.

F5 again. And all is perfect. All javascript loaded, signalr/hubs also loads without any errors. Perfect! Next time connecting to server and making sure all is in place.

Deliver static page content with Nancy

Time to server some content with Nancy. That is straightforward, and a bit like MS MVC.

Get["/"] = parameters => View["Index.html"];

And this will serve my HTML. But just a page is not enough – there is always a need for more. CSS? JavaScript? Maybe some images if you feel fancy enough? Thankfully Nancy comes with built-in convention that covers this for us (at least for basic usage; then again I don’t need much at the moment, do I?). As they kindly put in their documentation:

TL;DR: stick stuff in /Content .. done.

Wouldn’t write it better myself ;) New dir; new stylesheet; link it to index page. Done! Just do hard refresh (Ctrl+R in Chrome) to avoid browser cashing and I have my page looking nicely.

Tip of a day – in Chrome, go to developer tools (F12), there switch to Network tab and mark Disable cache checkbox – this way browser will always load all the resources from the server, avoiding cache. This will be done only when dev tools are open so your day-to-day browsing speed will not be impacted. Same goes for FireFox and IE – saves you some nerves when trying to figure out why those damn css aren’t working (assuming they are working at all, I’m looking at you, you damn css!).

ToDo at some point I will probably need to move onto something better than plain css to simplify style management. Few years back I had brief encounter with Less, but seems to me like Sass is all the rage now. But that’s for future – at this point there is no need for big guns.

Nancy in Class Library

I’m just starting new project (https://github.com/pako1337/raim) and thought about doing it in different technology stack, not usual ASP.NET MVC I’m used to at work. I chose Nancy FX for the moment, and later it should be joined by SignalR. Nothing fancy for now, but I don’t need much at this stage.

Setting up Nancy is pretty straightforward, all instructions are available on web (https://github.com/NancyFx/Nancy/wiki/Hosting-nancy-with-owin) and it is just few steps to having Nancy module and returning hello world string. What I want to do differently is – I don’t want to use ASP.NET project. I always use it and never bothered to see what’s inside of it. It started bothering me some time ago that I have no idea how is it different to normal class library.

First thing first, I have set up new solution and createn new, empty project. In Visual Studio for some reason empty projects are not empty at all – there are bunch of dependencies already included – basic stuff. And there is useless Class1.cs – straight to bin with it!

Next nuget and installing few packages: Nancy, Nancy.Owin and Microsoft.Owin.Host.SystemWeb (which depends on Microsoft.Owin). Easy-peasy. Since we are doing Owin, Startup.cs is nice to have, important to put it in the same namespace as project’s default one, otherwise it needs assembly attribute to point to it – but why make life harder if there is nice convention.

    public class Startup
    {
        public void Configration(IAppBuilder builder)
        {
            builder.UseNancy();
        }
    }

It doesn’t get much easier than that. Owin set up (at the minimum, but still). Now it is time for Nancy module that will handle our requests.

    public class HomeModule : NancyModule
    {
        public HomeModule()
        {
            Get["/"] = parameters => "Welcome to Raim!";
        }
    }

Also as simple as it gets. When you get request to application with no parameters and nothing at all in request’s path – call this anonymous method to return string. not quite HTML – but will let us know if all is set up. F5 and here we… wait, what? Class library cannot be started directly? Well, yea, Visual Studio won’t run class libraries at all.

At first I was sure that it has to be some simple thing. Setting somewhere to tell it it can be started directly, connected to IIS Express (I want it to be my dev server). Looked through properties and found exactly nothing. My google-fu was useless as well. First few pages were of no use, guess no one is doing this the hard way!

My next idea was – create ASP.NET project, diff csproj files and find differences. Did that. At first I noticed nothing strange – few additional references, some files and directories I didn’t have. Nothing strange. Then I noticed one line that seemed interesting – entry. And two Guids in it. Decided to copy it over to my csproj (need to use editor outside of VS to do that; or you have to unload the project, edit the file manualy and then reload it). And what do you know – works like a charm! Maybe that is some common knowledge, but I happened to never stumble upon it in my few years as software dev.

...
<Project>
    <PropertyGroup>
        <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
        ...

What is left is double check IIS settings, F5 – yes, please add web.config file, thank you – 403.14 – Forbidden! But why? Shouldn’t it be working? Took me a while to realise what is wrong – and I feel silly now, knowing that – project was building into /bin/Debug directory, while IIS was looking into /bin directly. Of course it does, it always did, fool of a Took! Quick change in settings and finally – “Welcome to Raim!” appears on my screen!

Nothing extra fancy yet, but hey! At least now I know that how VS differentiate between web application, console application and simple class library.

NancyFx is a way to go

Another quickie. I wrote tiny domain for fun. Now I wanted to write some UI (HTML) code and api to access domain. First I was thinking about standard .NET WebService, but at Twitter I’ve stumbled at NancyFx. Took me about 5 minutes from this twit to having Nancy deployed in my solution, configured and returning test value. And it’s awesome. No more over complicated configuration. No more web.config modifications just to make some things work. For simple things at least Nancy seems great choice. Hope it will keep surprising me in positive way over and over again!