The Troubles With JavaScript Modules

Tuesday, October 4, 2016 by K. Scott Allen

This post is one in a series of posts where I describe common problems developers face using ES2015 features of JavaScript. In this post we look at modules.

The Syntax Pitfall

The first pitfall developers hit when using modules is making assumptions about the syntax. I fell into this trap myself.

import {Person, Animal} from "./lib"

Curly braces in JavaScript appear everywhere. We use them to define block statements, object literals, and more recently, use them for destructuring. Once I learned about destructuring, I looked at my next import statement and wrongly assumed JavaScript was destructuring a node-like module object into new variables.

That’s all wrong!

Import statements create bindings with behaviors that transcend mere variable declarations.

Immutable Bindings

Consider a module with the following export.

export let counter = 0;

And now a module that wants to consume the export.

import {counter} from "./lib/exporter";

counter = 2;

The code trying to set the counter is in error because import bindings are immutable.

What sort of error will you see?

The specification calls for a TypeError, however:

    - we currently don’t have a runtime environment that uses ES modules natively because the module loading spec is still a work in progress, and

    - we rely on transpilers to transform ES 2015 imports and exports into de-facto standards like CommonJS where the rules are relaxed

For those reasons, the error we will see (or not see) depends on the tools we use. For example, the TypeScript compiler will give an error on any assignment to counter – “Invalid left-hand side of assignment expression”. Babel will give us a similar build-time error. As an aside, this is the type of scenario that worries me. Features like import bindings, variable scopes, const, and others might work differently when we transpile for newer runtimes in the future and use these features natively. I don’t foresee catastrophic problems, but there will be some headaches along the way.

Live Bindings

The behavior of bindings also surprises some developers, particularly when importing state from another module. Let’s add some additional exports to the exporting module.

export let counter = 0;

export let creature = {
    name: "Oscar"
};

export function increment() {
    counter += 1;
    return counter;
}

export function inspect() {
    return creature.name;
}

export function reset() {
    creature = { name: "Oscar" };
}

Although we can’t import and then mutate the value of the counter binding, we can call a piece of code in the exporting module that can change the value of the counter.

import {counter, increment} from "./lib/exporter";

describe("binding behavior", () => {
    it("is live", () => {

        expect(counter).toBe(0);

        increment();

        expect(counter).toBe(1);

    });
});

Notice the change to counter is visible inside the importing module. The same behavior holds for objects, too.

import {creature, inspect, reset} from "./lib/exporter";

describe("binding behavior", () => {
    it("is live", () => {

        expect(creature.name).toBe("Oscar");

        // this is legal - not trying to change the binding
        creature.name = "Scott";

        // everyone sees the change, even the exporting module
        expect(inspect()).toBe("Scott");

        // but only the exporter can change the binding value
        reset();
        expect(creature.name).toBe("Oscar");
    })
});

For developers, it’s important to understand that modules are singletons. Any module importing counter and creature will see the same values.

Static Semantics

Node developers accustomed to the flexibility of ConmmonJS can be disappointed by the inflexible, concrete nature of ES 2015 modules. The ES specification gives tools and runtimes the ability to statically analyze module code to discover imports and exports. Static analysis is good for early error detection, bundlers, optimizers, and tools in general, but not so good for anyone who wants to dynamically load modules. Dynamic loading is not out of the question, however. Dynamic loading will be something you can do with the module loading API at runtime (System.import, for example), but not with the ES syntax itself.

Which isn’t too say there is no flexibility in ES modules. RxJS 5 has an interesting design. The following import statement brings in large swaths of the library so you do not need to explicitly add individual operators.

import {Observable} from "rxjs";

If you want to build  a smaller application bundle, you can import Observable from a different location and add just the operators you need. 

import {Observable} from "rxjs/Observable";
import "rxjs/add/operator/map";

Default Exports versus Named Exports

Finally, another area of confusion exists when working with libraries like React that provide both named and default exports. To grab a default export, the code doesn’t use curly braces.

import React, {Component} from "react";

I’ve seen a few developers try to use the braceless syntax to grab named exports, but without braces you can only grab the default export.

Previous Topics

The Troubles with JavaScript Classes

The Troubles with JavaScript Arrow Functions

Reusing JavaScript Template Literals

Modules in JavaScript

Database Migrations and Seeding in ASP.NET Core

Tuesday, September 20, 2016 by K. Scott Allen

There is an instant in time when an ASP.NET application is fully alive and configured but it still held in check and waiting for a signal from the starter’s gun. This moment exists between the lines of code in Program.cs, and it is here where I’ve found a nice place to automatically run database migrations and seed a database based on command line arguments to the program.

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    ProcessDbCommands(args, host);

    host.Run();
}

ProcessDBCommands is the method I use in the above code, and the logic here can be as simple or as complicated as you need. In my case, I’m just going to look for keywords in the arguments to drop, migrate, and seed the database. For example, running “dotnet run dropdb migratedb seeddb” will execute all three options against the configured database.

private static void ProcessDbCommands(string[] args, IWebHost host)
{
    var services = (IServiceScopeFactory)host.Services.GetService(typeof(IServiceScopeFactory));

    using (var scope = services.CreateScope())
    {
        if (args.Contains("dropdb"))
        {
            Console.WriteLine("Dropping database");
            var db = GetLeagueDb(scope);
            db.Database.EnsureDeleted();
        }
        if (args.Contains("migratedb"))
        {
            Console.WriteLine("Migrating database");
            var db = GetLeagueDb(scope);
            db.Database.Migrate();
        }
        if (args.Contains("seeddb"))
        {
            Console.WriteLine("Seeding database");
            var db = GetLeagueDb(scope);
            db.Seed();
        }
    }        
}

private static LeagueDb GetLeagueDb(IServiceScope services)
{
    var db = services.ServiceProvider.GetRequiredService<LeagueDb>();           
    return db;
}

A couple notes on the above code.

IWebHost gives us access to a fully configured environment, so connection strings and services are available just as they are inside the rest of the post-startup application code.

The db.Database.EnsureDeleted and db.Database.Migrate methods are built-in APIs for EF Core. The Seed method, on the other hand, is a custom extension method.

The Troubles with JavaScript Classes

Tuesday, September 13, 2016 by K. Scott Allen

Over the summer I gave a talk titled “The New Dragons of JavaScript”. The idea was to provide, like the cartographers of the Old World, a map of where the dragons and sea serpents live in the new JavaScript feature landscape. These mythological beasts have a tendency to introduce confusion or pain in software development.  

One area I covered were the quirks you might run into with JavaScript classes. Some introductions explain how classes work by describing the de-sugaring a transpiler applies to transform a class into the classical constructor function and prototype manipulation we’ve used in JavaScript for many years.

class Employee {
    constructor(name) {
        this._name = name;
    }

    doWork() {
        return `${this._name} is working`;
    }
}

// above code becomes ...

let Employee = function(name) {
    this._name = name;
};

Employee.prototype = {
    doWork: function() {
        return `${this._name} is working`;
    }
}

Constructor functions and prototypes are a useful mental model to have at times, but also leads to trouble because classes aren’t exactly like using constructor functions. For example, functions in JavaScript will hoist, but classes do not. If you ever want to push the definition of a small utility class to the bottom of a file and try to use the class in the code at the top of the file, you’ll be setting yourself up for an error.

// this code works
const e = new Employee();

function Employee() {

}

// this code produces a ReferenceError
const e = new Employee();

class Employee {

}

Technically, classes (and variables declared with let and const) do hoist themselves, but they hoist themselves into an area the early specs referred to as the “temporal dead zone”. Accessing a symbol in its TDZ creates a RefernceError.  As an aside, “Temporal dead zone” is, I think, one of the greatest computer science terms ever conceived and should also be the title of a Hollywood film starring Mark Wahlberg.

Another difference between creating an object using a class and creating an object with a constructor function is in reflective code. It’s easy to discover the methods of an object instantiated with a constructor function using a for in loop.

const Human = function () { }
Human.prototype.doWork = function () { };

let names = [];
for (const p in new Human()) {
    names.push(p);
}
// ["doWork"]

The same code won’t work when using a class definition.

class Horse {
    constructor() {}            
    doWork() { }
}

names = [];
for (const p in new Horse()) {
    names.push(p);
}
// []

However, it is possible to get to the methods of a class using some Object APIs.

names = [];
const prototype = Object.getPrototypeOf(new Horse());
for(const name of Object.getOwnPropertyNames(prototype)) {
    names.push(name);
}
// ["constructor", "doWork"]

Coming soon – The Troubles with Modules.

Previously in this series – The Trouble with JavaScript Arrow Functions

Combining HttpPost and ValidateAntiForgeryToken

Thursday, September 8, 2016 by K. Scott Allen

I’ve been kicking around the idea of combining [HttpPost] and [ValidateAntiForgeryToken] in an application using authentication cookies. Both attributes typically appear together to prevent cross-site request forgeries in MVC applications using cookie based authentication. The result looks like the following.

[HttpPostWithValidAntiForgeryToken]
public IActionResult Edit(Input model)
{
    // ... 
}

And the attribute definition is as follows.

public class HttpPostWithValidAntiForgeryToken
    : Attribute, IActionHttpMethodProvider, IFilterFactory
{
    private readonly HttpPostAttribute _postAttribute;
    private readonly ValidateAntiForgeryTokenAttribute _antiForgeryAttribute;

    public HttpPostWithValidAntiForgeryToken()
    {
        _postAttribute = new HttpPostAttribute();
        _antiForgeryAttribute = new ValidateAntiForgeryTokenAttribute();
    }

    public IEnumerable<string> HttpMethods => _postAttribute.HttpMethods;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return _antiForgeryAttribute.CreateInstance(serviceProvider);
    }

    public bool IsReusable => _antiForgeryAttribute.IsReusable;
}

With the new attribute, a plain [HttpPost] should never appear in the application, and a unit test using reflection could enforce the rule.

Don't Throw Away All Those web.config Settings

Tuesday, September 6, 2016 by K. Scott Allen

ASP.NET Core might not use a complicated hierarchy of XML configuration files anymore, but if you host under IIS, then IIS and web.config are still the best of friends. There is some XML configuration required to run Core under IIS, specifically the part to reverse proxy all incoming requests over to the ASP.NET Core module and ultimately into the Kestrel server.

Other pieces of web.config still work in the new world of ASP.NET, too. For example, IIS will still honor rewrite rules in web.config.

Here is a sample web.config to enforce lower case URLs that also proxies to the ASP.NET Core Module.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>

    <rewrite>
      <rules>
        <rule name="Convert to lower case" stopProcessing="true">
          <match url=".*[A-Z].*" ignoreCase="false" />
          <action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
    
    <handlers>
      <add name="aspNetCore" path="*" verb="*" 
           modules="AspNetCoreModule" resourceType="Unspecified"/>
    </handlers>
    
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" 
                stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" 
                forwardWindowsAuthToken="false"/>
    
  </system.webServer>
</configuration>

The Troubles with JavaScript Arrow Functions

Thursday, September 1, 2016 by K. Scott Allen

Over the summer I gave a talk titled “The New Dragons of JavaScript”. The idea was to provide, like the cartographers of the Old World, a map of where the dragons and sea serpents live in the new JavaScript feature landscape. These mythological beasts have a tendency to introduce confusion or pain in software development.

Arrow functions have surprised me with the amount of turmoil they’ve created. At first glance, they seem so easy, like when multiplying the numbers in an array by 2.

const numbers = [1, 2, 3];
const result = numbers.map(n => n * 2);
// produces [2,4,6]

But even a simple map operation can run into problems if the code tries to map each element to an object literal using the wrong syntax.

const numbers = [1, 2, 3];
const result = numbers.map(n => { value: n });
// produces [undefined], [undefined], [undefined]

The problem in the above code is that the opening curly brace of the arrow function makes JavaScript think there is a block of code to execute instead of a simple object literal expression to evaluate. The result is an array of undefined. In this scenario the code either needs an explicit return statement, or to parenthesize the object literal.

const result = numbers.map(n => ({ value: n }));
// [{value: 1}, {value:2}, {value:3}]

Ironically, most problems developers encounter with arrow functions center around the problem arrow functions attempt to solve. The slippery JavaScript this pointer. A bit of casual reading about arrow functions will tell you how arrow functions capture the this reference from their lexical environment. With arrows, you can write code like the following without worrying about explicitly capturing this into a local variable.

const adder = {
    sum: 0,
    add(numbers) {
        numbers.forEach(n => {
            this.sum += n;
        });
    }

};

adder.add([1, 2, 3]);
// adder.sum === 6

However, it’s easy to write code that assumes the wrong environment. In the following code we have an arrow function inside an arrow function, so the this reference will not be the adder object, but whatever scope the adder object lives in.

const adder = {
    sum: 0,
    add: (numbers) => { // scope here is important
        numbers.forEach(n => {
            this.sum += n;
        });
    }

};

adder.add([1, 2, 3]);
// adder.sum === 0

The biggest sea dragon on the map in the arrow function waters is highlighted in the “NOTE” section of 14.2.16 of the spec. The takeaway here is that we cannot change the this reference inside of an arrow function. The reference is fixed, it’s baked, it’s  static and permanent. There are implications for two types of code. First is the type of code that expects to manipulate this using bind, call, or apply.

const adder = {
    sum: 0
};

const add = (numbers) => numbers.forEach(n => this.sum += 1);

adder.add = add.bind(adder);

adder.add([1, 2, 3]);
// adder.sum === 0

The second type of code is code that expects someone else to setup this for a call. I first experienced the brain teaser of unexpected this values writing arrow functions with Jasmine. Jasmine sets this to a context object for sharing state between test setups and asserts. Arrow functions, Jasmine contexts and regular functions mix into a broken cocktail. The same problem can arise with DOM event handlers.

it("this is not what you might expect", () => {

    // .. this?

});

Summary

Arrow functions are not a replacement for regular functions in JavaScript. There are situations where arrow functions do not work as expected. I’m not giving up on arrow functions, I still use them when possible. However, I do lament the fact that I still need to fret over every use of this in JavaScript code.

Keeping a Clean Startup.cs in Asp.Net Core

Tuesday, August 30, 2016 by K. Scott Allen

In some applications the Configure and ConfigureServices methods of Startup.cs can become unwieldy. It’s not complicated logic, but with all the middleware and services and options to configure, the methods become long and messy.

I prefer to keep a series of simple, one-line method calls inside of both methods.

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.AddCustomizedMvc();
    services.AddCustomizedIdentity();
    services.AddDataStores();
    // ...
}

All of the details for these method calls live inside extensions methods for IApplicationBuilder or IServiceCollection. Here’s an example. 

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddCustomizedMvc(this IServiceCollection services)
    {
        var locationFormat = @"Features\Shared\{0}.cshtml";
        var expander = new ViewWithControllerViewLocationExpander();

        services.AddMvc()
           .AddRazorOptions(options =>
           {
               options.ViewLocationFormats.Clear();
               options.ViewLocationFormats.Add(locationFormat);
               options.ViewLocationExpanders.Add(expander);
           });

        return services;
    }

    // ...
}

My Pluralsight Courses

K.Scott Allen OdeToCode by K. Scott Allen
What JavaScript Developers Should Know About ECMAScript 2015
The Podcast!