Given that both these methods are not entirely reliable, there is another approach through which you pick up the build target setting directly from Visual Studio, and then use that to bring in a debug or release file.
Here's how. Create two .js files in the project (debug.js and release.js in a js-buildinfo folder) and make sure to exclude them from the end package by setting their Package Action to None instead of Content (right click, select Properties, and you'll see the actions under Solution Explorer).
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.
*/
});
})();
You'd then use BuildInfo.* anywhere in your code you need to differentiate. Better still, encapsulate build-specific stuff in these files as much as you can, e.g. the CurrentApp vs. CurrentAppSimulator, calls to WinJS.Log.startLog, etc.
Then use an MSBuild task to selectively copy one or the other file to a common name in the package (e.g. buildinfo.js). To do this, 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:
<ItemGroup>
<BuildFlagSource Include="js-buildinfo \$(Configuration).js" />
</ItemGroup>
<ItemGroup>
<BuildFlagDestination Include="js\buildinfo.js" />
</ItemGroup>
And then farther down there’s a section that’s commented--you uncomment it and add the 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 enables 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.
But it does work and is the closest I've come to precompilation directive with other languages.