Multi-Platform Distribution with TypeScript

By on June 1, 2015 10:47 am

Over the past several years, JavaScript has grown to be relevant not only for rich browser applications, but also for server and console applications. Many types of JavaScript libraries can be useful on both ends of this spectrum. Dojo 2 is no exception, and one of our goals is therefore to make it as easily distributable and consumable across environments as possible.

Module Compilation in TypeScript Today

TypeScript can already help toward this goal by compiling to both the AMD and CommonJS module formats. For example, given the following simple TypeScript module:

export function myFunction() {
    // ...
}

Compiling this with tsc -m amd produces the following code:

define(["require", "exports"], function (require, exports) {
    function myFunction() {
        // ...
    }
    exports.myFunction = myFunction;
});

Meanwhile, compiling with tsc -m commonjs looks like this:

function myFunction() {
    // ...
}
exports.myFunction = myFunction;

This is all well and good, but as-is it clearly requires maintaining two separate distribution processes – one for each format. This not only adds complexity to our compilation and release processes; it also throws a significant curveball at IDEs with TypeScript integration.

Making Ends Meet with UMD

A number of modern libraries have adopted the Universal Module Definition (UMD) format as a solution to this problem. This format accommodates both CommonJS and AMD loaders, typically by assigning to module.exports if it exists (for CommonJS), or calling define if it exists and define.amd is defined (for AMD).

If you’ve been following our blog, you know we’re pretty passionate about TypeScript, and we’re not afraid to get our hands dirty and help out where we can. Colin Snover, one of our senior software engineers, discovered an open TypeScript issue for adding UMD support, and put together a pull request.

After some discussion (mostly around the name for the added mode, because naming things is hard), the pull request was merged. This is great news, because it means that in TypeScript 1.5, anyone interested in compiling code to support both AMD and CommonJS environments will be able to use the umd module format.

Using the same example from above, running tsc -m umd in TypeScript 1.5 will produce the following:

(function (deps, factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(deps, factory);
    }
})(["require", "exports"], function (require, exports) {
    function myFunction() {
        // ...
    }
    exports.myFunction = myFunction;
});

Note that while some variants of UMD include a fallback to set a global variable, TypeScript’s umd support does not include this provision, primarily because of the complexity involved in automatically generating reasonable yet unique global variable names for every module. (Did I mention that naming things is hard?)

Using UMD in TypeScript Now

If you just can’t wait for TypeScript 1.5, and are willing to live on the edge, Arnav Singh graciously provides periodic releases based on TypeScript’s master branch in his typescript-github repository, and UMD support is in the latest builds. However, it’s worth noting that TypeScript’s master branch can have show-stopping bugs sometimes (such as this one, recently fixed by our own Bryan Forbes, and fixed in the 2015-05-06 build), so there is some amount of risk involved.

Conclusion

TypeScript is already proving to be a solid choice for robust application development due to its type safety and its growing list of useful features. Adding UMD support to that list is particularly powerful for authors of libraries intended to be consumable by browsers and servers alike.

Learning More

If your team is new to TypeScript and needs support, we’re happy to help under our support plans. If you are looking to build an application with TypeScript, and need assistance with architecture or development of features, we’d love to help. Contact us for a free 30 minute consultation to discuss your application.

Comments