CHAPTER 6
There are different ways of packaging your program depending on where you are planning on running it. It is easier if you decide on your packaging strategy up front as it may lead to a subtly different program structure. So far in this book I have used examples that suit the first of the packaging techniques: bundling. This is the technique you are most likely to use if you are writing applications using ASP.NET MVC (bundling was introduced in version 4).
The main differences packaging can make to your TypeScript program are:
I will describe how to do these three things for each of the packaging techniques in this chapter.
Bundling is an increasingly common strategy for improving the performance of websites and web applications. When you reference multiple JavaScript files on a webpage, each file is a separate HTTP request that typically spends more time queuing than downloading. This makes the page appear to load slowly. By combining all of your JavaScript files into a single release file, you eliminate most of the queuing time, which makes users perceive that the webpage loads much faster.
Yahoo’s Exceptional Performance team puts the goal of minimizing HTTP requests at the top of its Best Practices for Speeding up Your Web Site list and suggests bundling as the solution for script files. The list can be found here: http://developer.yahoo.com/performance/rules.html.
To use a bundling strategy in your program, you can declare the modules as you have seen in the examples in this book.
MyModule.ts
module MyModule { export class MyClass { } } |
TypeScript has a commenting system that allows you to make modules in different files available throughout your program. In the comment, you specify the path to the file you want to include relative to the directory of the current source file.
Main.ts
/// <reference path="MyModule.ts" /> var myClass = new MyModule.MyClass(); |
The reference comment promises the compiler that the file will be available at run time, so it allows the use of the module and classes defined inside of the MyModule.ts file. You will get all of the autocompletion and type checking at design time based on the reference comments you include. You can use these comments throughout your TypeScript program wherever one file depends on another, and you can add multiple reference comments if you need to.
When using bundling, TypeScript leaves the method of combining scripts to you. This allows you to take advantage of the built-in ASP.NET MVC bundling feature. In ASP.NET MVC 4, you can configure your scripts in BundleConfig.cs, which is in the App_Start folder of your application. In this file, reference the compiled JavaScript files, which will have a .js file extension.
BundleConfig.cs
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/MyProgram").Include( "~/Scripts/MyModule.js", "~/Scripts/Main.js")); } } |
If you want to include all scripts in a given directory, you can use a wildcard character in your bundle registration, although this will not guarantee any ordering like an explicit bundle would.
Bundle Using Wildcard Character
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/MyProgram").Include( "~/Scripts/*")); } } |
To add the bundle to your page, use the built-in Scripts helper to render the bundle in your view.
Using the Bundle
@Scripts.Render("~/bundles/MyProgram") |
TypeScript fits in neatly with ASP.NET MVC bundling. This doesn’t mean you have to use MVC to use TypeScript with bundling. You can use a number of free tools to combine your compiled JavaScript files such as YUI Compressor, JSMin, or Google’s Closure Compiler.
Whenever you add a reference comment, let that trigger a reminder in your head to add the script to the bundle or the webpage if it isn’t already included.
CommonJS is intended to provide a common standard library for JavaScript that makes it easier to run as a server-side language, command-line tool, or desktop application. The most famous implementation of CommonJS is the highly scalable Node.js, which runs on Google’s V8 JavaScript engine.
If you are targeting a platform such as Node.js, which implements a CommonJS runtime module loader, you can tell the TypeScript compiler to generate code that works out of the box with CommonJS. To do this, add a module switch to the TypeScript compiler command in your project file. You can also use this switch outside of Visual Studio, which I describe in Appendix A: Alternative Development Tools.
<Exec |
There are currently three draft specifications of CommonJS, and although version 1.0 has been superseded by version 1.1, Node.js hasn’t yet signed up to the changes, so I have based my examples on version 1.0.
To make a module available to a CommonJS implementation, you rely on the file name rather than a module declaration. Because the module is implicitly named after the file, you can simply export the classes and functions that you want to expose externally. If you are using CommonJS, you can organize your TypeScript program using folders and files that represent modules.
MyModule.ts
export class MyClass { } |
Rather than using comments to make a module available, the CommonJS pattern uses an import declaration to load the module. The import statement is automatically compiled into a JavaScript requires statement, which is how you ask CommonJS to load a module.
Main.ts
import myModule = module('MyModule'); // MyModule.ts var myClass = new myModule.MyClass(); |
All of the scripts required by your main.js file will be automatically loaded by the CommonJS library.
TypeScript’s CommonJS support is tailored for platforms such as Node.js, although there are many more implementations that you may not have heard of, such as Narwhal and CouchDB.
AMD stands for asynchronous module definition and is an API that allows your modules to be loaded asynchronously on an as needed basis. This is actually a pattern adapted from CommonJS intended to be used in web browsers.
To use AMD, you will need to add a module-loader to your program, such as RequireJS.
To get AMD output from the TypeScript compiler, set the module mode to “amd” in your project file. If you aren’t using Visual Studio, you can find more information to help you in Appendix A: Alternative Development Tools.
<Exec |
Just like CommonJS modules, your files become modules automatically, and the file name without the extension becomes the module name.
MyModule.ts
export class MyClass { } |
Modules are referenced identically to the CommonJS style, using the import declaration. Although your TypeScript file looks identical to the CommonJS TypeScript file, the compiled JavaScript is very different.
Main.ts
import myModule = module('MyModule'); // MyModule.ts var myClass = new myModule.MyClass(); |
Because RequireJS loads all of your modules as required, you only need to add a script tag for the require.js JavaScript file, and specify your main program file using the data-main attribute. When the RequireJS script loads, it will automatically load the file you specify—in this case Main.js, located in the Scripts folder. As further modules are required, they will be loaded for you behind the scenes.
<script src="Scripts/require.js" data-main="Scripts/Main"></script> |
If you are designing a program that will run on the server, as well as in a browser, you can write your modules in the CommonJS style, and use the TypeScript compiler to give you the CommonJS and the AMD flavors of compiled JavaScript without having to change your code. While your TypeScript remains unchanged between the two platforms, the CommonJS output will use the built-in require function, while the AMD output will call RequireJS.