Having spent the vast majority of my career in the front-end space, there has always been a thirst for better processes and management of resources. For those who have long histories with HTML and CSS, you remember the days of keeping folders of code snippets, our personal library of sorts, the cool code we wrote and wanted to have at the ready for our next project.
Sure there were desktop apps that tried to manage this for us, journler was my tool of choice back in those days. I have also seen some use Google Docs and other document and snippet managers, but they never really worked. And let us never forget all those really crappy websites that were supposed to be our saving grace. In the end, managing assets on the front-end has been nothing but a total fail.
When I began working with a Rails team, I was introduced to better solutions for managing libraries of reusable front-end code. Not to mention, this was my first exposure to Git and Github. I'll never forget the day I woke up at 3am and said, "I want to git init
my LIFE!"
What happened next are the events that changed my life. Anyone who knows me, knows I am addicted to Sass. For the first time I was able to create really reusable components for CSS. The very concept was revolutionary. In Ruby, we have Gems, but creating reusable modules for Sass didn't fit the standard Gem model, it was difficult to get a Sass library into the ecosystem.
Compass to the rescue! Through some additional Ruby hacking, the well known Sass framework invented a solution called 'Compass Extensions'. This was AWESOME! This was AMAZING! This solved ALL my problems. This limited my sandbox to always having a Ruby dependency ;(
Unless you live in a hole, you are well aware that the JavaScript revolution is all around us. Many of the amazing concepts I discovered in the Rails ecosystem are now bursting out into the JavaScript space allowing for a greater distribution of awesome. The three pillars are; Yeoman, Bower and Grunt.
The problem I need to solve is; what is the best way to get some library code up on Github and make it easily accessible to users without having to clone the project? Because, that's pretty lame, right?
Initially I came across generator-sass-boilerplate, a 'Yeoman generator for quickly scaffolding out Sass styles'. This is a very interesting approach for creating a complex library and allowing the user to customize the install. But for a simpler library of code, maybe just some functions and mixins, this is way to much overhead.
Fast forward to now. I recently came across new posts that really break down what Bower is and what it is best at. And it hit me, this IS the answer!
For those not in the know, Bower is an extremely simple solution for front-end package management.
It offers a generic, unopinionated solution to the problem of front-end package management, while exposing the package dependency model via an API that can be consumed by a more opinionated build stack.
The beauty of Bower is held within it's simplicity. Bower has a registry, but it's not 100% necessary. The common command is bower install <package>
where <package>
can refer to a large number of options, thus making it dirt simple to just share some code. NICE!
Sticking with the 'dirt simple' theme, you can use Bower to easily pull a repo into your project without having to clone it. Even if it doesn't have a bower.json
file.
For example Stipe, a Compass Extension library I wrote, is not Bower aware at all.
$ bower install git://github.com/Toadstool-Stipe/stipe.git
Run that command in any folder and you will pull in the entire repo with no Github history. This alone is pretty interesting.
To get started, it's simple really. Assuming that Node and npm is installed on your local box, run:
$ npm install -g bower
I won't go into exhaustive detail here, but 99% of the time you simply need to run:
$ bower install <package>
As stated above, there are alternate install options, but the primary solution is to have a bower.json
file in the repo and have it registered with Bower.
If you have a bower.json
file in your project, explained in the next section, you can add the --save
flag with the install and this will add the library as a dependency in your project. Sweet.
When you distribute the project, a user who clones it only has to run $ bower install
and it will pull in all the external resources. Nice!
This new system of creating and distributing resources raises an interesting question; do you commit all your bower packages or not? In the Ruby world, Gems are not actually part of the project, but dependencies of the project, and never committed to the project's version control. In this new JavaScript world, Node and Bower package dependencies are referenced via a manifest, much like the Gemfile in Ruby, but are actually installed into the root of the project directory.
There is a whole discussion on this topic. I look at it this way, when you install a Bower library, are you leaving this as a dependency or are you making modifications?
The choice is up to you, the arguments are strong on either side. In a situation where you are actually forking the code you installed, then the answer is pretty clear, it should be committed to the project or you need to fork the dependency.
Creating a new Bower file is again, really simple.
$ bower init
In the CLI, this will initiate a series of questions, the answers of which will be plugged into the new .json
file it creates. Put as much in as you want, but all you really need is illustrated here:
{
"name": "your-project",
"version": "0.0.1"
}
And that's it really. You have just created your first Bower resource library. Now go forth and build! Build out your resources, documentation, etc ... your package is ready to go at any time.
For easy testing, remember the $ bower install git://github.com/ ...
trick? Run this against a new repo and see how it installs.
Be mindful of this step and what the package contains. In my opinion, I see Bower as a great way to distribute smaller, specific libraries of code. When I pull in your Bower package, do I really want all your documentation, tests, demonstration resources, etc ... As an example, I am going to pick on the Bourbon kids here, run:
$ bower install bourbon
Running this installer, you will get the whole repo. I don't want the whole repo, all I really want is what is in the dist/
dir. To solve this, another developer forked Bourbon and created a new repo called bower-bourbon:
$ bower install bower-bourbon
Running this install you actually only get what is in the dist/
dir. But are these forks reliable? Ohh open source, you are a wild one.
UPDATE: It's been brought to my attention that using the Bower install of Bourbon pulls in it's 3.2 Beta and appears not to be fully functional. This section was not intended to say "bad Bourbon" but to simply illustrate that in some cases, using Bower, you will get more of the library then you really want.
Once you are ready for release, register it with Bower. The criteria is pretty simple:
- Make sure your repo has the
bower.json
file - You must use semantic versioning
- Your package must be available at a Git endpoint, e.g. Github
Once you have all of that, run this command with your new package name and the Git endpoint:
$ bower register <my-package-name> <git-endpoint>
Registration is painless. Once you get the green light on everything, give it a test and do a $ bower install <my-package-name>
Bower and Sass libraries are an amazing pairing. There are small repos all over Github where the complexity of making them a Ruby Gem/Compass Extension was just to much overhead. You are required to either fork, clone, or god forbid, copy and paste code into your project. What? Are we not civilized?
In the Ruby world, developers are used to having Gems and Compass Extensions installed in a safe, *untouchable location. The new Gem is added to the Gemfile and we simply reference the library in the project.
*Untouchable is a frustration with many developers. Importing Sass libraries that they did not have control over, or were unable to modify, that actually output CSS can be very frustrating.
In the new JavaScipt world, the library is added to the bower.json
manifest or simply installed, but instead of it being in a obscured location, it is installed into the root of the project. This keeps things simple from an install perspective, but this means our Sass imports are in relative directories. Not a big deal, but different from what we are used to.
So, what does a Sass Bower package look like? Let's take a simple project I created called, sass-icon-fonts. This package is simply a couple of mixins, one that allows the developer to easily create a @font-face
set of rules and another is the ability to quickly generate a series of icon-font rules. The mini library comes with instructions and a very simple API.
Now, let's imagine you are building a Node project and you want to use this package as a resource, run:
bower install sass-icon-fonts --save
This installs the package and adds the dependency to your bower.json
file. Located at the root level of the project is your sass/
directory, within that is your application.scss
file. At your root is the bower_components
directory. For your application.scss
file to access the new library, you will need to import a relative path to the library, as illustrated in the following:
@import "../bower_components/sass-icon-fonts/_ico-font.scss";
There is nothing wrong with this, it's just different from the @import "compass";
we are all used to. In many ways I have a preference to this. I have complete control over my dependencies and I can import all or, depending on the library, a few of the files I want.
Going back to the Sass Icon Fonts library, it is set up in such a way that I can import both mixins easily, or I can simply import only the mixin I want, as illustrated in the following import statement:
@import "../bower_components/sass-icon-fonts/mixins/_ico-fonts.scss";
Looking back at the Bourbon library, it is also set up in such a way that I can be really selective on my own as to what I want to import in my project without waiting for a special API to allow me to do so.
While the previous example works, while I found this acceptable, I didn't really find it awesome. Digging more into the Grint-Sass API I discovered the includePaths function. This allows you to set an import path to include.
Seeing that this repo doesn't really have a good example how to use this, it was easily dismissible. So, how does this work?
Basically, this needs to be referenced in your Grunt file as an option within the Sass function.
options: {
includePaths: ['./bower_components/bower-bourbon']
}
Now that you have this in your Grunt file, you can simply reference the library's main manifest file with a simply Sass import, like so:
@import "bourbon";
note: the previous example is using the alternative to the Bourbon library, Bourbon for Bower.
If you find yourself behind a firewall that does not allow for the git://[repo]
protocol, there is a fix for this. First, I suggest maually doing a clone using the https://[repo]
protocol to make sure that this is really the issue. If the https://[repo]
protocol works, then you may want to make the following update:
git config --global url."https://".insteadOf git://
Thank you Stack Overflow!
When I say I want to Bower all the things, I mean just that. Now understanding Bower, I am looking at simple package management in a whole new light and I hope that you do to.
No more forking, cloning, deleting .git/
directories just to include a library into a project. I am looking at creating Sass modules in a whole new light as well. Not that Compass extensions were difficult, but Bower frees me of multiple dependencies. Something that has been a real issue on many projects.
one more thing, add this line into compass configuration file
config.rb
so this
will become this