Last Updated: 7/14/2015

Since 2010, the Microsoft development community has been using NuGet for package management in Visual Studio. Prior to this, developers would’ve entered into a laborious voyage with their favorite search engine in an attempt to locate the necessary project files. NuGet set out to streamline that daunting process. Say you’re creating a new ASP.NET MVC project. NuGet has been your crutch for acquiring the necessary MVC bits and static files; and, while it has served many of us well, it has left ASP.NET developers something to be desired in client-side asset management. You see, NuGet allows the package author to determine the locale of files placed into the project. The package author for another library you install may have conflicting opinions of conventions to be followed. Often times, the result is that the coveted Content and Scripts directories become a dumping grounds. Thus, enforcing reasonable standards within these 2 folders becomes challenging. If your development team wants to abolish this constraint, a package manager such as Bower (or perhaps NPM) becomes more attractive.

NuGet has fallen out of favor with the majority of the modern, open web community at large. It requires the author to possess an intimate understanding of how to create and publish a package to the NuGet feed for others to begin using it. Each time development on a new release is completed, the package must be republished; and, since not everyone is a Microsoft fanboy, NuGet loses its luster. From a SPA framework maintainer’s perspective, for example, there is little value in publishing to a package repository with a reach limited to the Microsoft developer community. It’s an additional hurdle which must be cleared to deliver an exciting, new product to the intended audience.

In the often overlooked world of enterprise development where deadlines are constantly looming, NuGet could be a problem; here’s why. Take the ever popular KnockoutJS library as an example. I was using the 3.2 release, for data-binding and reusable web components, in a large ASP.NET MVC project; and, version 3.3 had just been released. This particular release boasted some attractive enhancements which I wanted to take advantage of before delivering the application for testing. As you might have already guessed, it became available immediately via Bower. Unfortunately, I was still using NuGet and hadn’t yet ventured into the Bower craze. Now I was caught in a holding pattern for a few weeks, while the team was looking for some free time to create an updated NuGet package. It became clear that NuGet was a low priority afterthought, and a well-justified afterthought at that. One of the KnockoutJS core team members, Ryan Niemeyer, confirmed that NuGet would be updated eventually:

Bower addresses this problem by pulling the required assets directly from the project’s GitHub repository. Once a release is tagged, it becomes generally available.

Recently, I was engaged in a conversation regarding Twitter Bootstrap. At the time of writing, there is no official NuGet package available; although, an issue was opened in the official project’s repository with hopes of changing this. I fully understand that large enterprises are technological dawdlers and, as a result, have a white-knuckled grip on NuGet; however, it’s shortsighted and irresponsible to ignore the inevitable. NuGet has been dethroned because there’s a better, more widely adopted tool for the job. Knowing that Microsoft’s official recommendation is to use Bower, I felt inclined to leave my 2 cents. Fortunately, Scott Hanselman dropped in to confirm my statements in that GitHub issue thread:

…better to use Bower or npm, that’s what they are for. NuGet is for compiled .NET binaries.

Thank you, Mr. Hanselman, from a “lesser Scott.”

At this point, you may be thinking that Bower is worth taking for a test drive in your next ASP.NET application. If that’s the case, read on. Before you do, please don’t misinterpret my message. NuGet is still a powerful tool of great value for the appropriate use case, but like any piece of technology, it must evolve to survive. In its current state, there exists excessive friction between the package author and the package manager itself. It’s my opinion that this is the single biggest reason why NuGet has been dethroned as the defacto client-side package manager in the Microsoft development community.

Using Bower without Visual Studio 2015

Let’s assume you’re using Visual Studio 2012 or 2013 and want to begin using Bower to start your transition to Visual Studio 2015/ASP.NET Core 1.0. First, install Bower via NPM:

npm install –g bower

Git for Windows installationWait a minute! You’re telling me I have to install Bower, a package manager, with NPM, another package manager? That’s correct. If you’re unhappy with that, the good news is that NPM can often be used as a replacement for Bower. If you do decide to stick with Bower, install Git as well. As a Windows user, you’ll need Git for Windows, and there’s a useful Microsoft Virtual Academy course which outlines how to install and configure it. Don’t have time to watch the course? The most important detail is to choose the radio button which is selected in the screenshot to the right. Also included in that MVA course are instructions for Linux and Mac. Keep in mind that not every Bower package requires Git, but it’s best to install and not fret.

Now that Bower and Git are installed at the system level, navigate to your project’s root directory and create a bower.json file:

bower init

What ensues is a series of questions which must be answered to build the bower.json file:bower init

Answer yes to the “Looks good?” question at the end, and the file is created. A preview of the file’s content is also provided in the console window.

There’s another important detail to consider. If you’re working behind a corporate proxy server, Bower offers a couple of configuration settings that you’ll likely need to change before a package installation will succeed. Those settings are proxy and https-proxy. Set them inside of a .bowerrc file at the root of the project:

{
	"proxy":"http://<user>:<password>@<host>:<port>",
	"https-proxy":"http://<user>:<password>@<host>:<port>"	
}

For me, this was the most painful aspect of configuring Bower. Tweak your firewall rules, and this configuration becomes unnecessary. Now you’re ready to install your first package. Let’s install Bootstrap:

bower install --save bootstrap

The --save option is important, since it will add the package name and version number to the dependencies section of the bower.json file:

  "dependencies": {
    "bootstrap": "~3.3.5"
  }

This will allow any other developers on the team to fetch the requisite Bower packages by issuing the following command:

bower install

By default, all Bower packages will be downloaded to a bower_components folder at the project’s root. Of course, this name can easily be changed to something else by using the directory setting.

Solution ExplorerUpon expanding the bower_components folder, you’ll see 2 folders: bootstrap and jquery. Since jQuery is a dependency of Bootstrap, it pulled that package in as well. It’s worth mentioning that if you use NPM 2.x instead of Bower for client-side package management, the dependency tree may not be flattened. It’s commonplace to see node_modules folders nested several levels deep. There are several tricks to resolve the issue, one of which is using an NPM package called flatten-packages. Also check out Mads Kristensen’s Flatten Packages extension for Visual Studio. Version 3 of NPM aims to flatten that dependency tree as a remedy to the 260-character path limitation in Windows.

One last consideration is linking to the required assets within the application. Some developers are perfectly fine with directly referencing files in the bower_components folder. Personally, I prefer to use Gulp to copy only the necessary files to another folder, since I’d rather not commit the entire bower_components folder to my Team Foundation Server project. To solidify that practice, it’s a great idea to mark the bower_components folder as ignored from source control with a .tfignore file. If you’re using Git, a .gitignore file will accomplish the same thing. If you think about it, this is consistent with the NuGet Package Restore functionality.

Now it’s safe to uninstall the corresponding NuGet package. From this point forward, only use NuGet for your .NET binaries, such as Entity Framework and the server-side components of ASP.NET MVC. Why only the server-side components? As of Visual Studio 2015 RC, Bower is used to install the client-side assets required for MVC, such as the jQuery unobtrusive validation JavaScript files. The same is true of libraries such as SignalR.

How Does Visual Studio 2015 Ease the Pain?

With the advent of Visual Studio 2015, Microsoft is embracing some of the open source community’s most prominent tooling. Bower and NPM have become first-class citizens with seamless integration into Solution Explorer and have received NuGet-esque package restore features within the IDE. The JavaScript task runners (Grunt and Gulp) which would be used for wrangling Bower and NPM files are integrated into Task Runner Explorer. Extend Task Runner Explorer even further to support the launching of scripts defined in NPM’s package.json file by installing Mads Kristensen’s NPM Scripts Task Runner extension. And to make all of this possible, the foundational tooling (Node.js, NPM, and Git) is installed along with Visual Studio. The change doesn’t stop here.

Microsoft recognizes that ASP.NET developers have been inundated with foreign matter in this release. They also recognize this as an opportunity to win the hearts of those from non-Microsoft communities who have traditionally sidestepped Visual Studio. To appease both crowds, it’s been made equally productive to work from either the command line or the IDE on any platform.

In an ASP.NET Core 1.0 application, there’s a wwwroot folder which houses all “servable” files. If using the default template, you’ll find a robust Gulp task which copies the Bower files to a wwwroot/lib folder. As an aside, Grunt was the default task runner in earlier CTP releases. Below is the pertinent task from the default Gulp file. Prior to Visual Studio 2015, you would’ve had to write something similar yourself.

gulp.task("copy", ["clean"], function () {
    var bower = {
        "bootstrap": "bootstrap/dist/**/*.{js,map,css,ttf,svg,woff,eot}",
        "bootstrap-touch-carousel": "bootstrap-touch-carousel/dist/**/*.{js,css}",
        "hammer.js": "hammer.js/hammer*.{js,map}",
        "jquery": "jquery/jquery*.{js,map}",
        "jquery-validation": "jquery-validation/jquery.validate.js",
        "jquery-validation-unobtrusive": "jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
    };

    for (var destinationDir in bower) {
        gulp.src(paths.bower + bower[destinationDir])
          .pipe(gulp.dest(paths.lib + destinationDir));
    }
});

Something else Visual Studio 2015 does for you is disguise the bower_components and node_modules folders in Solution Explorer. These are rolled up into the Dependencies node under Bower and NPM, respectively. If the thought of using the command line makes you cower, have no fear. Simply add new, colon-delimited key-value pairs to the bower.json file instead of issuing the bower install <package_name> command.

What I’ve described in this section only scratches the surface. Rather than rehashing content that’s already well documented, I’d recommend reading through the ASP.NET Core 1.0 Client-Side Development documentation. Don’t just take my word for it that Visual Studio 2015 reduces the friction between the developer and the tooling; try it for yourself. Only when you’ve done things the more difficult way can you truly appreciate these enhancements.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s