datajs goodies - build system

The datajs source code includes not only the files for the library itself, but also the files to build from the multiple source files and to run a series of basic tests on them.

The main goals we wanted for our project were the following:

  • Ability to produce an efficient, minified codebase.
  • Ability to separate our code into different files, to improve maintenance and help understand what's in there.
  • Ability to leverage Visual Studio as an IDE and to run tests and debug from it, and do these same activities from a command line.
  • Achieve all of the above with some simple and straightforward.

As such, the datajs project includes a series of files under the 'BuildTools' directory that help with this. We assume that if you're working on datajs then you know JavaScript, and so the build system is mostly driven by JavaScript files run by cscript.

Here is a quick overview of what happens when you build.

  • To build, run djsbuild.cmd. This will prompt for a number of environment variables to be set, then merges all source files, removes internal flags and produces a minified version.
  • The merging takes place in djsbuildfile.js. Here we start from files that aren't included from anywhere else (in our case odata.js) and textually include all files that are referenced in an // INCLUDE: comment.
  • The files may include sections of code under a special conditional (so far we only have ODATA_INTERNAL defined). These blocks are removed during the build process from the merged file.
  • The minified file is created if you download and copy the files from https://ajaxmin.codeplex.com/. We didn't include these in our project to keep things simple - no need to go through extra licenses when getting datajs, or to keep updating ajaxmin (and also to make it easier to isolate and modify the specific minifer used).

datajs ODATA_INTERNAL flag

The datajs sources include special internal flags, typically variables that are checked on the window object such as window.ODATA_INTERNAL.

The purpose of these flags is to expose additional functions on some globally-reachable object, so other files can use them.

For example, the file odata-utils.js has a lot of constants and functions that are exposed, such as parseTimezone. This is done by assigning them to the OData object. The file odata-atom.js assigns OData.parseTimezone to a local variable before the content section, and then uses it whenever it needs to.

When we merge the files to produce a single datajs file, everything goes into the same function, and so can be accessed directly without having to go through a global path. Therefore, you will see that the code always "imports" code before real content, and you will always see that code that "publishes" members inside a conditional block.

The effect is that from a tool that doesn't know about the build process you can run code that uses datajs simply by including all files - the files will cooperate to share code and data. When we run the build process, the files are all merged together, the members are no longer publicly accessible, and the minifer tools can turn all of those functions into much, much shorter text.

Enjoy!