For some time I’ve been looking for a reliable equivalent to #ifdef DEBUG in a JavaScript app, as there are a number of needs to set up different code structures between the two build targets. This includes switching between Windows.ApplicationModel.Store.CurrentApp and CurrentAppSimulator, using test data vs. live data, using test URIs vs production URIs, using test accounts vs. live accounts, using different tokens for back end services, and so on..

I've seen some solutions that utilize t deterministic for JavaScript, but this isn't deterministic for JavaScript because you can debug a Release build just like a Debug build–all the source code is just there, so it's not like C++ where you lose your symbols. I've also seen hacky methods that check for "Debug" in the package install folder path, but that doesn't work for side-loaded apps (like you might share with testers) and maybe not for remote debugging.

It’s really best to get the target configuration straight from VS and somehow apply it to a project, and I worked out how to do it without a VS extension. See this small DebugRelease sample for a demonstration: http://kraigbrockschmidt.com/?attachment_id=1287

What I did is create two .js files in the project (debug.js and release.js in a js-buildinfo folder) that I exclude from the end package by setting their Package Action to None instead of Content. I then use in MSBuild task to selectively copy one or the other file to a common name in the package (e.g. buildinfo.js).

Here are basic file contents:

debug.js:

(function () {
    "use strict";

    WinJS.Namespace.define("BuildInfo", {
        isDebugBuild: true,
        isReleaseBuild: false,

        config: "Debug",
        currentApp: Windows.ApplicationModel.Store.CurrentAppSimulator

        /*
         * Include debug-only data, service URIs, access tokens, accounts, etc.
         */
    });
})();

 

release.js:

(function () {
    "use strict";


    WinJS.Namespace.define("BuildInfo", {
        isDebugBuild: false,
        isReleaseBuild: true,

        config: "Release",
        currentApp: Windows.ApplicationModel.Store.CurrentApp

        /*
         * Include release-only data, service URIs, access tokens, accounts, etc.
         */
    });
})();

To do the selective copy, it’s necessary to add a BeforeBuild action in the project file. At present, VS doesn’t allow custom build configuration for JS projects through the UI, so you have to do the following:

  • Right click and Unload Project in VS.
  • Right click and Edit the project manually.
  • Make the changes below.
  • Right click and Reload Project.

Editing the .jsproj file I added the following entries under the ItemGroup with the project files:

<ItemGrup>
  <BuildFlagSource Include="js-buildinfo $(Configuration).js" />
</ItemGroup>
<ItemGroup>
  <BuildFlagDestination Include="jsbuildinfo.js" />
</ItemGroup>

And then farther down there’s a section that’s commented—you uncomment it and add the <Copy> element shown here:

<Target Name="BeforeBuild">
  <Copy SourceFiles="@(BuildFlagSource)" DestinationFiles="@(BuildFlagDestination)" OverwriteReadOnlyFiles="true" SkipUnchangedFiles="true" />
</Target>
<Target Name="AfterBuild">
</Target>
<PropertyGroup>
  <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>

Ideally you’d make buildinfo.js read-only in the project to prevent editing what will be overwritten in the build.

And the you can just have this line in whatever HTML files need it (usually before other .js files that would use the BuildInfo properties):

<script src="/js/buildinfo.js"></script>

Things I like about this solution:

  • It’s extensible as you can add anything you want to the debug.js and release.js files.
  • The BuildInfo namespace can include methods to do build-specific work, which is sometimes necessary.
  • It enabled isolation of all build-specific code in these files, rather than littering it throughout the rest of the app as you would with just a simple flag. I still have a flag in here as an option, but you wouldn’t have to use that at all.
  • It works no matter how an app is deployed.
  • It’s not dependent on any compiled VS extension that you’d have to produce for x86, x64, and ARM.

A few downsides:

  • Have to hand-edit a project and do some one-time configuration like adding a buildinfo.js and making it read-only.
  • You have to make sure that the debug.js and release.js files define the same stuff.
  • It feels a bit fragile given the manual steps.

What do you think of this solution? It works well and reliably applies the chosen build target to your JS code. But are there things I've missed or things that can be improved?


3 Comments

  1. phil
    Posted February 26, 2014 at 9:37 pm | Permalink

    You know what I think? Visual Studio 2013 gets worse and worse over the years. Your solution is just another hack. Such things should be supported by the default project configuration (like in C++ projects, where you can exclude files for a certain build config).
    Tell u the truth, for our last project we used VS just for compiling and debugging (which is really good). We created the VS project files from the folder structure and a custom coffee script project generator. That also handled this case you write about here. We used sublimetext for CoffeeScript file coding because the VS editor sucks and is so limited (even with VisualAssist for C++).

    Its a shame really.

    • Posted February 26, 2014 at 10:38 pm | Permalink

      Yes, I totally agree that the VS UI should have better configuration for JS apps. To be fair, I’m sure they have a huge backlog for language-specific project features, and have to balance a long list of priorities (such as getting TypeScript up to a first-class citizen, which I just saw in the news today). I’m at least glad that there is a way to do stuff like this, even if it is hacky. After all, the VS UI would just make some of these kinds of changes to the project file itself.

      Still, I would also love to see more attention given to some of these concerns.

  2. Philipp
    Posted February 27, 2014 at 10:40 pm | Permalink

    Just look at the Eclipse editors. They have XML plain text editors but also Rich editors. For the same file, mind you. All in sync. You can change the XML and it will reflect in the rich editor.
    In VS from the start (VS 6. was my first) you could have a file open only in one editor at a time (rc the infamous example). And instead of VS automatically closing the editor the file is opened with at the moment and open it again with the users choice of editor, it throws a useless error box at you that reads “This file is opened in another editor [OK]“.Its not OK, just offer a button “Close other editor and reopen with…” if you really have to put up a msgbox. And that is just one example of bad UX in VisualStudio.
    But they have the time to implement gamefication and yet another UI theme.

    As for TypeScript… fine. What does it mean to be first-class citizen? Are the APIs of VS not that open that it can support any kind of language (in 2014!). What about CoffeeScript that has been around for years. Nooo MS has to (yet again) invent its own language. Can you even write Windows Store apps with it yet? Doesn’t seem so.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>