Let’s face it. Managing front end dependencies is still a headache. As developers, we have a plethora of options for building dependencies. Some of the tools off the top of my head are Grunt, Gulp, Broccoli, Component, NPM, and probably 5 more have been released since I started writing this post. In this tutorial, I am going to focus on Gulp but I’m sure it can be modified to work with any of the others.
Lately I’ve started a few side projects and wanted to quickly build out a MVP, minimal viable product, and Bootstrap paired with FontAwesome is a great way of doing this. The problem comes in with trying to automate the setup and have a nice clean package. Sure you can use a CDN but that limits your ability to modify variables and makes working offline difficult. By setting up Gulp we have all the sources available to modify and extend as we need.
Tonight after integrating these for the fourth time I thought it would be something good to share with the goal of benefiting others. From this point forward I will assume you have both bower and npm installed. If you do not then just do a little searching for installation instructions for your operating system. Neither should be too difficult.
Bower
The first step is to setup Bower. Create a new local directory and “cd” into it. Next run bower init
and following the instructions. I don’t believe any of the answers to the questions matter as this will only be used locally.
After that finishes install our required bower packages:
bower install bootstrap-sass-official --save
bower install fontawesome --save
By default, this will put them in the bower_components
directory which can be changed if you prefer. I will leave it as default.
NPM
Now we need to setup our gulp dependencies, which pull from NPM. Create a new package.json file and just add an empty object, {}
and save it.
Head back to the terminal and install our NPM dependencies:
npm install gulp gulp-ruby-sass gulp-notify gulp-bower --save-dev
This will install all the needed dependencies in a node_modules folder and also automatically update our package.json file with these dependencies.
Here is an example package.json showing the versions of dependencies I’m using:
{
"devDependencies": {
"gulp": "^3.8.11",
"gulp-bower": "0.0.10",
"gulp-notify": "^2.2.0",
"gulp-ruby-sass": "^0.7.1"
}
}
PLEASE NOTE: – gulp-ruby-sass is going through some changes. To follow along be sure and use the “^0.7.1” version as I did.
Gulp
Finally, we need to setup the gulpfile.js. Create this file and we’ll step through all the settings.
If you’ve looked at gulp files before then you might know they all start by including the dependencies by using the node require function. Here is the start:
var gulp = require('gulp'),
sass = require('gulp-ruby-sass')
notify = require("gulp-notify")
bower = require('gulp-bower');
These are everything we installed in the NPM step above and at this point just included and not actually doing anything.
Next up, I create a config object to hold various settings:
var config = {
sassPath: './resources/sass',
bowerDir: './bower_components'
}
I find by doing this it keeps the rest of the file simpler. The sassPath is the folder where I store the sass files I create. I’m using Laravel 5.0 and as you can see I just put them in resources/sass. These will end up being parsed and put in a ./public directory. Next is the bowerDir which is just the path to the bower_components.
Next let’s setup up our first gulp task for running bower.
gulp.task('bower', function() {
return bower()
.pipe(gulp.dest(config.bowerDir))
});
This task basically runs bower install
but by including in the gulpfile other contributors only have to run gulp bower and have them all setup and ready.
FontAwesome
Now that we have FontAwesome in bower_components we need to move the fonts out and place them into the ./public directory. Here is a simple move task to handle this:
gulp.task('icons', function() {
return gulp.src(config.bowerDir + '/fontawesome/fonts/**.*')
.pipe(gulp.dest('./public/fonts'));
});
All this is doing is taking whatever is in bower_components/fontawesome/fonts/ directory and moving those to ./public/fonts.
Bootstrap Sass
The next piece to the puzzle is setting up Sass and linking bootstrap and fontawesome into our path so our sass files can access them. Here is the task:
gulp.task('css', function() {
return gulp.src(config.sassPath + '/style.scss')
.pipe(sass({
style: 'compressed',
loadPath: [
'./resources/sass',
config.bowerDir + '/bootstrap-sass-official/assets/stylesheets',
config.bowerDir + '/fontawesome/scss',
]
})
.on("error", notify.onError(function (error) {
return "Error: " + error.message;
})))
.pipe(gulp.dest('./public/css'));
});
This task is a little complex but shouldn’t be to0 difficult to follow. The important parts of this task is the loadPath which tells gulp-ruby-sass all the locations it should look for files. The .on(“error” uses the notify plugin to alert something failed in the build.
With this setup our main style.scss can import bootstrap and fontawesome easily. Here is an example:
@import url(http://fonts.googleapis.com/css?family=Raleway:400,700,300);
$font-family-base: 'Raleway', sans-serif;
// Import bootstrap and fontawesome
@import "bootstrap";
@import "font-awesome";
//...
I imported a new font and set it as bootstraps $font-family-base. When bootstrap is later pulled in it will see the variable is defined and use our setting. You can also do this for any bootstrap variables.
Watch and Default Task
Finally, we are almost finished. Now we need a watch task and a default task.
// Rerun the task when a file changes
gulp.task('watch', function() {
gulp.watch(config.sassPath + '/**/*.scss', ['css']);
});
gulp.task('default', ['bower', 'icons', 'css']);
The first is the watch task which just listens for changes in the path and then runs the “css” task. Finally, we have a default task which when called runs bower, icons, and the css task. This is useful so contributors can pull down your code, cd into it, run npm install, and finally gulp. Everything should be easily shared and used.
If you would like to see the final files used for this tutorial take a look at this demo repo. Also, if you have any questions or if anything isn’t clear let me know in the comments.
What an absolutely brilliant post. Everything explained extremely clearly, this is much appreciated!
LikeLiked by 1 person
Hi Eric, I’m getting the following error when I run gulp: gulp-ruby-sass: stderr: ‘sass’ is not recognized as an internal or external command, operable program or batch file.
I needed to install gulp with the -g flag from npm, I tried that with gulp-ruby-sass too but that didn’t fix this error. Any ideas?
LikeLike
You may need to install sass from the Ruby gem first:
`gem install sass`
Then I believe it should work. An alternative would be to use gulp-sass but that changes the gulp css task I included in the post.
LikeLike
Fantastic writeup! Didn’t realise `gulp-ruby-sass` existed, let alone supported loadPath.
One question I had, what is the Bower task for. Is it purely for contributors that want the bower_components to be downloaded when they run gulp for the first time?
LikeLike
Yes that is correct. I just figured it would be one less step for others.
LikeLike
Hey Eric!
Great post! Really enjoy seeing how other developers setup their build systems. Always end up learning a few new things! Really like your config idea for file paths. That definitely will help keep code a little neater!
If you’re curious, check out this post over at Viget (http://viget.com/extend/gulp-browserify-starter-faq) regarding using Gulp & Browserify. It was also insightful to me and cool to learn how to split each task into little task files to help modularize it all a bit more 🙂
Thanks for posting!
LikeLike
Great post Eric. Thanks for this. Everything is explained in an easy to understand way.
LikeLike
Hi Eric,
I’m trying to troubleshoot why I can’t seem to compile bootstrap by using:
gulp.task(‘css’, function() {
return gulp.src(“app/assets/bootstrap-sass-official/assets/stylesheets/_bootstrap.scss”)
.pipe(sass({
style: ‘compressed’
})).on(‘error’, util.log)
.pipe(gulp.dest(‘public/test’));
});
and came across your post while googling around. Like you, I used bower to add the bootstrap-sass assets. But I don’t get any output when running gulp sass. If I point gulp.src to one of my own scss files, it works just fine. Any ideas?
LikeLike
OK, so I figured it out. Turns out you can’t reference files with leading underscores in gulp, so the workaround is to create a custom scss file, import the bootstrap file (sans underscore, even though its in the file name), run gulp against your custom file, and everything is running again. whew.
LikeLike
I have the same issue…but i cant fix it
Can you help me?
LikeLike
I had the same issue, Finally found the bug where it is. It is actually version issue of the
gulp-ruby-sass
version. However the code works forgulp-sass
😊LikeLike
Hi Eric, great post btw but it’s possible show your entire structure project and explain your workflow? Thank you
LikeLike
You can see all the files in this gist – https://gist.github.com/ericbarnes/ac3ae075c97c1073869c
LikeLike
Thanks. Where I can add my custom CSS files? I have compiled the all SASS from bootstrap into public/css/style.css but I want add more files inside style.css..I mean that I want compile with gulp SASS another css/sass out of bower_components folder
LikeLike
I think you just need to use partials and imports in your main sass file:
http://sass-lang.com/guide#topic-4
LikeLike
Yes Eric. Sorry about this noob question. I figured it out now. Thanks for your time writing this tutorial and btw great post!
LikeLike
Good job on this! I am wondering though why you are not using npm for bootstrap and font awesome, bower seems redundant
LikeLike
Why npm? Is better? Can you explain? Thanks
LikeLike
When I create my ‘style.scss’ file in the ‘./resources/sass’ directory I get a sass compile error. It can’t locate the ‘bootstrap/mixins’ partial. What have I done wrong?
LikeLike
Thanks for this great post
I got an error when running gulp:
TypeError: Arguments to path.join must be strings
It semes gulp-ruby-sass syntax has updated:
http://stackoverflow.com/questions/28140012/gulp-typeerror-arguments-to-path-join-must-be-strings
https://github.com/sindresorhus/gulp-ruby-sass/tree/rw/1.0#usage
“gulp-ruby-sass is a gulp source adapter. Use it instead of gulp.src.”
var gulp = require(‘gulp’);
var sass = require(‘gulp-ruby-sass’);
gulp.task(‘sass’, function() {
return sass(‘source/’)
.on(‘error’, function (err) {
console.error(‘Error!’, err.message);
})
.pipe(gulp.dest(‘result’));
});
So I change to gulp-sass https://github.com/dlmanning/gulp-sass
var gulp = require(‘gulp’);
var sass = require(‘gulp-sass’);
gulp.task(‘sass’, function () {
gulp.src(‘./scss/*.scss’)
.pipe(sass())
.pipe(gulp.dest(‘./css’));
});
LikeLike
FYI not sure when the option changed but it is no longer ‘loadPath’ to include other paths, it is ‘includePaths’. Took me forever to debug that, hope this helps the next reader!
LikeLiked by 1 person
Thanks! I’ve updated the post to reflect this.
LikeLike
Great thanks Eric!
LikeLike
Hey, thanks a lot for this tutorial! I think you forgot to update the post! I’ve been scratching my head to why it wouldn’t work, and the problem was loadPath.
LikeLike
Thank you Frank,
you saved my time (couldn’t realize why “loadPath” didn’t work)
LikeLike
Eric,
Can you please show your entire project structure, not just the content of the gulpfile and bower.json files? I’ve looked at the gist, and it only has 3 files.
LikeLike
Yes I can. Give me a few days to put it together.
LikeLike
I have just updated this tutorial and created a new repo with all the code:
https://github.com/ericbarnes/gulp-bower-bootstrap-fontawesome
gulp-ruby-sass seems to be going through some changes and I’m recommended sticking with the ^0.7.1 until v1 is stable.
LikeLike
Thanks Eric!
LikeLike
Great tutorial, thanks. I’ve been using bower for a while; gulp just made the my workflow ten times better.
LikeLike
How to have code blocks like header footer and add them in multiple pages so we change at one place and reflect everywhere
LikeLike
I think you are looking for something different than this tutorial as it focuses only on the css aspect. Are you using a server side language? Or a template engine?
LikeLike
Good article! I am doing something similar but I am not using Bower to manage/install Bootstrap. Instead, I downloaded Bootstrap Sass directly from the website and added the bootstrap folder to my src/scss folder.
I am having issues with the mixins. When I create a new file called _layout.scss and include the following code:
section {
@include make-row();
article {
@include make-lg-column(2);
}
}
Unfortunately, this doesn’t seem to be working as expected. The output is:
section {
margin-left: -15px;
margin-right: -15px; }
section:before, section:after {
content: ” “;
display: table; }
section:after {
clear: both; }
section article {
position: relative;
min-height: 1px;
padding-left: 15px;
padding-right: 15px; }
@media (min-width: 1200px) {
section article {
float: left;
width: 16.66667%; } }
Has anyone else experienced issues with the sass mixins?
LikeLike
That actually looks correct to me from just glancing at it. If you look at make-row() in the source you can see the margin being added and it including the clearfix;
https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/mixins/_grid.scss#L15
LikeLike
It does seem to be working as expected. Sorry for any confusion.
LikeLike
Hi,
I was about to start setting up my env. the way you have described but then I’ve read about Yeoman – is there a generator creating the same configuration as you have described?
LikeLike
Hello Eric,
great post. Inspired by you I’ve prepared the separate repo (https://github.com/pnowy/bimper) with Gulp, Bower, Boostrap Less, Browser-Sync and asset-builder. I’ve also introduce the PHP templating for easier prototyping. I’ve build it on the top of Sage WordPress theme and your Github repo (http://oneslashtoofar.com/2015/04/26/setting-up-gulp-bower-bootstrap-less-browser-sync-with-php-templating/).
I think it would be good to think about some Yeoman generator for that kind of stuff.
Best,
Przemyslaw
LikeLike
Was looking for handeling with Fontawesome and Gulp and you delivered. Thank you for the help.
LikeLike
Just a tip for begignners: You can type npm init and hit enter and follow the instructions instead of create the package.json by yourself.
LikeLike
Awesome!
You saved my searches!
LikeLike
I was curious what path is required for the following lines in style.scss. :
@import “bootstrap”;
@import “font-awesome”;
I’m finding I get an error whenever I add these lines.
Error: /Users/hemant/sites/angular-gulp-kss/src/app/styles/_base:4: error: file to import not found or unreadable: “bootstrap”
LikeLike
This is set by the
loadPath
in the gulpfile. You can see it here:https://github.com/ericbarnes/gulp-bower-bootstrap-fontawesome/blob/master/gulpfile.js#L27
LikeLike
I also get that same error as @Hemant and the loadPath isn’t working. Its the correct directory but it still cant find it to import it.
LikeLike
Eric…awesome #FTW
LikeLike
Hi, great article, but I have a problem with css on run gulp: “TypeError: glob pattern string required”
I have tried to install npm glob, but doesn’t work although.
Could you help me?
LikeLike
Ralph: As noted in the article:
PLEASE NOTE: – gulp-ruby-sass is going through some changes. To follow along be sure and use the “^0.7.1” version as I did.
LikeLike
Thanks key! I needed to change dir in gulpfile too, but is working now 😉
LikeLike
I used the version you outlined above and I still get ” TypeError: glob pattern string required.” I followed all your steps verbatim. Any help is much appreciated. -VS
LikeLike
what “dir” did you change in the gulpfile?
LikeLike
What if you wanted to actually use Bootstrap’s Javascript plugins? How would you compile those to the public directory? Anyone sorted this out?
LikeLike
I assume you are missing a few lines of code in the “Bootstrap Sass” code as you mention “auto prefix” in the text below it but don’t have any code for this?
LikeLike
Sorry about that. I just removed that line now. I originally had it included but removed it to try and simplify the instructions.
LikeLike