Scott Hanselman

Control how your bower packages are installed with a gulpfile in ASP.NET 5

October 17, 2015 Comment on this post [29] Posted in ASP.NET | Javascript | Open Source
Sponsored By

ASP.NET 5 beta 8 is out. Yes, that's a lot of betas, but it's important to get things right when you're doing something new like this. You can find instructions in our documentation for installing ASP.NET 5 beta8 on Windows, Mac and Linux.

ASP.NET 5 uses the NuGet package manager to get server-side libraries but for client-side things we recommend folks use Bower. The most popular JavaScript and CSS libraries are there, and there's no need for us to duplicate them in NuGet. This means ASP.NET 5 folks get to use the same great client-side libraries that other open web technologies enjoy.

In very early builds of ASP.NET 5 we put those libraries in a folder outside the web root (wwwroot) into bower_components or npm_components and then used a gulp/grunt (think MSBuild for JavaScript) task to copy the files you want to deploy into wwwroot in preparation for deployment. However this confused a LOT of folks who weren't familiar with these tools. It also meant another step after installing a new JavaScript library. For example, you'd install angular with bower, then manually edit the gulp file to copy the .js you wanted into the folder of your choice, then run gulp to actually move it. These are common tasks for many of today's open web developers, but have been confusing for ASP.NET 5 users who don't usually work on the command line. So, this was changed a while back and your bower libraries show up right in your wwwroot.

bower stuff under wwwroot

While this is convenient change and great to starters, at some point you'll want to graduate to a more formal process and want to move your bower client libraries back out, and then setup a task to move in just a files you want. Let's take a moment and switch it back the way it was.

Here's how.

Update your .bowerrc and project.json

In the root of your project is a .bowerrc file. It looks like this:

{
"directory": "wwwroot/lib"
}

Change it to something like this, and delete your actual wwwroot/lib folder.

{
"directory": "bower_components"
}

Exclude your source bower folder from your project.json

You'll also want to go into your project.json file for ASP.NET 5 and make sure that your source bower_components folder is excluded from the project and any packing and publishing process.

"exclude": [
"wwwroot",
"node_modules",
"bower_components"
],

Update your gulpfile.js

In your gulpfile, make sure that path is present in paths. There are totally other ways to do this, including having gulp install bower and figure out the path. It's up to you how sophisticated you want your gulpfile to get as long as the result is that production ready .js ends up in your wwwroot ready to be served to the customer. Also include a lib or destination for where your resulting JavaScript gets copied. Could be scripts, could be js, could be lib as in my case.

var paths = {
webroot: "./" + project.webroot + "/",
bower: "./bower_components/",
lib: "./" + project.webroot + "/lib/"
};

Add a copy task to your Gulpfile

Now open your Gulpfile and note all the tasks. You're going to add a copy task to copy in just the files you want for deployment with your web app.

Here is an example copy task:

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));
}
});

Do note this is a very simple and very explicit copy tasks. Others might just copy more or less, or even use a globbing wildcard. It's up to you. The point is, if you don't like a behavior in ASP.NET 5 or in the general build flow of your web application you have more power than ever before.

Right click the Bower node in the Solution Explorer and "Restore Packages." You can also do this in the command line or just let it happen at build time.

image

Looking in this simplified screenshot, you can see the bower dependencies that come down into the ~/bower_components folder. Just the parts I want are moved into the ~/wwwroot/lib/** folder when the gulpfile runs the copy task.

A new flow for my JavaScript

Feel free to share in the comments links to your blog posts on how YOU like your gulpfiles and build process to work!


Sponsor: Thanks to Infragistics for sponsoring the feed this week! Responsive web design on any browser, any platform and any device with Infragistics jQuery/HTML5 Controls.  Get super-charged performance with the world’s fastest HTML5 Grid - Download for free now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
October 17, 2015 1:57
“…for client-side things we recommend folks use Bower or npm.”

Actually npm folks themselves do not recommend npm for client side deployments.

From npm FAQ: “Use npm to manage dependencies in your dev environment, but not in your deployment scripts.”
October 17, 2015 2:29
I meant things like client-side tools and commands. I'll update the post. Thanks for your help!
October 17, 2015 2:49
I like to use gulp-bower-normalize. It allows me to declare the files I want to serve on bower.json and leave the gulpfile intact.

October 17, 2015 3:46
Why not just split asp.net mvc projects into a no major forward support product (WebForms with VS 2012 style sln proj files) and a major forward support product (MVC with npm, ... tools)?

VS is slouching into a mish-mash of opensource command line tools with many hand edited script files. Now may be mostly easy, though inheriting a system 5 years from now will be a costly costly task.

Jon
October 17, 2015 5:24
@Jon: since there is really no upgrade path between old .csproj based projects and the project.json projects, the tooling is already separate. VS still works perfectly fine with older project types, and the newer project types import what features that they need. So I'm not understanding what you're getting at.

All web developers need to be comfortable with npm/node, bower, grunt/gulp, et all. These aren't that new of tools or workflows, and they've largely taken over the entire industry - except the isolated sector of .net development. MS is taking an amazing, and very likely platform-saving move with integrating these tools into their flagship development environment. I think ASP.NET 5 and VS's new tooling secures ASP.NET's position for the next decade, as opposed to it slowly dying out with the wave after wave of younger developers who typically ignore the platform entirely.

It's also hardly a mish-mash, either. The support is incredibly powerful and convenient - and that's coming from a die hard command-line guy (I thought I'd hate the task runner window, but it's actually awesome!). The only concern for me is what happens with newer versions of the package managers/task runners - but I'm sure MS could figure out something along the lines of auto-detecting which version of the CLI each respective tool uses based off of package.json.


@Scott: thanks for the writeup! I actually came across this the other day. To be honest, the new defaults actually confused me, and I'm a huge proponent of using a task runner to copy the files. When I saw my libraries dumped into wwwroot, I thought "oh, huh, is this how MS intends for us to use Bower now? That sucks."

But I was able to locate the .rc file and get things setup the way I wanted to. However, I always feel a little "dirty" about changing stuff like that, and when I first made the change I wasn't sure if the tooling supported such a thing. If only JSON files could have comments, I'd recommend the templated .rc file mentions that it's perfectly safe to change the directory.

Either way, the BETA8 is pretty slick! I was able to put together a quick project skeleton with everything from TypeScript/tsd to Less, a proper watch task in gulp with live-reload, and it worked *almost* flawlessly. There seemed to be a crash that happened half the time I added or removed a package from bower.json or package.json. When it crashed, the next time I started it up and hit CTRL+F5, the webserver would throw a random internal server error at me, until I went back and hit CTRL+F5 again.

Hope that gets sorted out, because otherwise it's looking amazing! Can't wait for RC!
October 17, 2015 9:34
Hi Scott

I would use bower exportsOverride for this because your using bower anyway. Here's an example (using grunt), but it shows the bower override. I have added an override for angular and angular-ui-router.

http://damienbod.com/2015/03/28/asp-net-5-angularjs-application-using-angular-ui-router/


Greetings Damien
October 17, 2015 12:17
Your copy task does not return a stream (or a promise, or use a callback) which means that gulp does not know then it has finished copying.

This is bad as it can make your build unpredictable by starting dependent tasks too early or not returning an appropriate exit code on failure, which causes issues with CI.
October 17, 2015 19:11
I think it makes sense to have the bower components below wwwroot in wwwroot/lib rather than outside in a folder like bower_components because you cannot reference scripts outside of wwwroot.

Instead of processing files from an external folder like bower_components, you can still process them from wwwroot/lib into a different place for production.

So for example in dev you can reference directly files below wwwroot/lib without having to run taskrunner, but for production you could run taskrunner to process just the files you want into a different folder such as wwwroot/js and you can make your scripts reference different files for dev vs production. There is a more elaborate discussion of this on stackoverflow

It should be possible to exclude wwwroot/lib from publishing, so it is basically the same approach as using bower_components except the workflow is easier because you don't need to run taskrunner to copy files for dev, you just use them directly, and then copy them elsewhere for production.
October 19, 2015 7:44
I think quite a few people [1] are moving to using just npm for everything. npm will be fully supporting front end scripts [2][3] so that's an option too.

[1]: http://gofore.com/ohjelmistokehitys/stop-using-bower
[2]: http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging
[3]: http://blog.npmjs.org/post/122450408965/npm-weekly-20-npm-3-is-here-ish
October 19, 2015 10:28
OK. Super naive question here. I notice a lot of Visual Studio 2015 demonstrations using Nodejs stuff like npm. Does this mean we need to install Nodejs on our dev machines, or is Visual Studio somehow invoking its own version of Nodejs? I'm guessing this is so obvious that no-one has pointed it out yet. Cheers.
October 19, 2015 11:00
I agree with Eddie that more and more people using just npm to manage the client side packages. If you combine npm scripts with a toll like webpack then gulp is not required at all. You can see a different approach than the default that uses webpack here. I think I have to write a more explicit post about it. In Reactjs development most examples don't use gulp at all.
October 19, 2015 11:37
Regarding the shortcomings of Bower:
Bower is STILL missing a feature like shrinkwrap (npm) or the lock file (dnu), meaning there is no practical way of locking down every package version of your dependency tree. So every "bower install" is based on pure luck. Oh, there's a PR for that feature. It doesn't get much love. https://github.com/bower/bower/pull/1748

We have removed bower wherever possible from our projects.
October 19, 2015 12:10
For a full working example of this and much more, take a look at ASP.NET MVC Boilerplate.
October 19, 2015 18:39
I've mostly moved from Bower to JSPM for client-side package management. JSPM sets things up for SystemJS, which is a polyfill+value-add for the ES2015 (ES6) module loader, including setting up NPM modules to run in the browser (similar to browserify/webpack) and configuring a transpiler (such as Babel) for modules written in modern JS dialects. It would be great to see some JSPM support in Visual Studio like NPM/Bower.
Max
October 19, 2015 19:24
Making a business case for using VS, its compiler, debugger, project explorer and VS wrapper around bunch of open source tools will be more difficult in the future. Longevity of the development environment, tools, support updates, etc. is a critical concern when staring development of a new solution costing $1mm+.

For mature applications, upgrade and QA re-verification costs are significant burden, measured in tens of man months, and not budgeted for by large organizations for a sizable portion of their portfolio of applications. Most or all of an organization's budget would be spent just upgrading/retesting applications if they upgraded them to the latest VS, tools version, OS version, ...

Jon
October 20, 2015 11:22
A hate speech.

We will soon need a package managers manager to manage all those package managers.

It's all started from the NuGet command line making its way into the VS IDE. And now just look where we are - command lines everywhere, package managers installing another package managers and stuff to minify and bundle scripts...

People. JUST. MINIFY. NOTHING.

And leave SASS\LESS and [script-on-top-of-javascript]script compilers to IDEs, don't turn your machine into a trashcan installing all those things with meaningless names.
October 20, 2015 12:54
Scott,

You are doing it wrong!!

Every bower.json file declares its dependencies and its 'main' files (= which files are relevant).

For instance, this is the bower.json of the angular-bootstrap package:

{
"author": {
"name": "https://github.com/angular-ui/bootstrap/graphs/contributors"
},
"name": "angular-bootstrap",
"keywords": [
"angular",
"angular-ui",
"bootstrap"
],
"license": "MIT",
"ignore": [],
"description": "Native AngularJS (Angular) directives for Bootstrap.",
"version": "0.13.4",
"main": ["./ui-bootstrap-tpls.js"],
"dependencies": {
"angular": ">=1.3.0"
}
}


It spells out what it depends on ("angular": ">=1.3.0") and where its important bits are (["./ui-bootstrap-tpls.js"]).

A plugin like 'main-bower-files' ( https://www.npmjs.com/package/gulp-main-bower-files ) will figure out the dependencies between your packages and put all the important files in a stream which can then be used to

a) copy to the output directory
b) inject *in order* into an html file (if you so require)


npm install main-bower-files




gulp.task('copy', function () {
log('Copying lib files to wwwroot...');

var mainBowerFiles = require('main-bower-files');

return gulp
.src(mainBowerFiles(), { base: './bower_components' })
.pipe(gulp.dest('wwwroot/lib'));
});


In addition you can override the main files in your own bower.json!


Can it be more simple?

Why doesn't MS make this the default behavior instead of tampering with the default bower_components directory?

October 21, 2015 2:09
I use JSPM package manager which works pretty well for Angular2 and React. Dropping any package folders in wwwroot is not a good idea. I opened a ticket here regarding this.
October 23, 2015 14:34
I wish VS started to support project configuration type. I understand the complexity here but still VS users need a way to tie configuration variable into the gulp.js.
October 27, 2015 12:30
Hi Scott,

This article is great. Indeed if I can understand the step back for a huge majority of users that do not grasp this philosophy, this way of separating the sources from what is effectively posted on the web site is the way it should be! So thank you for this clear explanation that will avoid me to be frustrated from this step back.

Frederic
October 27, 2015 17:49
The bower problem I ran into is that VS installs an older version of bower and node in a 3rd party tooling folder. There's no way to update them, and they don't work with some newer gulp plugins (gulp-autoprefixer was my problem).
I'd like to see VS just use the standardly installed node, bower, etc. rather than use older, hidden, non-upgradable versions. The fix is to adjust your 3rd party tooling path setting, but who knows about that setting in the first place, and who knows what other problems that could cause.
October 28, 2015 2:30
@mark: Tools/options/Projects and Solutions > External Web Tools
November 04, 2015 2:08
Have not watched it yet, but Pluralsight published a course two weeks ago about using npm without having to use Grunt or Gulp.
https://app.pluralsight.com/library/courses/npm-build-tool-introduction/table-of-contents
November 12, 2015 8:42
I've read a few comments here detailing it, but I'm kind of surprised to see the new asp.net using bower.

It would make more sense to bundle in webpack and use npm to manage client dependencies. Seems to be the direction things are headed. Especially when you consider that it then becomes way easier to integrate typescript or es6 with your project. Could even be the default!
November 13, 2015 0:08
Not sure if anyone can help me here, but I have a couple of questions about Bower integration:
1) Are there plans to upgrade the version of Bower to something later? The version Visual Studio uses is pretty old...
2) We are planning to define some Bower packages that will not be registered in the public Bower repository. Is there any way to update the intellisense data used in the bower.json editor? That is, we would like to have our custom packages show up in the list as a user adds dependencies.
November 14, 2015 17:21
Hi Scott,

I would like to make a request for another blog post.

I don't like so much that dnvm heavily on the user profile's location.

In my case I have to work with dnvm with several profiles and I would like to rely on only one installation of the environments and the caches for the different user profile I use on the same machine.

Would you elaborate a method in order to achieve this.

I would really appreciate as you always find the right way to do that type of improvement.

Thanks in advance for taking my request in consideration

Frederic
November 25, 2015 1:18
Hi Scott,

Nice article and thank you for your blog, I really like it!

I recently started using npm, bower and Gulp and noticed my files are excluded from the solution. Is there a way to auto-include them (for publish purposes)?

Thanks!
November 25, 2015 4:50
@Max, I too would love to see jspm support in Visual Studio - espcially since I am interested in working with Rob Eisenberg's Aurelia. I just added this suggestion to the ASP.NET user voice: https://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/10854297-add-jspm-package-support

Anyone who is interested to see this can vote at the above link.
January 14, 2016 0:57
Not sure if the Bower_Components can be excluded from Published output by configuration that you have mentioned.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.