Working with Sass, Bootstrap and Gulp

For frontend developers, the days when you manually linked css files to your index.html are over. Modern workflows needs some compilation steps before having a css file that can be use in development or production. Most notably, sass has become the most important language that extends css functionalities, while gulp has won the battle on the building tools front.

In this tutorial I’m going to show how to use gulp to create a workflow that combines sass and bootstrap the right way.

First, lets create a folder to play called “gulp” (you can call it whatever you want, it doesn’t matter):

Because we need to separate our “source” files from the compiled ones, it’s better two create two different folders called “src” and “dist”.

Inside our “src” folder we should have an “index.html” and a main sass file called “main.scss” where we are going to put all the sass code.

We are going to start with a very simple html file that we are going to improve progressively

Similarly, we are going to create a very simple sass code inside “main.scss” just to test that everything is working.

We are now ready to start working with gulp. The first step is to create the file “package.json” to store all of our npm dependencies using the “-y” flag to accept all the default values.

Next we install the npm packages to use gulp with sass, using the “–save-dev” flag to store a reference in package.json.

Our file package.json should now look like this:

We can now proceed to create our gulp file to automate our building process.

Right now, our folder structure is as follow:

With the gulp file in place, we should create a task to compile “main.scss” and write the result to the folder “dist”.

We can execute the task with the following command:

As a result, we get a new file called “main.css” inside the “dist” folder.

We now have our sass files compiled to css in the public directory but we also need to move our “index.html” to the “dist” folder in order to group all relevant files in one place. To do that, we create a new gulp task called “html”.

If we execute both tasks using:

We obtain the following folder structure:

If we look inside  dist/index.html we immediately see a problem: there is no reference to the css file anywhere. We need to “inject” our newly compiled css file into the html and we can do that with the npm package “gulp-inject”.

We now need to modify our gulpfile to use this new package and, to save some time, find a way to invoke both tasks (styles and html) using a single command.

Several things changed here. First, on line 3, we require the “gulp-inject” package. Next, on line 11 we enforced that the “styles” task to run before the “html” task son we don’t need to call both all the time, calling just  gulp html is enough to execute both in order. On line 12 we decide which files we want to inject, in this case the processed css file. Finally, on line 15, we tell gulp to inject the css file inside “index.html”.

But then again, something is missing. We are telling gulp to inject a file, but we are not specifying where. To do that, we have to modify the index.html file to put some special flags for the gulp-inject package to do its magic.

Now, if we run  gulp html this is what we get:

Ok, we managed to inject the file but it’s not quite right. “index.html” and “main.css” are both inside the same folder so the path for the css file shouldn’t be “/dist/main.css” but just “main.css”. To do that, we define some special options to the inject package inside “gulpfile.js”.

When we run  gulp html again, the index.html changes showing the real path for the css file.

Our example is very simple because we have only one sass file but, what if we have multiple sass files? First we should create a new folder called “styles” inside the “src” folder to store all the sass files.

The file “main.scss” will become the master sass file where the other files will be injected and ideally shouldn’t have css rules other than “@import”. We need to move the content of “main.scss” to “layout.scss” and set some sass rules inside “panel.scss” to verify that both files can share sass variables.

Similar to what we did in “index.html” we need to define some placeholders in “main.scss” to instruct gulp-inject where to inject the others sass files.

Unlike html, gulp-inject does not have a default placeholder for injecting sass files, so we have to help the injector to recognize these placeholders.

First of all, we need to tell the injector which files we want to inject, in this case, we want to inject all files with the .scss extension found in the “/src/styles/” folder (line 6). Next we define the injector options, establishing how we are going to write the import statement (transformFilePath), how to recognize the start and end of the placeholders (starttag and endtag) and that we don’t want a root slash in the import path (addRootSlash).

In the streaming process, we add a new pipe right before the execution of the sass compiler, where we inject the sass files inside “main.scss” (line 20). Notice that for consistency with “src”, we now redirect the resulting css to a “styles” folder inside “dist” (line 22). If we now run  gulp html we can see that the compiled css has all the rules defined in the sass files.

Adding Bootstrap (SASS)

So far everything works great, we can create all the sass files we want and they will always get compiled to a single css file cross referencing all variables, mixins and so forth. But, what if we wanted to use the sass version of bootstrap and have also access to bootstrap internal variables and mixins? What if we wanted to overwrite some bootstrap default variables to take complete control over the framework? I’m glad you ask…

Because we are going to use bower to manage front end dependencies, we need to create a “bower.json” file first to store all of our dependencies. A very similar step of what we did with npm.

If we accept all the default options, we end up with a file like this:

We are ready to download our first dependency: “bootstrap-sass”. We must remember to always use the “–save” flag to store the reference in “bower.json”.

Because we want to have access to bootstrap variables and mixins, we need to find a way to inject bootstrap in our main sass file “main.scss” along with our own sass files. In fact, we should take care to inject bootstrap before our sass files to guarantee that the variables are defined before we try to use it in our sass files. Unfortunately, “gulp-inject” is not the right tool for the job and we must rely in another npm package called “wiredep”.

The wiredep package works similar to gulp-inject in the sense that it looks for placeholders to put the necessary import statements in our “main.scss” file.

Additionally to putting the placehoders, we must change our gulpfile.js to use the “wiredep” package and include it in the piping process.

Whit this minor changes, we are ready to run again  gulp html. If we now open the compiled file we can see that bootstrap is now there on the top, and our css rules are at the bottom of the file.

We now can now safely use all bootstrap variables, mixins and classes in our own code. But there’s still something to be done, we need a way to overwrite bootstrap variables.

This code should be injected before bootstrap itself and should live in its own folder inside “src”. For that, we create a new folder called “global” inside “src”, and a sass file called “variables.scss” where we are going to put the bootstrap variables that we want to overwrite along with their new values.

Bootstrap defines a variable called $font-size-base that has a default value of 14 px. Many other bootstrap variables depend on this variable, son changing it have a huge impact on bootstrap visualization.

Because we need to inject the “global” sass files before bootstrap, we need to define a new placeholder in “main.scss”.

We are now ready to update the gulp file to inject the sass files inside the “global” folder. The process is similar to what we did before when we injected the sass files inside our “styles” folder as can be seen below.

To verify that it’s working, we run  gulp html and inspect the resulting css file.

We can now see that we managed to control bootstrap internals overwriting just one variable.

To wrap up, we can define a new task that deletes the “dist” folder before we start compiling and moving files around. To do that we are going to need a new npm package called “del”.

And we need to modify our gulp file once more. In addition tu using the “del” package, we are going to simplify the command needed to run the task using the “default” task keyword.

Finally, bootstrap is completely integrated into our workflow and we can check it running just  gulp with no extra parameter.

Adding Other CSS Dependencies

Most libraries out there are not written or available in sass, how do we manage those libraries in our workflow?

Because those libraries doesn’t need to be compiled we are going to concatenate them into a single file called “vendors.css”. To do that, we are going to need three new npm packages: “gulp-concat”, “main-bower-files” and “gulp-filter”.

Next we create a new task called “vendors” in our gulp file and make sure is invoked in the “default” task.

The new “vendors” task, grabs the main files of every bower library installed (js, css, sass, etc.) as defined in the bower.json file of every library (line 45), then filters only the css files (line 46), concatenates them in a file called “vendor.css” (line 47) that is then stored inside “dist/styles” (line 48).

Because we need to make sure that this new file gets referenced from “index.html”, we add that file to the injected files in the default task (line 52). Take note that the order of which the files are defined matters and because many libraries relies on bootstrap, we have to include the “vendors.css” file after our “main.css” files were bootstrap lives.

To try it out, we need to download some bower library that has a css file. For this tutorial we are going to use the library “bootstrap-material-desing”.

We can test if everything is working Ok running the command  gulp. As a result we get a new file called “vendor.css” in our “dist/styles” folder that is referenced in “index.html”.

Both css files are very long and could take a while to download when in production, so the next logical step is to use a minifier tool to reduce the total size of the generated css files. For that purpose we are going to use the npm package “gulp-csso”.

Then we modify our gulp file to include the minifier in the process.

Now when we run the  gulp command, we end up with two minified css files in our “dist/styles” folder.

This was a very long post, but there is a long to say about gulp. All files are available on github.

Published by

David Barreto

David Barreto is a Javascript Developer with a Bachelor's degree in Electronics Engineer and a Master's degree in Systems Engineering. He is passionate about developing web apps, teaching programming, discovering new technologies and learning all about software development methodologies. He currently works at Rangle.io in Toronto.

35 thoughts on “Working with Sass, Bootstrap and Gulp”

      1. thanks for this great tutorial! Is it please possible to explain that after creating the layout.scss file and the panel.scss file I move the following contents to main.scss $primary-color: red;
        body {
        background-color: $primary-color;
        }
        and replace this code in the main.scss with the placeholders? I only ask in this section above you mention not having any code in the main.scss but in the example it shows this code in the main.scss, the code for panel.scss and then the placeholders within the same main.scss file.

        When I am running gulp html the only the body styles are there and it is not compiling the styles from panel.scss

        I would really appreciate some help with this as I am struggling to get to grips with this section. Thanks again

        1. ya your’s and mine are in the same condition ? have you got the solution for this problem ??
          and i think the one with the code in the state is the layout.scss which he created at this state but he mistakely written main.scss. I tried his initial code of main.scss moving to the layout.scss and the same css in the panel.scss and just put the // inject:app
          // endinject in the main.scss and run grunt html and even grunt styles but nothing happend. The compile is not working 🙁 🙁

          Any Solution anyone

    1. sincerelly i prefer use bindep. It is very simple to config and very powerfull. wiredep dont solve all the real cases.
      It happened a lot of times i find bower i cant inject , resources missing and bower components in which you can t load optional parts or a specific version for mobile after preprocessing. Bindep is more professional. npm bindep if you want to try

    1. That would be nice but unfortunately I don’t have the time right now to improve the gulp building process. In the meantime check the gulp-angular yeoman generator to get some ideas of how to implement the “watch” task

  1. Hey ! I’m New in sass i’m attached bootstrap .scss file in my main style.scss & it working as normal Is it the way ? to use bootstrap with sass b/c some user attached two time bootstrap file like with html before close head or also in main.scss file i’m confuse which is the right way ?

  2. Thank you very much for your smart and so progressive/patient article.
    But… I have a problem with the injection of scss wich, (hélas…) doesn’t work.
    Should I whrite some @import somewhere ?

    So I tried with your zip folder (thanks again for the share !) : but when I change something in the scss file (the color of the variable for example), it doesn’t have impact the main.css.
    Any idea ?…
    Thanks one more time !

  3. Thank for your post.

    I tried to learning step by step , It work for me.

    But I have some problem about your cb (call back) from gulp-del plugin that you implement

    ————————————————-
    Ex…

    gulp.task(‘clean’, function(cb){
    del([‘dist’], cb);
    });

    after run command line = $gulp

    It will delete index.html on dest folder

    ————————————————–

    Now we think we will delete task clean until you or me or team can fix it

    Refer gulpfile.js on line —> gulp.task(‘default’, [‘clean’, ‘styles’, ‘vendors’], function(){

    we fix my problem by used only —> gulp.task(‘default’, [‘styles’], function(){

    because of task clean still not work for me
    and task vendor still have problem to learning because of bootstrap-material-design fail after $ bower bootstrap-material-design

    I don’t know why ??? that I can not test task vendor

    Thank again for your post.
    Sorry I ‘m very poor english wording , I came from Thailand

    รักนะ จุ๊บๆ

  4. Sorry my friend.

    Refer My post before 1 hr.

    i have problem 2 thing

    1) task clean
    2) vendor css

    Now i can fix vendor problem by my self because I do it wrong something by my self when I tried to do with your post step by step.

    When I back to download your code on GIT and run CMD $ npm install. and $ bower install it no have any problem.

    But task clean still wait action.

  5. Great post, thank you!

    According to this workflow, how would you go about properly name spacing? Reference: http://stackoverflow.com/questions/13966259/how-to-namespace-twitter-bootstrap-so-styles-dont-conflict

    In the main.scss file, I tried the following:

    .namespace {

    // inject:global
    // endinject

    // bower:scss
    // endbower

    // inject:app
    // endinject

    }

    Though, the output renders a double name space in the main.css file:

    .namespace {

    .namespace html {

    }

    }

    Ideas how to do this properly?

  6. Again my friend.

    Sorry

    I found some thing about gunt plugin wiredep

    “wiredep”: “^4.0.0” ——-> current version ($ npm install –save-dev wiredep) not work it will not create index.html file at folder dist

    but your original project is “wiredep”: “^2.2.2” no have any problem sir

    Thank

    1. Final problem from today ….. Good night

      We found version of plugin del [$ npm install –save-dev del] current version is “del”: “^2.2.0”
      The new version I think that effect to delete file of index.html on dist folder.

      If we change back to “del”: “^1.2.0” (Refer your GIT) it no have problem.

      Don’t sure but if we go back from “del”: “^2.2.0” to “del”: “^1.2.0” it no have problem.

  7. remove variable cb from the clean callback with del v2.20 and the “clean” function will create index.html

    gulp.task(‘clean’, function(){
    del([‘dist’]);
    });

  8. Hi David,

    It’s absolutely the best tutorial about using gulp, sass and bootstrap together. Thank you!

  9. Thank you very much for this tutorial. I had a hard time figuring out how all these tools are stitched together, and finally it makes some sense. And all this just to write some CSS… it boggles the mind! I guess it’s not 1997 anymore :-).

  10. Thanks David your tutorial is really great. Looks like Browserify improved on this workflow and removed the need for Bower and now it looks like webpack is even yet another improvement on the Browserify workflow.

    I don’t understand how those others work yet but you helped me understand this process a lot better. Now I’m going to try and use Bootstrap 4 which now is built with Sass but uses the Grunt build tool. Not sure how to navigate through this jungle just yet, but taking the knowledge you shared in this tutorial, I feel confident on taking my next step.

    @ Casey – thanks for your tip, it helped me get back my html file.

    1. You’re welcome. I wrote that post a while ago, now I’m using webpack as well without bower, it’s much cleaner and simple. I haven’t used Bootstrap 4 yet but it’s nice to know that this version is build with Sass instead of Less.

  11. I ran into an issue with “npm ERR! Refusing to install gulp as a dependency of itself” it looks like naming the project “gulp” (mkdir gulp) was causing the circular dependency so I renamed it to gulp-tutorial and it looked to fix it

  12. Hi

    I really enjoyed your tutorial.
    But it seems that I got stucked in a error after trying to add vendors css.
    Every time that I call gulp I receive this output:

    “events.js:160
    throw er; // Unhandled ‘error’ event
    ^
    Error: bower_components\bootstrap-material-design\scss\_variables.scss
    Error: File to import not found or unreadable: bootstrap/scss/variables.
    Parent style sheet: C:/Users//WebstormProjects/sass-bootstrap-gulp/bower_components/bootstrap-material-design/scss/_variables.scss
    on line 42 of bower_components/bootstrap-material-design/scss/_variables.scss
    >> @import “bootstrap/scss/variables”; // from bootstrap node_module
    ^

    at options.error (C:\Users\\WebstormProjects\sass-bootstrap-gulp\node_modules\node-sass\lib\index.js:291:26)”

    Could give me a hand on it? I searched at Google but so far I didn’t find a solution that fixed the problem.

    Thanks

  13. Hi,
    after $ npm install –save-dev gulp-inject I am getting “Error : Cannot find any-promise implementation nor global.promise.”, is there anything I need to do before gulp inject ?

Leave a Reply