Generating a single output file

In the original version of our drawing application, we only had six files to download to the client browser: a single CSS file, our app.js file, and the files containing our object types. Each file is a separate web request and all of the files must be loaded before our application can run.

Generating a single output file

This is a relatively speedy process, and on average takes less than 100 ms depending on network latency. However, in our quest to create a large-scale maintainable application, the number of code files we have has exploded. We now have more than 20 files that need to be loaded into the client browser before the application will successfully complete all of its functionality. This has caused our load times to more than double from what they previously were as shown in the following screenshot of the network traffic:

Generating a single output file

This delay in load time is perfectly acceptable for development purposes (in fact, as we will see in the next chapter, it will actually be preferable). However, if we ever plan to make our application available to consumers, then we will need to reduce the footprint of our JavaScript output. Before implementing AMD modules, this was as simple as providing the compiler with the --out parameter or changing our TypeScript build settings in Visual Studio. However, when the module flag is provided, this is not possible.

To compile all of our resulting JavaScript modules into a single file, we will need at least one more tool at our disposal. Node.js is a fantastic platform that provides a whole host of functionality, and its primary function is to help create scalable network applications. It is available for download from http://nodejs.org/. Node provides a ton of functionality, and I encourage you to read through the API documentation and examples to learn more. In our case, we are going to use it as a JavaScript runtime environment. This will allow us to use r.js to trace all of our RequireJS statements and build an optimized module list.

Generating a single output file

Once we have Node.js installed, we will have access to it from the command line as well as through PowerShell. We will use this in combination with r.js, which was installed in our Visual Studio project when we installed the RequireJS NuGet package. This library is an optimizer for RequireJS and runs in both Node and Rhino.

Note

For more information regarding Rhino, please visit https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino.

The optimizer requires a few parameters that will determine how the output is generated. We must provide a name, the path to the resulting output file, a flag that tells the optimizer to search for all of the nested dependencies in our application, and the paths that r.js should look at when performing its optimization. We will place all of these options in a separate JavaScript file that we can modify if we want to change the way we want our final code to be generated:

({
    name: "DrawingApplication",
    out: "DrawingApplication.js",
    findNestedDependencies: true,
    optimize: "none",
    paths: {
        'DrawingApplication': 'app'
    }
})

As you can see, all of these options are placed on a JSON object that will be provided to the RequireJS optimizer. The one extra flag here is the optimize flag, which determines whether or not the code should be minified.

Note

For more information about the r.js optimizer, please visit http://requirejs.org/docs/optimization.html.

For the sake of readability, we will leave it at none for now. When we actually want to deploy our code, we can simply comment this option out and all of our code will be placed on a single line in a single file. The final thing we must do to generate our optimized JavaScript output file is create a simple PowerShell script that will run the optimizer and provide our options:

cls
write-host '-Building Drawing Application'
node Scripts/r.js -o buildSingleFile.js

In this script, we clear the current screen, log some output, and finally use Node.js to run the RequireJS optimizer. If everything goes as expected, the optimizer will provide tracing output, letting us know that all of the modules required for our application to work have been included in the optimization. The following screenshot shows the output of running our script and as you can see all of the JavaScript dependencies have been included in the build:

Generating a single output file

The final piece of this process is modifying our HTML page to point at the resulting output file. Before we can do this, we must understand the output from the PowerShell script we just ran. As we discussed earlier, there are three parameters for AMD modules; however, we only provided two. The module name was left out of the resulting JavaScript for our module definitions, and this caused RequireJS to search the directory structure for modules. Now that we have combined all of these modules into a single file, this is no longer an effective way for us to load modules. Thankfully, the optimizer handles this problem for us:

define('DrawingApplication',["require", "exports", 'Scripts/DrawingApplicationModel'], function(require, exports, DrawingApplicationModel) {
    $(document).ready(function () {
        var canvas = window.document.getElementById("drawingCanvas");
        ko.applyBindings(new DrawingApplicationModel(canvas));
    });
});

This module definition actually represents the output of the app.ts file, which is the entry point to our application. As you can see, the define method is now receiving all three parameters. Based on the parameters we provided to the optimizer, the name given for the app module is now DrawingApplication. RequireJS will take note of this name, and anywhere another module requires it, it will be loaded instantly rather than searching the file structure for a JavaScript file with the given pathname and filename. The last thing we must do is modify our HTML page to point at the new single output file. This is done by setting the data-main attribute for the RequireJS tag to the newly built JavaScript file as shown in the following screenshot:

Generating a single output file

We only need to modify the data-main attribute of the script tag we use to load RequireJS and it will handle the rest. RequireJS will see that it does not have a definition for DrawingApplication and will search the filesystem relative to the location of require.js for DrawingApplication.js and load it.

Note

This behavior can be modified through the require.config method. For more information about require.config, please visit http://requirejs.org/docs/api.html#config.

This will cause all of our module definitions to be evaluated and an entry will be created for each one by RequireJS for instantaneous loading when they are required. Finally, when RequireJS reaches the DrawingApplication module, which has been placed last in the resulting output file to ensure all of its dependencies have been defined, it will be defined and then the function will run.

The DrawingApplicationModel class, which has already been defined, will be found in the RequireJS cache and will not be dependent on loading another JavaScript file. As you can see, the loading of our application code is now only a single web request, which will significantly decrease the application load time:

Generating a single output file

Now, we can keep our code separated in individual code files and not have to worry about performance in production. In the next chapter, when we cover debugging, this will become even more important for aiding our development of application-scale JavaScript projects.

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

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