I’ll take my Durandal with Intellisense, please


For the past couple of months, I’ve been using DurandalJS, a really great cross-platform javascript framework designed to simplify building SPA web sites.  It’s built on libraries you already probably know and love, such as KnockOut, Require, and Sammy.  It’s been gaining a lot of traction lately, and for good reason.  The framework is very robust and extensible, and Rob Eisenberg, the creator, is incredibly responsive and helpful.

RequireJS is a great library for AMD support, but it currently has no Intellisense support in Visual Studio.  Fortunately, there is a workaround, and that’s what I want to share here.  More specifically, this post will demonstrate exactly what it takes to get the DurandalJS-based Hot Towel SPA project template by John Papa to support Intellisense in Visual Studio 2012.

One word of warning here: currently as of this writing, the solution I am demonstrating involves modifying Durandal modules directly.  Obviously, this will cause difficulties when updating to a newer version of Durandal files.  This may be a bigger issue for some folks than for others, so you’ll have to consider what’s the trade off value in your particular situation.

Download the example:

I created a brand new project using the Hot Towel SPA project template and modified it so that it supports Intellisense in Visual Studio 2012.  This solution depends on NuGet packages, so you’ll need to make sure that NuGet is configured correctly to allow packages to download automatically – this is done in the Visual Studio options dialog.

To demonstrate the Intellisense, I added some XML documentation comments to the services/logger module. I figured this would be a good module to add it to, since it’s required by every view model.

Download the entire solution here.

The details:

Below is a breakdown of the changes made to the Hot Towel SPA 1.0 project template in order to get Intellisense working in Visual Studio 2012:
  • Add require.intellisense file in the same folder as require.js.
  • Named all the modules, including the Durandal ones. Simplest naming convention is to set App/ as the baseUrl and use the remaining path as the name. i.e. durandal/system, services/logger, etc.
  • Modify the require.config statement to set the baseUrl to “/App/”
  • Moved require.config statement to its own file so that it can be referenced by Scripts/_references.js as well as by the main MVC view.
  • Modify Scripts/_references.js to add a reference to both the require.js and require-config.js files. Path here can use ~/ syntax.
  • Modify the main view so that it loads the require.config file (after this move, the require.js and require-config.js script tags could be moved into the ~/scripts/vendor Bundle).

Note: Intellisense still doesn’t work inside the durandal modules where the “./xyz” syntax is used for require statements.  For instance, require(“./viewEngine”) will break Intellisense, but modifying it require(“durandal/viewEngine”) so that it matches the exact name specified in the define for viewEngine.

Sometimes, it takes a user action (like pressing .) to trigger the Intellisense engine to process the require.intellisense file.  As a result, when a new file is opened, it make take a couple of tries before Intellisense starts working.  I haven’t nailed down exactly the pattern, but wanted to mention it.

I didn’t try to explain many of the changes above – partly because my understanding of the details are somewhat limited, and I don’t want to misrepresent why something behaves the way it does.  However, if you get stuck and need some help, let me know, and I’ll try to assist.

Credits: I obtained the require.intellisense file and Script/_references.js ideas from this Code Project article, which helped me greatly.  I’m not exactly sure who wrote the file or where it originated, but it’s the version I’ve found that works reliably for Require modules.