A good[ish] website
Web development blog, loads of UI and JavaScript topics
Bower is great! But it only does one thing, that is to manage packages. We’ll need a bit 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 (e.g. Zepto, Scut or whatever library or plugin desired). Meaning, that it's now possible to download any package from the comfort of your command line, past are the 'right click on a link, choose save as' times. Bower can also update packages with the bower update
command.
Start by Installin Bower globally (node/npm is needed):
$ npm install -g bower
cd
into your project and run:
$ bower init
The init
is not mandatory if Bower is only used to pull in packages, it just creates bower.json
file that we need later on.
It'll prompt you with various questions, most of them are very 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 <bob@exmpl.com>) # 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)
bower.json
file is created in the project root, check it out. It can be edited in normal fashion if needed.
bower.json
fileThis is the heart of your Bower, it contains mundane information about the project (name, homepage etc.), along with list of dependencies.
It's needed only when:
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 <bob@example.com>"],
"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"
}
}
Only really interesting bit is the dependencies, the packages a project needs to function.
The syntax for installing is:
$ bower install <endpoint> [<endpoint> ..] [<options>]
If jQuery is desired, it can be first searched:
$ bower search jquery
Choose suitable jQuery package and issue:
$ bower install jquery --save
The --save
flag saves is as a dependency to 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 devDependenciesNow, bower_components
directory is created into project root, and jQuery is pulled in from it's Git repo.
bower_components/
└── jquery
Btw, bower.json
file is not needed for installing packages.
It's really easy to pull in packages with Bower, but the real strength lays 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 instal
And Bower will look into the bower.json
file and pull in all the listed dependencies.
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.
"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.js
Ummm...
Sure I don’t need all of that?
As we see, 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.js
What it does:
grunt-bower-task
copies the main file to /lib
bower.json
: "main": "dist/jquery.js",
bower_components
dir can be now excluded in .gitignore
lib
instead<script src="lib/jquery/jquery.js"></script>
grunt-bower-task
usageConfiguring 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 bower
Now the task copies the main
files from each package to /lib
. The dir structure could looks something like this:
lib
├── jquery
├── zepto
└── yepnope
When grunt-bower-task
is set up, install Bower packages like so:
$ bower install jquery && grunt bower
And off you go, happy pappy.
main
fileIf 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.
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 <bob@example.com>"],
"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 in bower_components
"js"
target dir in ./lib
"dist/zepto.js"
is path to the wanted file in bower_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.js
Nice! We got that problem solved.
Or grunt-contrib-copy would also do the job, it's a task that copies specified files.
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>
Bower is pretty amazing, and couple in with grunt it reaches new heights.
Comments would go here, but the commenting system isn’t ready yet, sorry.