Bower is great, but it only does one thing: manage packages. We’ll need a bit of help from Grunt to reach perfection. Here’s how to install and use Bower, and how to automate the copying of files from bower_components to lib.
Note: I have a follow up article on how to do all this with Gulp: Bower and Gulp: match made in heaven (also)
Bower, "a package manager for the web", a tool that makes
installing packages a breeze (such as Zepto, Scut, or any desired library or
plugin). This means you can download packages from the comfort of your command
line. The days of 'right-click on a link, choose Save As' are over. Bower can
also update packages with the bower update command.
Install Bower
Start by installing Bower globally (Node/npm is needed):
$ npm install -g bowercd into your project and run:
$ bower initThe init is not mandatory if Bower is only used to pull in packages, it just
creates a bower.json file that we need later.
It'll prompt you with various questions, most of which are self-explanatory. Skip any of them with enter. See the comments below for explanations.
[?] name: (test) # This defaults to the directory name
[?] version: (0.0.0) # In which version is your project
[?] description: # Short description of your project
[?] main file: # The main file of your project, in jQuery that would be the `jquery.js`
[?] what types of modules does this package expose? (Press <space> to select)
❯⬡ amd # More: http://requirejs.org/docs/whyamd.html
⬡ es6 # More: http://wiki.ecmascript.org/doku.php?id=harmony%3amodules
⬡ globals #
⬡ node # More: http://nodejs.org/api/modules.html
⬡ yui # Or just press enter to skip this
[?] keywords: # Like tags, if you publish your project
[?] authors: (bob <[email protected]>) # I suppose Bower pulls these from you Git configuration
[?] license: (MIT) # MIT is the default and sufficient in most cases
[?] homepage: # Project home
[?] set currently installed components as dependencies? (Y/n) # You most likely want to say Y to this
[?] add commonly ignored files to ignore list? (Y/n) # Solid Y also
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? (y/N)The bower.json file is created in the project root. Check it out. It can be
edited in normal fashion if needed.
bower.json file
This is the heart of your Bower project. It contains information about the project (name, homepage etc.), along with list of dependencies.
It's needed only when:
- Publishing packages
- Using the
grunt-bower-task(more on that later)
Example Bower manifest file could look something like this:
{
"name": "Test Project",
"version": "2.0",
"homepage": "https://github.com/bob/test-project",
"authors": ["bob <[email protected]>"],
"description": "This is a test project",
"license": "MIT",
"ignore": ["**/.*", "node_modules", "bower_components", "test", "tests"],
"dependencies": {
"jquery": "~2.1.0",
"scut": "~0.10.2",
"unveil": "~1.3.0",
"zeptojs": "~1.1.3",
"yepnope": "~1.5.4"
}
}The only really interesting bit is the dependencies: the packages a project needs to function.
Installing packages with Bower
The syntax for installing is:
$ bower install <endpoint> [<endpoint> ..] [<options>]If jQuery is desired, it can be first searched:
$ bower search jqueryChoose suitable jQuery package and issue:
$ bower install jquery --saveThe --save flag saves it as a dependency in the project. Here are all the
options it takes.
-F,--force-latest: Force latest version on conflict-p,--production: Do not install project devDependencies-S,--save: Save installed packages into the project’s bower.json dependencies-D,--save-dev: Save installed packages into the project’s bower.json devDependencies
Now, a bower_components directory is created in the project root, and jQuery
is pulled in from its Git repo.
bower_components/
└── jqueryBy the way, a bower.json file is not needed to install packages.
Install all the project dependencies
It's easy to pull in packages with Bower, but its real strength lies in its ability to pull in all the needed dependencies for a given project. Say, clone a project from GitHub, none of the dependencies are included into it, they're in their respective repositories. Just run:
$ bower installAnd Bower will look into the bower.json file and pull in all the listed
dependencies.
Using the packages
Bower is only a package manager, not a module loader. Reference packages in normal fashion:
<script src="bower_components/jquery/dist/jquery.min.js"></script>This is where the trouble starts.
The package dilemma
"Bower package" equals exactly to: "its git repository"
Which is how it should be, but, we have problem now. For example, jQuery that was pulled in, created a directory tree like this:
jquery/
├── MIT-LICENSE.txt
├── bower.json
├── dist
│ ├── jquery.js
│ ├── jquery.min.js
│ └── jquery.min.map
└── src
├── ajax
│ ├── jsonp.js
│ ├── load.js
│ ├── parseJSON.js
│ ├── parseXML.js
│ ├── script.js
│ ├── var
│ │ ├── nonce.js
│ │ └── rquery.js
│ └── xhr.js
├── ajax.js
├── attributes
│ ├── attr.js
│ ├── classes.js
│ ├── prop.js
│ ├── support.js
│ └── val.js
├── attributes.js
├── callbacks.js
├── core
│ ├── access.js
│ ├── init.js
│ ├── parseHTML.js
│ ├── ready.js
│ └── var
│ └── rsingleTag.js
├── core.js
├── css
│ ├── addGetHookIf.js
│ ├── curCSS.js
│ ├── defaultDisplay.js
│ ├── hiddenVisibleSelectors.js
│ ├── support.js
│ ├── swap.js
│ └── var
│ ├── cssExpand.js
│ ├── getStyles.js
│ ├── isHidden.js
│ ├── rmargin.js
│ └── rnumnonpx.js
├── css.js
├── data
│ ├── Data.js
│ ├── accepts.js
│ └── var
│ ├── data_priv.js
│ └── data_user.js
├── data.js
├── deferred.js
├── deprecated.js
├── dimensions.js
├── effects
│ ├── Tween.js
│ └── animatedSelector.js
├── effects.js
├── event
│ ├── alias.js
│ └── support.js
├── event.js
├── exports
│ ├── amd.js
│ └── global.js
├── intro.js
├── jquery.js
├── manipulation
│ ├── _evalUrl.js
│ ├── support.js
│ └── var
│ └── rcheckableType.js
├── manipulation.js
├── offset.js
├── outro.js
├── queue
│ └── delay.js
├── queue.js
├── selector-native.js
├── selector-sizzle.js
├── selector.js
├── serialize.js
├── sizzle
│ └── dist
│ ├── sizzle.js
│ ├── sizzle.min.js
│ └── sizzle.min.map
├── traversing
│ ├── findFilter.js
│ └── var
│ └── rneedsContext.js
├── traversing.js
├── var
│ ├── arr.js
│ ├── class2type.js
│ ├── concat.js
│ ├── hasOwn.js
│ ├── indexOf.js
│ ├── pnum.js
│ ├── push.js
│ ├── rnotwhite.js
│ ├── slice.js
│ ├── strundefined.js
│ ├── support.js
│ └── toString.js
└── wrap.jsSure I don’t need all of that?
Bower does one thing, and it does it well. It's not trying to be anything else than a tool that pulls in packages.
From jQuery repo, only one file is really needed:
jquery/
└── dist
└── jquery.jsgrunt-bower-task to rescue
What it does:
grunt-bower-taskcopies the main file to/lib- Main file is the file that is specified in
bower.json:"main": "dist/jquery.js",
- Main file is the file that is specified in
bower_componentsdir can be now excluded in.gitignore- Link to files in
libinstead<script src="lib/jquery/jquery.js"></script>
grunt-bower-task usage
Configuring is easy:
grunt.initConfig({
bower: {
install: {
//just run $ grunt bower:install and you'll see files from your Bower packages in lib directory
},
},
})See more usage and installation instruction here.
After setting it up, try it out:
$ grunt bowerNow the task copies the main files from each package to /lib. The dir
structure could looks something like this:
lib
├── jquery
├── zepto
└── yepnopeWhen grunt-bower-task is set up, install Bower packages like so:
$ bower install jquery && grunt bowerAnd off you go, happy pappy.
What if no main file
If there is no main file, here's what grunt-bower-task does:
- If
"main"files are empty then the whole package directory will be copied to./lib.- When you define
"exportsOverride"only asset types and files specified by you will be copied to./lib.
This happens. For example with Zepto, cause it assumes that every user builds their own version of it, therefore no main file exists, and the whole tree is copied. Bummer. But as alway, there's a way.
Copying specified files only
After Zepto is custom built,
(heres how to do that), only
zeptojs/dist/zepto.js is desired. Pop open the bower.json from the project
root and define exportsOverride there, like this:
{
"name": "Test Project",
"version": "2.0",
"homepage": "https://github.com/bob/test-project",
"authors": ["bob <[email protected]>"],
"dependencies": {
"jquery": "~2.1.0",
"scut": "~0.10.2",
"unveil": "~1.3.0",
"zeptojs": "~1.1.3",
"yepnope": "~1.5.4"
},
"exportsOverride": {
"zeptojs": {
"js": "dist/zepto.js"
},
"yepnope": {
"js": "yepnope.js"
}
}
}It breaks down to:
"zeptojs"the package dir inbower_components"js"target dir in./lib"dist/zepto.js"is path to the wanted file inbower_components
Now if $ grunt bower is issued, it'll create the following directory
structure:
lib
├── jquery
│ └── jquery.js
├── js
│ ├── yepnope
│ │ └── yepnope.js
│ └── zeptojs
│ └── zepto.js
├── scut
│ └── _scut.scss
└── unveil
└── jquery.unveil.jsNice! We got that problem solved.
Or grunt-contrib-copy would also do the job, it's a task that copies specified files.
Other useful Bower commands
Uninstall:
$ bower uninstall <packagename>Publish packages:
To register a new package:
- There must be a valid manifest JSON in the current working directory.
- Your package should use semver Git tags.
- Your package must be available at a Git endpoint (e.g., GitHub); remember to push your Git tags!
- Then use the following command:
$ bower register <my-package-name> <git-endpoint>
Conclusion
Bower is pretty amazing, and couple in with grunt it reaches new heights.