Dojorama Part 8: Baking The Production Build

This article is part of the series Dojorama: Building a Dojo Single Page Application.

To conclude with this series of articles, we'll look at the process of creating optimized builds for production deployments.

A typical step in deploying a Dojo Toolkit-based application is to create a build of your application; IMHO this process comes quite close to magic: a build minifies your JavaScript, inlines HTML and CSS, and generally makes your application run much more efficiently. I'm not going into the details of the Dojo build system, please go here for an introduction.

Optimization Strategy

Working with the build tool leaves a lot of room to experiment with your build configuration. Depending on your strategy, you might create one big file containing all or most of the modules which are used globally across your app. Another strategy might be to split up the code and generate multiple layer files under 25k (uncompressed).

In the final application I have added configurations for both strategies in build/single-file.js and build/multi-file.js respectively.

Global Code In One Big File

<html>
    <body>
        <script src="/builds/single-file/dojo/dojo.js"></script>
    </body>
</html>

Global Code In Mulitple Files (Each Under 25k)

<html>
    <body>
        <script src="/builds/multi-file/dojo/dojo.js"></script>
        <script src="/builds/multi-file/dojorama/layers/mijit.js"></script>
        <script src="/builds/multi-file/dojorama/layers/app.js"></script>
        <script src="/builds/multi-file/dojorama/layers/model.js"></script>
        <script src="/builds/multi-file/dojorama/layers/form.js"></script>
        <script src="/builds/multi-file/dojorama/layers/dobolo.js"></script>
        <script src="/builds/multi-file/dojorama/layers/dgrid-common.js"></script>
        <script src="/builds/multi-file/dojorama/layers/dgrid-extra.js"></script>
        <script src="/builds/multi-file/dojorama/layers/global-stuff.js"></script>
    </body>
</html>

Lazy-Loading Layers

In addition to the global layer(s), we want some layers to lazy-load only when the users accesses a specific section of the application. Dojomat provides the infrastructure to preload any number of layers before initializing page widgets. To do so, the layer paths have to be added to routing-map.js:

define(["require"], function (require) {
    return {
        home: {
            schema: '',
            widget: require.toAbsMid('./ui/home/HomePage'),
            layers: [require.toAbsMid('./layers/home')]
        }
    };
});

Runtime Configuration

Hardcoding layer paths in the routing map leads yet to a problem: We want to be able to use the same routing-map.js, no matter if we're running the application from source or from an optimized build. To achieve this, we will load layer-paths from dojoConfig:

routing-map.js

define(["dojo/_base/config", "require"], function (config, require) {
    var layers = config['routing-map'].layers || {};

    return {
        home: {
            schema: '',
            widget: require.toAbsMid('./ui/home/HomePage'),
            layers: layers.home || []
        }
    };
});

With this setup, we can optionally feed in the layer paths from configuration:

Running From Deployment Build

Adding layer paths to configuration:

tests/app/single-file/index.html

<html>
    <body>
        <script>
            var dojoConfig = {
                async: 1,
                'routing-map': {
                    layers: {
                        home: ["dojorama/layers/home"]
                    }
                }
            };
        </script>

        <script src="/builds/single-file/dojo/dojo.js"></script>
    </body>
</html>

Running From Source

tests/app/source/index.html

<html>
    <body>
        <script>
            var dojoConfig = {
                async: 1
            };
        </script>

        <script src="/vendor/dojo/dojo/dojo.js"></script>
    </body>
</html>

Build Configuration

Here's a quick summary of all the files required to configure and run the build:

  • package.json (package description)
  • package.js (dojo-specific build information)

Single-File Build

  • builds/single-file.js (build profile)
  • builds/single-file.sh (command line shortcut to run the build)
  • builds/single-file/* (build files are generated into this directory)
  • builds/single-file/build-report.txt (build report for debugging)

Multi-File Build

  • builds/multi-file.js (build profile)
  • builds/multi-file.sh (command line shortcut to run the build)
  • builds/multi-file/* (build files are generated into this directory)
  • builds/multi-file/build-report.txt (build report for debugging)

Running The Build

  • cd builds
  • rm -dR single-file (delete existing build)
  • ./single-file.sh (create single-file build)
  • point your browser to tests/app/single-file-build

or

  • cd builds
  • rm -dR multi-file (delete existing build)
  • ./multi-file.sh (create multi-file build)
  • point your browser to tests/app/multi-file-build

Conclusion

It can take a little bit of experimenting until layers are configured correctly according your requirements. The build-report is of great help for debugging. But once you have your configuration in place, your entire application, including JavaScript and CSS, gets minified and optimized with one single command and in less than a minute. This is a great thing!

This was the last article in this series. In the hope that his has been at least a little bit useful for someone, I'd like to thank you for reading!