Running BabelJS/ES2015 Apps in Azure App Service

BabelJS is a really cool in-line transpiler. You can use it as a ‘require-hook’ to make your Node.js apps use the full ES6 syntax without the v8 javascript interpreter issues around ES6 support. For instance, I have a server.js file that looks like this:

require('babel-register');
require('./app');

My app.js file contains regular ES6 code, like this:

import express from 'express';
import process from 'process';
import staticFiles from 'serve-static';

let app = express();
app.use(staticFiles('public', { index: 'index.html' }));
app.listen(process.env.PORT || 3000);

I’ve also got a public directory and an index.html file inside the public directory for display. Finally, I need a .babelrc file:

{
    "presets": [ "es2015" ]
}

Assuming I’ve installed all the right packages:

npm install --save babel-register babel-preset-es2015 express serve-static

This will run and I’ll be able to browse to http://localhost:3000 and get my index page. It just works. Which is a great thing. Now, let’s transfer it up to the cloud. Azure App Service to be precise.

To do this, I logged onto the Azure Portal, created a new Web App and set up Continuous Deployment to read my site from the GitHub repository. When it deployed, I got a successful deployment. However, when I browsed to my site, I got a failure. The failure in the logs was this:

Mon Dec 28 2015 22:36:55 GMT+0000 (Coordinated Universal Time): Unaught exception: Error: ENOENT: no such file or directory, open 'D:\local\UserProfile\.babel.json'
    at Error (native)
    at Object.fs.openSync (fs.js:584:18)
    at Object.fs.writeFileSync (fs.js:1224:33)
    at save (D:\home\site\wwwroot\node_modules\babel-register\lib\cache.js:45:19)
    at nextTickCallbackWith0Args (node.js:433:9)
    at process._tickCallback (node.js:362:13)
    at Function.Module.runMain (module.js:432:11)
    at startup (node.js:141:18)
    at node.js:980:3

I don’t even have this .babel.json file, so what’s wrong? By default, BabelJS will save a cache file in your user profile. This is fine if you are running in the context of a user account – user accounts generally have a home directory or user profile.

BabelJS saves the JSON Cache in the following places:

  • BABEL_CACHE_PATH
  • USERPROFILE
  • HOMEDRIVE + HOMEPATH
  • HOME

You can also set BABEL_DISABLE_CACHE=1 to disable the generation of this file. Since the existence of this file improves startup times (and Azure does restart your site from time to time), you probably want to keep the file.

These are all environment variables. In Azure, USERPROFILE points to a directory that does not exist – there is no user in Azure. My opinion is that it should point to the temporary directory or not be set. Azure has a temporary directory at D:\local\Temp. We can force BabelJS to write to the temporary directory by specify an App Setting. To do this:

  1. Log onto the Azure Portal and select your Web App.
  2. Click on Settings, then Application Settings (under GENERAL).
  3. Scroll down to the bottom of the App settings section.
  4. In an empty box, for key, enter BABEL_CACHE_PATH and for value, enter D:\local\Temp\babel.json
  5. Click on Save.

You application may need a restart. Once restarted, browse to your site again and see it work properly. With this app setting, your site will work for both local development and within the Azure cloud.

Browser Testing with PhantomJS and Mocha – Part 1

If you have been following along for the past couple of weeks, you will know that I’ve been writing a browser library recently. I’m writing the library in ES2015 and then transpiling it into UMD.

A sidebar on bugs in BabelJS
I did bump into a bug when transpiling into the UMD module format. The bug is pretty much across the module transforms, and manifests as a ‘Maximum Call Stack Exceeded’ error with _typeof. The bug is T6777. There is a workaround, which is to add a typeof undefined; line at the top of your library.

Back to the problem at hand. I’ve already used Mocha to test my library and I use mocks to attempt to exercise the code, but at some point you have to run it in a browser. There are two steps to this. The first is to set up a test system that runs in a browser, and the second is to run the test system through a headless browser so it can be automated. Let’s tackle the first step today.

My library is a client library to access a remote AJAX environment. I want the library to use either a provided URL or the URL the page was loaded from – whichever is appropriate. As a result, I need to load the files over the Internet – loading from a file:// URL isn’t good enough. To handle this, I’m going to:

  • Create a local test server
  • Load the files into a static service area
  • Run the pages in a browser

To this end, I’ve got a Gulp task that builds my server:

var gulp = require('gulp'),
    babel = require('gulp-babel'),
    concat = require('gulp-concat'),
    sourcemaps = require('gulp-sourcemaps'),
    config = require('../configuration');

module.exports = exports = function() {
    return gulp.src(config.source.files)
        .pipe(sourcemaps.init())
        .pipe(concat('MyLibrary.js'))
        .pipe(babel())
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(config.destination.directory));
};

I store my gulp tasks in a separate file – one file per task. I then require the file in the main Gulpfile.js:

var gulp = require('gulp');

gulp.task('build', require('./gulp/tasks/build'));

I now have a MyLibrary.js file and a MyLibrary.js.map file in the dist directory. Building the server area is just as easy:

var gulp = require('gulp'),
    config = require('../configuration');

// Builds the server.rootdir up to service test files
module.exports = exports = function() {
    return gulp.src(config.test.server.files)
        .pipe(gulp.dest(config.test.server.rootdir));
};

My configuration.js exposes a list of files like this:

module.exports = exports = {
    source: {
        files: [ 'src/**/*.js' ]
    },
    destination: {
        directory: 'dist'
    },
    test: {
        mocha: [ 'test/**/*.js' ],
        server: {
            files: [
                'browser-tests/global.html',
                'browser-tests/global-tests.js',
                'dist/MyLibrary.js',
                'dist/MyLibrary.js.map',
                'node_modules/chai/chai.js',
                'node_modules/mocha/mocha.css',
                'node_modules/mocha/mocha.js'
            ],
            port: 3000,
            rootdir: 'www'
        }
    }
};

Take a look at the test.server.files object. That contains three distinct sections – the browser test files (more on those in a moment), the library files under test and the testing libraries. You should already have these installed, but if you don’t, you can install them:

npm install --save-dev mocha chai

I will have a www directory with all the files I need in it once I run the gulp buildserver command. Next, I need a server. I use ExpressJS for this. First off, install ExpressJS:

npm install --save-dev express

Note that this is a dev install – not a production install, hence the use of the --save-dev tag. I want express listed in devDependencies. Now, on to the server code, which I place in testserver.js:

var express = require('express'),
    config = require('./gulp/configuration');

var app = express();
app.use(express.static(config.test.server.rootdir));
app.listen(config.test.server.port || 3000, function() {
    console.info('Listening for connections');
});

This is about the most basic configuration for an ExpressJS server you can get. I’m serving static pages from the area I’ve built. That’s enough of infrastructure – now, how about running tests? I’ve got two files in my files list that I have not written yet. The first is a test file called global-tests.js and the other is a HTML file that sets up the test run – called global.html. The global-tests.js is a pretty normal Mocha test suite:

/* global describe, it, chai, MyLibrary */
var expect = chai.expect;

describe('MyLibrary.Client - Global Browser Object', function () {
    it('should have an MyLibrary global object', function () {
        expect(MyLibrary).to.be.a('object');
    });

    it('should have an MyLibrary.Client method', function () {
        expect(MyLibrary.Client).to.be.a('function');
    });

    it('should create a Client object when run in a browser', function () {
        var client = new MyLibrary.Client();
        expect(client).to.be.an.instanceof(MyLibrary.Client);
    });

    it('should set the url appropriately', function () {
        var client = new MyLibrary.Client();
        expect(client.url).to.equal('http://localhost:3000');
    });

    it('should set the environment appropriately', function () {
        var client = new MyLibrary.Client();
        expect(client.environment).to.equal('web/globals');
    });
});

There are a couple of changes. Firstly, this code is going to run in the browser, so you must write your tests for that environment. Secondly, it expects that the test framework is established already – it expects the chai library to be pre-loaded. One other thing is that this is a minimal test load. The majority of the testing is done inside my standard Mocha test run. As long as you have your tests exercise all paths within the code across the test suites (both the standard mocha tests and the browser tests), then you will be ok. I only test things that need the browser in order to test them.

The global.html test file sets up the tests, loads the appropriate libraries and then executes the tests:

<!DOCTYPE html>
<html>

<head>
    <title>Mocha Test File: Global Library Definition</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="mocha.css">
</head>

<body>
    <div id="mocha"></div>
    <script src="mocha.js"></script>
    <script src="chai.js"></script>
    <script>
        mocha.setup('bdd');
        mocha.reporter('html');
    </script>
    <script src="MyLibrary.js"></script>
    <script src="global-tests.js"></script>
    <script>
        mocha.run();
    </script>
</body>

</html>

I’m intending on writing a test file that implements the global object version, AMD module definition and browserify to ensure that the library runs in all environments. Each environment will have it’s own HTML file and test suite file. I can include as many of these sets as I want.

Running the tests

Running the tests at this stage is a two-step process. First, you start the server:

node testserver.js

Secondly, you browse to http://localhost:3000/global.html – note the initiator for your test suite is the HTML file. If you have done everything properly, the tests will just work:

mocha-browser

If things don’t work, you can use Developer Tools to figure out what is going on and correct the problem, then re-run the tests. Since this is an ES2015 project, there are some things that may require a polyfill. You can provide your own (mine only needs a polyfill for Object.assign – a matter for a couple of dozen lines of code), or you can use a major ES2015 polyfill like core.js – just ensure you load the polyfill in your test environment. This is also a great pointer to ensure your library has the right dependencies listed and that you have documented your requirements for the browser.

In the next article (Happy New Year!) I will integrate this into automated testing so that you don’t have to open a browser to do this task.

An ECMAScript 6 Search Box (Part 2)

In my previous article I set up the basic ASP.NET environment and a build environment with gulp. I also added a couple of libraries that I will need to the build environment and made sure my wwwroot directory was built and cleaned appropriately. Today I am going to create a fully ECMAScript 6 compatible Search Box based on my prior work with RequireJS and jQuery.

The ECMAScript 6 Search Box

I’ve used a lot of the same code in this class as in my jQuery extension plugin. Let’s look at it bit by bit though. I’ve created a src/js/classes directory for my work. I’ve created a MySearchBox.js Javascript file. Somewhat surprisingly, Visual Studio understood most of my ECMAScript 6 code. Hopefully Visual Studio and Web Essentials will catch up fast and provide full ECMAScript 6 intellisense soon. Let’s start with the constructor of the class:

import * as $ from 'jquery';

// Class for implementing the Search box functionality
class MySearchBox {

    // Constructor to set up the searchbox
    constructor(pElement, pOptions = {}) {
        this.clickableElement = pElement;
        // Create an options field based on the default options overridden by the provided options
        this.options = $.extend({
            searchId: MySearchBox.generateGUID(),
            bubbleClass: 'bubble'
        }, pOptions || {});

        // Make the thing that enables the search box clickable
        pElement.css({'cursor': 'pointer'}).click({ 'options': this.options }, MySearchBox.onClick);
    }
}

The import statement at the top tells the compiler that I need jQuery to be the $ variable – this is going to be fairly normal as long as you have a need for jQuery. Next I’ve defined my class and my constructor. In a departure from my jQuery version I’m using the ES6 default parameters to allow the user to not pass in any options. I use the normal jQuery method of setting the defaults for jQuery plugins – I’ve just moved it inside the class.

A quick note about jQuery events. Just like in prior versions of my code, I am going to lose the context of the event, so I’m designating the event handler as a static block of code in the class. As I learn more ES6 and Javascript, I’m sure I’ll find a way to write this that doesn’t lose the context. For right now – this works.

I’ve got two methods to write – generateGUID() comes directly from my utils.js file and looks like this:

    // Utility function to return a GUID
    static generateGUID() {
        let d = new Date().getTime();
        
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            let r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
    }

Finally, we need the click-handler method onClick. Here i put a whole load of debugging statements in as well. One of the optimizations I can do later on is to strip out debugging statements for production. I’m more likely to leave debugging statements in with that functionality.

    // Click Handler to create or destroy the search box
    static onClick(evt) {
        let clickedElement = $(evt.currentTarget),
            options = evt.data.options,
            searchElem = $('#' + options.searchId);

        console.group("MySearchBox::onClick");
        console.info("evt = ", evt);
        console.info("clickedElement = ", clickedElement);
        console.info("searchElem = ", searchElem);

        if (searchElem.length > 0) {
            // If it's there, destroy it
            console.info("searchElem exists - removing it");
            searchElem.remove();
            coonsole.groupEnd();
            return;
        }
        console.info("No searchElem - need to create one");
        // Calculate the ideal position for the new element
        let left = clickedElement.position().left - 22,
            top  = clickedElement.position().top + clickedElement.height() + 12,
            maxWidth = 350,
            width = ((left + maxWidth) < $(window).width()) ? maxWidth: $(window).width() - left;

        console.info("left = ", left);
        console.info("top = ", top);
        console.info("maxWidth = ", maxWidth);
        console.info("width = ", width);

        // Create the new DIV element with contents from a template
        let divElement = $(`<div id='${options.searchId}' class='${options.bubbleClass}'></div>`)
                .html("<div class='search'><input type='search' name='serch' placeholder='Search'></div>")
				.appendTo('body')
				.css({
				    'display': 'block',
				    'position': 'absolute',
				    'left': left + 'px',
				    'top': top + 'px',
				    'width': width + 'px'
				});
        console.info("Added ID=", options.searchId, " to the body: ", divElement);

        // Set the input focus to the search box
        $('input[type=search]', divElement).focus();
        console.info("Focus on the search");
        console.groupEnd();
    }

Finally, I need to hook this class in as a jQuery plugin:

// jQuery Interface to the class above
$.fn.searchbox = function(pOptions) {
    return $(this).each(function() {
        $(this).data('my-searchbox', new MySearchBox($(this), pOptions));
    });
};

In this file I’ve used the following new elements of ECMAScript 6:

In order to get this working, I need to compile the ECMAScript 6 code into ES5 code with babel and I need to use a module loader and bootstrap code to get it loaded. Finally, I need some stuff in my HTML page to wire it up.

I need to add gulp-babel and gulp-sourcemaps to my devDependencies in my package.json file to bring in babel support for gulp. I’m also going to add requirejs as a dependency at the same time since I need a module loader. Here is my current package.json file:

{
    "version": "1.0.0",
    "name": "BubbleSearch",
    "private": true,
    "bin-links": true,
    "dev":  true,
    "dependencies": {
        "bootstrap": "3.3.2",
        "jquery": "2.1.3",
        "requirejs": "2.1.16"
    },
    "devDependencies": {
        "gulp": "3.8.11",
        "del": "1.1.1",
        "merge-stream": "0.1.7",
        "gulp-babel": "4.0.0",
        "gulp-sourcemaps": "1.5.0"
    }
}

In order to use RequireJS, I need to bootstrap file: src/js/init.js. This file is relatively small:

require.config({
    baseUrl: '/js',
    paths: {
        'jquery': '/lib/jquery/jquery.min',
        'bootstrap': '/lib/bootstrap/js/bootstrap.min'
    },
    shim: {
        'bootstrap': { deps: ['jquery'] }
    }
});

require([
    'jquery',
    'classes/MySearchBox',
    'bootstrap'
], function ($) {
    $(document).ready(function () {
        $('#nav-search').searchbox();
    })
});

When I brought in RequireJS from NPM I noticed that it didn’t have a dist directory so I can’t add it to my libraries array. There are always exceptions to the rule. I’m going to have to deal with that separately in the Gulpfile.js with this task:

gulp.task('libraries:requirejs', function () {
    gulp.src(path.join(npmPath, 'requirejs/require.js'))
        .pipe(gulp.dest(path.join(buildPath, 'lib/requirejs')));
});

I also want to compile my ECMAScript 6 files and put them in my wwwroot directory. This is another task in the Gulpfile.js. I’m also going to put in a task to clean up my generated javascript files:

gulp.task('source:compile-js', function () {
    return gulp.src(['src/js/init.js', 'src/js/**/*.js'])
        .pipe(sourceMaps.init())
        .pipe(babel({ modules: "amd" }))
        .pipe(sourceMaps.write("."))
        .pipe(gulp.dest(path.join(buildPath, "js")));
});

gulp.task('source:clean-js', function (cb) {
    del([path.join(buildPath, 'js/**')], cb);
});

Finally I need to update the build and clean tasks in Gulpfile.js:

gulp.task('build', [
    'libraries:copy',
    'libraries:requirejs',
    'source:compile-js'
]);

gulp.task('clean', [
    'libraries:clean',
    'source:clean-js'
]);

As before, you can now use the build and clean tasks to generate the wwwroot area. We still have not wired up the code within the test.html file. Update the test.html file like this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test Page</title>
    <link href="lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="lib/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" />
</head>
<body>
    <header>
        <nav>
            <ul>
                <li id="nav-appstore"><span class="glyphicon glyphicon-th"></span></li>
                <li id="nav-notifications"><span class="glyphicon glyphicon-comment"></span></li>
                <li id="nav-search"><span class="glyphicon glyphicon-search"></span></li>
            </ul>
        </nav>
    </header>

    <script src="lib/requirejs/require.js" data-main="js/init"></script>
</body>
</html>

Let’s automate the running of the build and clean steps. To do this, right-click on the build task in the Task Runner Explorer and select Binding->After Build. Do the same thing for the clean task but pick the Binding->Clean option. Now you can run the project and it will automatically build your wwwroot area for you – you no longer have to right-click on Tasks->build to get the build to run – just press F6.

Before I leave, let me point out the console.

vnext-part2-console

Note the line numbers on the right hand side. They refer to the line numbers in the ECMAScript 6 file – not the line numbers in the compiled Javascript. I’ve also made the function collapsible – you can click on the arrow next to MySearchBox::onClick and collapse all the debugging statements into one line.

In my next article I’ll be discussing styling of the search box and will integrate the SASS preprocessor and Pleeease into my build process. Until then, I’ve uploaded this code to my GitHub Repository for you to review. Note that it is the complete code, so check out the other articles in the series that cover everything.

Web Dev Tools 101: ECMAScript Version

You think you are writing JavaScript. Actually, you are writing ECMAScript v5 – also known as ISO/IEC 16262 or ECMA-262. ECMAScript v5 was released in 2009 with an adjustment (v5.1) in 2011. That means the majority of the world is writing their JavaScript in this language. However, there is a new specification on the horizon – ECMAScript 6 – scheduled for a mid-2015 release, and you can expect modern browsers to start implementing the new standard quickly once ratified. But should you be adding ECMAScript 6 to your arsenal or should you leave it alone for now.

TL;DR

it’s a great time to start dabbling in ECMAScript 6, but use a transpiler like Babel-core to compile your code to ECMAScript 5. The browsers are catching up and within a couple of years, you won’t need this step.

Why do I care?

ECMAScript 6 is around the corner, but it’s pretty much backwards compatible. There is a great browser support page here that looks at the language feature by feature. Some things you will want to take advantage of straight away, and some probably won’t interest you. Let’s take a look at some of the features of ECMAScript 6, with appropriate links to real-world definitions (rather than the specification, which is worth a read if you can’t sleep).

These are ones I will actually use, rather than all the little ones.

I’ll be doing a whole article on Modules since it explicitly affects how you write code. All this is good, but that’s a lot of red on the compatibility chart. There are two questions you need to ask:

  1. When are major browsers going to support ECMAScript 6?
  2. What do I do in the interim?

The interim is a long long time – we’ve only just got rid of Internet Explorer 6 finally. So there is a valid point here. If it’s going to take forever for major browsers to work with ECMAScript 6 because of upgrade cycles, why should I even bother?

To answer question 1, let’s take a look at the major browsers:

  • Google Chrome: Most of the ES6 features are hidden behind a flag called “Experimental JavaScript features”. Visit chrome://flags/#enable-javascript-harmoney and enable this flag. Restart Chrome and you will get a bunch, but not all, features. It looks like Chrome is heading in the right direction.
  • Mozilla Firefox: Firefox is already implementing much of the ECMAScript 6 standard. It should be complete within a couple of releases. Since releases of Firefox are close together, this means that it’s likely that Firefox will have close to 100% coverage by the time the draft becomes a standard.
  • Microsoft Internet Explorer: The Technical Preview for the browser that will be released with windows 10 is shaping up to cover practically the entirety of ECMAScript 6. IE 10 and IE 11 are currently distributed though, and they do not provide coverage. Microsoft has also publically stated that they won’t be upgrading those browsers to be ECMAScript 6 compatible.

The Kangax site shows a support matrix for pretty much all the major browsers.

Transpiling: The Next Frontier

So, you like the features of ECMAScript 6, but no-one supports them. The next best option, and likely the best options for a few years, is to use a transpiler. A transpiler in this context is something that takes ECMAScript 6 in and outputs ECMAScript 5. Just like any other compiled language, you don’t want to be looking at the output. Ideally, the transpiler you choose should have three features:

  1. Support for the ES6 features you want to use
  2. Source maps
  3. Integration with your task runner

A sourcemap is generally yourfile.js.map – it’s a mapping from the original source code to the transpiled source code. When you are debugging, you don’t want to have to think about where the error occurred in the original source code – you just want the debugger to tell you. Sourcemaps do that for you.

You can check out the Kangax web site for supported features – it looks for the transpilers as well.

There are two transpilers worth your effort – Traceur and Babel-Core. Both of them are pretty good and the compatibility is improving all the time now that the ES6 specification is locked down. Pretty much anything you want to do (except for maybe modules) is either implemented in the browsers or implemented in one of the transpilers.

Which one is better? Babel-core has better coverage, works with more libraries, is distributed with NPM and has support for Gulp and Grunt.

Someone is going to tell me off because I missed out Typescript.  TypeScript is a language by Microsoft and fully supported within Visual Studio.  You can also compile it using grunt or gulp.  Angular just announced they are writing their v2.0 application code in Typescript, and it has a bunch of ES6 features – actually most of them.  Plus it’s got the backing of Microsoft.   I’d use it as a transpiler and certainly they’ve made it easy.  But be aware of the features in Typescript that aren’t ES6, like interfaces. Those are not transportable, so you need to be aware when you use them.

The Verdict

Do you like working in the future or the past? The past is ECMAScript 5, but it will be here for a long time. ECMAScript 6 is the future, easy to pick up once you have a working knowledge of ECMAScript 5, and easily implementable.

Browser support isn’t there yet for ECMAScript 6. My recommendation is write in ECMAScript 6 and use the Babel-core transpiler to compile your code to ECMAScript 5.