Controlling compiler output

The TypeScript compiler has a very robust set of features when it comes to controlling the final results of the compiler. The compiler is built in a scalable manner that allows us to compile multiple source files at once as well as controlling their output directory or path. We will also discuss creating source maps that help us when debugging our applications.

JavaScript output

Up until this point, we have only been working with compiling single TypeScript files at a time. As applications grow in size though, it is very important to separate our code into maintainable segments. When writing code for a C# application, it is common to separate code files by class. JavaScript conventions vary in how code is segmented. If following the module pattern, it is common to place an entire module in a single file; otherwise, code is usually segmented into related blocks as the application requires them. Passing multiple file names separated by spaces will tell the compiler to parse each file and generate a JavaScript file for each. The following screenshot shows how this is done:

JavaScript output

As you can see, we now have two TypeScript files and each is being passed to the compiler as a parameter. The result of running this command will be two JavaScript files, one for each corresponding TypeScript file. There is no limit to the number of files that can be provided; however, at some point the command line will reach its buffer limit. We will see in a little while how to make this easier through the use of a parameter file.

The TypeScript compiler provides two main options for controlling where the JavaScript that will be used at runtime is output to. The first option requires a folder location to output all of the generated JavaScript files separately. As you can see in the following screenshot, we use the --outDir parameter to provide our location:

JavaScript output

The other option allows us to compile our TypeScript down into a single JavaScript file. This allows us to make a single HTTP GET request for our application rather than having to make multiple ones. This can be a very complex task to accomplish when an application grows in scale and each piece of code must be loaded in a certain order to ensure proper execution. The TypeScript compiler has a few different ways of ensuring that code generated in a single file is created in such a manner that all objects exist before they are needed. The simplest manner in which to ensure this is to manually provide the files in the order that they should be compiled. Let's look at our two TypeScript files and how they interact:

function sayHello() {
    alert("Hello There");
}
function getRandom(): number {
    return Math.floor(Math.random() * Date.now());
}

The preceding section of code represents a file called utilities.ts and is a collection of functions that can be used to do a variety of different things. The next segment of code is app.ts and it references both of these functions and relies on them to be available at runtime.

SayHello();
alert(GetRandom());

If we were to generate these into separate JavaScript files then we would have to place multiple script tags in our HTML pages. The script tags would have to be provided in a specific order, otherwise a reference error would occur and the application would stop working. We already have to provide multiple TypeScript files to the compiler, so why not just generate a single JavaScript file and avoid having to deal with this? The following screenshot shows how to specify a single file location for all of our generated JavaScript:

JavaScript output

This will result in the concatenation of the two resulting JavaScript files that are generated by the compiler. This means that our TypeScript files must still be provided in the proper order, otherwise a reference error will occur. Thankfully, TypeScript provides a way to help control this problem using a particular syntax to determine a reference graph. The next code segment shows how to provide a specific reference to another TypeScript file to ensure the proper order is upheld by the compiler:

/// <reference path="utilities.ts" />
sayHello();
alert(getRandom());

These references should be made at the very top of your TypeScript files. If they are not, then the order your files are concatenated together in will be wrong. The compiler examines the beginning of each file and parses certain constructs to determine how the resulting JavaScript should be generated. Once the first block of execution code is reached, the compiler will stop looking for these syntax constructs. By providing this reference, we are now able to pass our TypeScript files to the compiler in any order that we want.

Run the command shown in the following screenshot:

JavaScript output

The resulting JavaScript file will look like the following:

function sayHello() {
    alert("Hello There");
}
function getRandom() {
    return Math.floor(Math.random() * Date.now());
}
/// <reference path="utilities.ts" />
sayHello();
alert(getRandom());

As you can see, our final result is placed into a single output.js file and is in the proper order to ensure no reference errors are thrown. It is possible for two files to reference each other, however this is not recommended. If only one of the files references objects instantiated by the other file, the compiler will be able to order the JavaScript properly. Otherwise, it will be unable to guarantee that all of the referenced objects are available at runtime. This will not result in a compilation error, so be wary of creating such a situation.

Source maps

Next, we will look at source maps and how they allow us to step through our TypeScript code rather than just the generated JavaScript. Source maps are a useful tool created to help debug code that has already been combined and minified. TypeScript and Visual Studio take advantage of this by providing source maps that direct back to the original TypeScript files. The --sourcemap parameter tells the compiler to generate a map file for each JavaScript file generated. This map file is then used to help map each line segment of minified or combined code back to a non-minified file that is easier to debug. The map file generated by the TypeScript compiler will point the mappings to the original TypeScript files associated with the code being run.

The following screenshot shows how to generate source maps during compilation:

Source maps

Now, both of our TypeScript files are combined into a single JavaScript file but if we want to debug them individually, we can. When the sourcemap parameter is provided, it tells the compiler to inject a new line into each generated JavaScript file directing the debugger to the source map that has been generated:

//# sourceMappingURL=output.js.map

In our case, the resulting map file is called output.js.map and is located in the same directory as output.js. The contents of this map file are as follows:

{
    "version":3,
    "file":"output.js",
    "sourceRoot":"",
    "sources":["utilities.ts","app.ts"],
    "names":["SayHello","GetRandom"],
    "mappings":"AACA,+BAD+B;AAC/B,SAAS,QAAQ;IACbA,KAAKA,CAACA,aAAaA,CAACA;AACxBA,CAACA;;AAED,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;ACLlB,qCAAqC;AACrC,QAAQ,CAAC,CAAC;AACV,SAAS,SAAS;IACdC,OAAOA,IAAIA,CAACA,KAAKA,CAACA,IAAIA,CAACA,MAAMA,CAACA,CAACA,GAAGA,IAAIA,CAACA,GAAGA,CAACA,CAACA,CAACA;AACjDA,CAACA;AAED,mBAAmB;AACnB,oBAAoB;AACpB,GAAG;AACH,+BAA+B;AAC/B,kCAAkC;AAClC,qBAAqB;AACrB,OAAO;AACP,2BAA2B;AAC3B,6BAA6B;AAC7B,OAAO;AACP,gCAAgC;AAChC,0CAA0C;AAC1C,kCAAkC;AAClC,kBAAkB;AAClB,4CAA4C;AAC5C,WAAW;AACX,OAAO;AACP,GAAG;AAEH,qCAAqC"
}

As you can see, this is a very simple JSON object that contains the information necessary to map the JavaScript code that has been generated back to the TypeScript files that it originated from. The "sources" property contains the array of TypeScript files that we build. The "names" property represents named types that exist within the code, and "sourceRoot" is the location where the source files are located. If you have opted to specify an output file for your combined JavaScript that is in a different directory than your TypeScript files, it is important to specify the --sourceRoot if you intend to use the source map. The sourceRoot parameter should be a value that is relative to the location of your map file.

The following screenshot shows you how to configure your Visual Studio project to combine its JavaScript into a single file, generate a source map, and point that source map back to the original TypeScript files:

Source maps

As you can see, we combine our TypeScript into a single JavaScript file in a subdirectory of the project. The Generate source maps checkbox has been selected so that sourceMappingURL is added to the resulting JavaScript. The Specify root directory of TypeScript files option has been selected and a relative path has been provided for the debugger to interpret. The Specify root directory of source maps option changes the location provided to the sourceMappingURL value. The TypeScript root directory and source map root directory options correspond to the --sourceRoot and --mapRoot respectively.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset