A Beginners Guide to Package Manager Bower and Using Gulp to Manage Components

Bower logo
The Bower bird

Package managers like Composer for PHP and NPM for Node have become essential tools for simplifying a developer’s life. A package manager is a tool for keeping track of what you’ve installed, as well as installing and upgrading packages. They also check for dependencies and compatibility. Bower is a package manager for the web.

The web is built from various frameworks, libraries and plugins. Bower’s job is to make managing these “packages” easy. With Bower you can quickly download things like jQuery and plugins, as well as CSS frameworks and much more.


Let’s Install Bower

Bower uses Node, so make sure you’ve installed it before proceeding to install Bower. You can check if Node is installed by opening up a terminal and running the following command:-

$ node -v

If you get something like ‘command not found’ you will need to install it. You can get it from the Node website.

Now we should be ready to globally install Bower. To do this we’ll use the Node Package Manager (npm) from the terminal:-

$ npm install -g bower

If you’re running this from OSX or Linux you will probably need to run this as an administrator so prepend it with sudo.

Setup Bower for a Project

For each of your projects that you want to use Bower with you will need to initialise it. From the terminal navigate to a project’s folder; something like:-

$ cd ~/projects/my-project

From now on all the commands we’ll be running will be from the project’s root folder. The project needs a file called bower.json. Create one in the project’s folder, the contents of the file should be something like:-

{
  "name": "my-project"
}

Alternatively you could generate the file by running bower init and answering the questions asked. It’s up to you which method you prefer.

We should now be in a position to start installing some packages.

Finding Packages

There are a few of ways of finding Bower packages. You can search via the Bower website or alternatively you can use the command line.

To search for packages from the terminal you use Bower’s search command followed by what you’re searching for:-

$ bower search <query>

For example, to search for jQuery packages:-

$ bower search jquery

Try it yourself. You should see a very long list of available packages.

Installing a Package

To install a package you can use Bower’s install command:-

$ bower install <package> --save

This will download the specified package to a bower_components folder in the project’s root (we’ll look at changing this in a moment). The --save flag tells Bower to add the package to the bower.json file for future reference.

Let’s give it a try and install jQuery:-

$ bower install jquery --save

You should find the latest version of jQuery downloaded to bower_components and the package added to bower.json. The version installed should have been output to the terminal.

If you want to fetch a specific version you can append the version number after the package name:-

$ bower install <package>#<version> --save

So for a specific version of jQuery:-

$ bower install jquery#1.8 --save

If Bower can’t find an exact match it will attempt to offer you a choice of versions to install.

Another neat trick that Bower will perform is that if you attempt to install a package that depends on another one it will download both and make sure the packages are compatible.

Updating Packages

To update your packages simply use Bower’s update command:-

$ bower update

Uninstall a Package

To uninstall a package use Bower’s uninstall command:-

$ bower uninstall <package> --save

The --save flag will remove the package from the bower.json file as well as uninstall it.

bower_components

By default Bower is going to download everything to the bower_components folder. We can change this using the directory setting in the .bowerrc file. If this file doesn’t yet exist you will need to add it to the same folder that contains your bower.json file. This file is a JSON file for defining your Bower settings. To change the folder that Bower installs packages add the directory setting like:-

{
  "directory": "public/vendor"
}

This will cause Bower to download everything to public/vendor/ instead of bower_components.

It may be worth excluding the bower_components folder from your repository if you’re using something like Git by adding the folder to your .gitignore file. Then whenever you pull down your code you can reinstall all the Bower managed packages by running:-

$ bower install

Excluding the bower_components folder will keep the size of your repository small, but not everyone agrees with excluding this; Addy Osmani has put together something arguing for-and-against checking in front-end dependencies which is worth a look when you have time.


Using the Installed Packages

How you use the packages downloaded by Bower is left up to you. One of the neat features of Bower.

One approach is to directly link to assets in the bower_components folder (or whatever you have configured it to be in the .bowerrc file). However, you ideally want to keep the size and number of assets included in your web pages to a minimum. Using a task runner like Gulp can help achieve this.

Managing Components with Gulp

If you’re not familiar with Gulp I recommend you take a look at my Beginners Guide to the Task Runner Gulp before reading on. I’m not going to explain what Gulp is or how it works here.

What I am going to show is how you can use Gulp to take the assets from installed Bower packages and combine them into smaller files suitable for delivering to the end user on the web.

The Gulp examples that follow are going to be using the excellent gulp-load-plugins plugin so that plugins don’t need to be individually declared in the gulp file. If you haven’t come across this plugin yet take a look at my Automatically Load Gulp Plugins with gulp-load-plugins post. The top of the gulpfile will look like this:-

// Include Gulp
var gulp = require('gulp');

// Include plugins
var plugins = require("gulp-load-plugins")({
	pattern: ['gulp-*', 'gulp.*', 'main-bower-files'],
	replaceString: /\bgulp[\-.]/
});

// Define default destination folder
var dest = 'www/public/';

JavaScript

We’re going to be using the main-bower-files and gulp-filter plugins to grab files from the installed Bower packages. So for example, we can retrieve all the main JS files from our Bower packages like this:-

gulp.src(plugins.mainBowerFiles())
	.pipe(plugins.filter('*.js'))
	.pipe(/* doing something with the JS scripts */)
	.pipe(gulp.dest(dest + 'js'));

plugins.mainBowerFiles() returns an array of all the main files from the packages and plugins.filter('*.js') uses gulp-filter to pass only JS files.

Let’s put this in a task and combine all the JS files from the Bower packages appended with JS files from our project then minify everything:-

gulp.task('js', function() {

	var jsFiles = ['src/js/*'];

	gulp.src(plugins.mainBowerFiles().concat(jsFiles))
		.pipe(plugins.filter('*.js'))
		.pipe(plugins.concat('main.js'))
		.pipe(plugins.uglify())
		.pipe(gulp.dest(dest + 'js'));

});

plugins.mainBowerFiles().concat(jsFiles) returns an array of all the main files from the packages combined with files defined in the jsFiles array we’ve defined. Any JS files from our project will be defined in this latter array. We’re then combining and minifying the scripts with the gulp-concat and gulp-uglify plugins.

Running gulp js will create a single minified JS file, www/public/js/main.js.

CSS

We can now do the same thing for any CSS files:-

gulp.task('css', function() {

	var cssFiles = ['src/css/*'];

	gulp.src(plugins.mainBowerFiles().concat(cssFiles))
		.pipe(plugins.filter('*.css'))
		.pipe(plugins.concat('main.css'))
		.pipe(plugins.uglify())
		.pipe(gulp.dest(dest + 'css'));

});

This will output a single minified CSS file called main.css containing all the CSS rules from our Bower packages and project much like we just did for our JS files. However, what if we want to specify the order the CSS files are concatenated? For example, say we’ve installed normalize.css (bower install normalize.css --save); ideally this would be at the top of our CSS file. We can sort the filtered CSS files by piping to the gulp-order plugin:-

gulp.task('css', function() {

	var cssFiles = ['src/css/*'];

	gulp.src(plugins.mainBowerFiles().concat(cssFiles))
		.pipe(plugins.filter('*.css'))
		.pipe(plugins.order([
			'normalize.css',
			'*'
		]))
		.pipe(plugins.concat('main.css'))
		.pipe(plugins.uglify())
		.pipe(gulp.dest(dest + 'css'));

});

This will ensure normalize.css is included before all the other CSS files.

We now have one JavaScript file and one CSS file to include on our webpages.


Final Words

Bower is an excellent tool for developers looking to make life that little bit simpler. You don’t need to use Gulp to work with Bower packages, but I hope I’ve shown how it can make working with Bower easier. Other task runners like Grunt can be used instead of Gulp if that’s your thing. Otherwise you can just link directly to files downloaded by Bower, although you lose the benefits of minimising the size and number of assets to include with a page that you get from using a task runner.

I hope I’ve got you interested in Bower. Go check out Bower for yourselves!

Related Content

Published on


Comments

  1. antonio |

    Hey Andy,
    Thanks for creating such a helpful post. I have been able to get the ‘js task’ to work, but I am having problems with the ‘css task’.

    When the ‘css task’ is run, I don’t get any errors, notifications (from terminal) or any file outputs, (css in this case).
    Here is a gist of what I have thus far.

    https://gist.github.com/antonioOrtiz/2abb5edc57142adb98b2

    I’d appreciate any insight!

    Thanks,
    Antonio

  2. Andy |

    Hi Antonio,

    Thanks for the comment. Glad the post has been helpful.

    I’m not familiar with some of the Gulp plugins you’re using with your CSS task. Does it work if you exclude the mainBowerFiles() so that you’re source is just gulp.src(sassSources)? I would try disabling some of the processes in your task to try and pinpoint where things are failing.

  3. M Kheel |

    Thanks so much! I’ve been searching for a gulp / grunt plugin like this for very long time.

  4. John |

    I’m trying to use this idea to concatenate my backbone.js with bower, yet it never concats in the order of dependency, meaning, for example, backbone-relational is always added before backbone, and causes an error in the console.

    Have you come across a solution to this?

  5. Andy |

    Hi John, have you tried using gulp-order as described above to reorder your JS files?

  6. Corey |

    Hey Andy, would like to also express my thanks and gratitude for such an awesome post. You helped me “connect the dots”!

  7. Dave |

    Hi Andy,
    I’ve installed a repo via Bower and there’s a bunch of different files in there. I need to add two of them to my html file and whilst I can do that manually, i’m using gulp wiredep to do this automatically for me in a task.
    How/where can I define which files from a repo I want to use? It appears to be automatic and I’d like control over it.
    Cheers,
    Dave

  8. Andy |

    Hi Dave, I’m not familiar with gulp-wiredep. The Bower packages come with the files defined in their individual bower.json file. As far as I am aware this can’t be overridden. My personal approach for specifying which files from a package to use is with the main-bower-files and gulp-filter plugins as described above.

  9. vh |

    How can i include multiple files in main tag of package.json ? ex “main”: [ “jquery.flot.js”, “jquery.flot.time.js” ],

  10. James Van Leuven |

    I’m running into an error with gulp-uglify

    my package.json devDependencies:

    “devDependencies”: { “gulp”: “^3.8.11”, “gulp-concat”: “^2.5.2”, “gulp-filter”: “^2.0.2”, “gulp-load-plugins”: “^0.9.0”, “gulp-order”: “^1.1.1”, “gulp-sourcemaps”: “^1.5.1”, “gulp-uglify”: “^1.1.0”, “gulp-util”: “^3.0.4”, “main-bower-files”: “^2.6.2” }

    my bower.json list:

    { “name”: “bookt.in”, “version”: “0.0.1”, “dependencies”: { “backbone”: “~1.1.2”, “bootstrap”: “~3.3.4”, “jquery”: “~2.1.3”, “font-awesome”: “~4.3.0”, “underscore”: “~1.8.2”, “knockout”: “~3.3.0”, “moment”: “~2.9.0” }
    }

    my gulpfile.js:

    var gulp = require(‘gulp’);
    var plugins = require(“gulp-load-plugins”)({ pattern: [‘gulp-*’, ‘gulp.*’, ‘main-bower-files’], replaceString: /\bgulp[\-.]/
    });
    var dest = ‘public/’;

    /* compress js files */
    gulp.task(‘scripts’, function() { var jsFiles = [‘src/js/*’]; gulp.src(plugins.mainBowerFiles().concat(jsFiles)) .pipe(plugins.filter(’*.js’)) .pipe(plugins.concat(‘main.js’)) .pipe(plugins.uglify()) .pipe(gulp.dest(dest + ‘js’));
    });

    /* compress css files */
    gulp.task(‘css’, function() { var cssFiles = [‘src/css/*’]; gulp.src(plugins.mainBowerFiles().concat(cssFiles)) .pipe(plugins.filter(’*.css’)) .pipe(plugins.concat(‘main.css’)) .pipe(plugins.uglify()) .pipe(gulp.dest(dest + ‘css’));
    });

    gulp.task(‘default’, [‘scripts’,‘css’]);

    my error:

    PS E:\hostingspaces\admin2\www\bookt.in> gulp
    [13:35:22] Using gulpfile E:\hostingspaces\admin2\www\bookt.in\gulpfile.js
    [13:35:22] Starting ‘scripts’…
    [13:35:24] Finished ‘scripts’ after 2.44 s
    [13:35:24] Starting ‘css’…
    [13:35:24] Finished ‘css’ after 74 ms
    [13:35:24] Starting ‘default’…
    [13:35:24] Finished ‘default’ after 19 μs

    events.js:85 throw er; // Unhandled ‘error’ event ^
    Error at new JS_Parse_Error (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:189:18) at js_error (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:197:11) at parse_error (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:299:55) at next_token (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:544:9) at E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:415:16 at E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:509:24 at handle_slash (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:485:20) at next_token (E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:538:27) at E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:415:16 at E:\hostingspaces\admin2\www\bookt.in\node_modules\gulp-uglify\node_modules\uglify-js\lib\parse.js:509:24

    I’ve googled it of course, and I’m not finding a solution.
    When I comment out “.pipe(plugins.uglify())” it concat’s no issue, but of course, it’s not minified.

    thoughts?

  11. Anirudh Banarji |

    I also wrote a tutorial and wanted to share it here in case it helps someone http://www.anirudhbanarji.com/getting-started-with-bower/

  12. Håkan Öström |

    Actually it is possible (as Dave asked) to define which files to include (or exclude) from individual bower packages when using main-bower-files. Take a look at the Overrides option.
    https://github.com/ck86/main-bower-files#overrides-options

  13. Shane |

    To anyone having issues with the CSS:

    The plugin gulp-uglify is for JS only, therefore trying to compress CSS with it throws an error.

    Use gulp-minify instead!

  14. Shane |

    Excellent tutorial by the way!

    This stuff can be extremely intimidating for someone just dipping into bower and gulp, and you did a great job taking away that intimidation!

  15. Dolorian |

    Very nice and helpful tutorial! It really helped me see Bower + Gulp in a different light (was rather skeptical about their utility before).

    Something I am not quite clear on yet, what can one do in the case of jQuery plugins like Fancybox and Flexslider or an utility like Font Awesome which not only have .css and .js files but also have a folder with images (or fonts in the case of Font Awesome)? How would one go about setting up a task (or tasks) to handle these modules?

  16. Kevin |

    Andy, is there any way you (or anyone here) could consider making a super simple repository with a basic structure, package.json, gulpfile.js with two or three bower components installed? For the life of me, I can’t get it to work and I’m sure I’m missing something rudimentary.

    I keep getting an error ‘TypeError: Cannot read property ‘on’ of undefined at DestroyableTransform.Readable.pipe’

  17. Kevin |

    OK, after almost thinking I was going completely insane, I realized that I was using gulp-load-plugins v. 0.2.0

    In the readme, I see that the camelize didn’t default to true until 0.3.0

    Thus I had to declare `camelize: true` in the options for `gulp-load-plugins` (or update gulp-load-plugins)

    Thanks for the writeup!

  18. Owen |

    Hi Andy,

    Just wanted to say a big thanks, as other have said, there’s a lot to get to grips to with Bower and it’s not intuitive to begin. Really helpful stuff.

  19. Digimix |

    Hey Andy, thanks for putting together this Bower/Gulp great tutorial! I’ll be sharing it as a reference during some upcoming training sessions.

  20. Andy |

    Hi Digimix, thanks. Good to know it is useful and getting shared.

  21. C.S. Rhymes |

    Thanks for this article. I have been looking at using Bower for a while now and this article is a great introduction explaining what it can do and how you can use it!

  22. Joel Duckworth |

    Thanks for your article, I ran into issues because your use of plugins.filter was using
    “*.js”
    instead of
    “**/*.js”

    Otherwise the filter doesn’t pick up the files in subdirectories from mainBowerFiles

  23. Baymediasoft |

    Excellent tutorial!

    Could you please explain when deploying web server what need to do?. The path in ref=“bower_components/bootstrap/dist/css/bootstrap.css”> isn’t really helping then, correlated to the ease of using a CDN. I have so far seen no Bower tutorial mention this part, what to do when files go on the server.

    Thanks

  24. Neil |

    This is great but once i’ve ended up with the main.js and main.css files what about references in those to other assets like font files, images, svg’s etc? Those file path references will surely all be incorrect now as the assets are still located in the depths of the bower-components directory and the new main.js/.css files are in (most likely /public/assets).

    Any suggestions about how to make these secondary assets link up or move them to /public/assets but at the same time updating the references in main.js/.css ?

    Thanks!

  25. Dallas |

    This was super helpful. Thanks!! Some interesting things I learned — if your bower package JSON is messed up, it’s possible to have a gulp task look like it ran correctly but not generate files or throw errors. Also, in case it helps anyone, using pump instead of .pipe is great for debugging. Another simple way of debugging was for me to just print out to the console which directories were being included with jsFiles. I’d never worked with these tools before, so even simple things like that helped me understand what each piece of the commands were doing.

  26. Dallas |

    One more thing — if you’re having trouble getting main-bower-files to include something you want, such as Bootstrap’s CSS files, check to see if that package is specifying the files in their Bower file. If they aren’t but the file exists, you can use an override in your own bower.json file to include them. https://github.com/twbs/bootstrap/issues/16663

Leave a Comment
  • You will need to preview your comment before you can submit it.