Ember-cli is the new hotness in the Ember world for generating new applications. The build process for ember-cli is provided by broccoli, a relatively new build tool. Trying to get a Sass version of Twitter bootstrap to play nicely with ember-cli turned out to be a bit of a challenge. Both ember-cli and broccoli are under heavy development, so I imagine that the process for using something like bootstrap-sass will become much easier in the very near future. The solution presented here is a quick and easy way to get things working today, but hopefully there will be an easier and more elegant long-term solution.

UPDATE : This is old and wrong

This article was written for ember-cli version 0.0.25. Version 0.0.27 is out now and things have gotten much easier. Please see this post about how to do this in ember-cli 0.0.27

A new app

For purposes of demonstration let's start with a clean new app. (You can find a complete repo of this example here.)

$ ember new ember-cli-bootstrap-sass

Easy peasy!

Sass

Out of the box ember-cli/broccoli doesn't come with the ability to deal with Sass files. So we need to install a broccoli extension.

$ npm install --save-dev broccoli-sass

At this point we can move app/styles/app.css to app/styles/app.scss and the build process will automatically detect that it should be compiled with the broccoli-sass extension.

You can see that this is working by moving the file and updating it to look like this:

html, body {
  margin: 20px;
  h2{
    text-decoration:underline;
  }
}

Then you should see something like this:

Bootstrap

Now we need to find a sass version of bootstrap and get it into the project somehow. After a quick search on bower.io it looks like boostrap-sass-official is the way to go. So we can install that into the project by running this command:

$ bower install --save bootstrap-sass-official

At this point, you can include bootstrap at the top of app.scss to get bootstrap included.

@import 'bootstrap';
html, body{
  ...
}

The bad news is that now you'll see a build error.

It's a big hairy error message, but the important part says this:

file to import not found or unreadable: "bootstrap/variables"

The issue is that bootstrap doesn't come as one giant scss file, rather there is the main bootstrap.scss file, and then it includes dozens of additional scss files. Broccoli is able to find the main file, but it doesn't locate the additional files that bootstrap needs.

At this time there isn't a way to tell the ember-cli build process where to look for additional files. (Maybe there is a way, and I just couldn't locate any information about it?) So, what we need to do is to stop the built in process from trying to compile the sass since it doesn't know where to find the bootstrap partials. Then we'll implement our own pipeline to compile the sass with all of the partials.

Preventing ember-cli from handling scss

Ember-cli watches for files with the .scss extension and autmatically passes them through a sass compiler. I haven't found a way to prevent that from happeneing, so my solution was to rename app.scss to app.custom_scss. You can use whatever other extension you want, it just can't be .scss or .sass. (This is one of the ugliest parts since it will likely doink with syntax highlighting.)

$ mv app/styles/app.scss app/styles/app.custom_scss

More bad news is that ember-cli expects app/styles/app.css or app/styles/app.scss to be in place, so we need to leave an empty file there for it to find.

$ echo "/* See app.custom_scss */" > app/styles/app.scss

At this point you should have a passing build, but since we haven't setup compilation for app.custom_scss yet you won't have any styles.

Compiling app.custom_scss

Now we can update Brocfile.js to add our own custom sass compilation step.

First you should remove the last line of the default Brocfile.

// Remove this line
module.exports = app.toTree();

Then replace it with these lines:

// Import a couple of modules;
var compileSass = require('broccoli-sass');
var mergeTrees  = require('broccoli-merge-trees');

// List all of the directories containing SASS source files
var sassSources = [
  'app/styles',
  'vendor/bootstrap-sass-official/vendor/assets/stylesheets'
]

// Compile a custom sass file, with the sources that need to be included
var appCss = compileSass( sassSources , 'app.custom_scss', 'assets/app.css');

// Merge the ember app and the custom css into a single tree for export
var appAndCustomDependencies = mergeTrees([app.toTree(),appCss], {
  overwrite: true
});

// EXPORT ALL THE THINGS!
module.exports = appAndCustomDependencies;

We also need to install one more broccoli extension to make this work.

$ npm install --save-dev broccoli-merge-trees

Now when you run ember build you should have a file in dist/assets/app.css that contains your own styles and all of the bootstrap sass compiled down to css.

You can see that the sass mixins are available by updating app/styles/app.custom_scss to look like this:

@import 'bootstrap';

h2{
  @extend .text-primary;
}

Now your running app should look something like this:

The End

Well, it's not all that pretty, but it works. I've put together a demo repo and I'd love to hear comments and criticisms on this approach. Please tweet at me or send me an email if you have any feedback. Now I'm off to read some ember-cli source code to try to figure out how to make this a smoother process. Maybe I'll have a PR for something soon…

UPDATE : This is old and wrong

Just in case you missed the update at the beginning, this article was written for ember-cli version 0.0.25. Version 0.0.27 is out now and things have gotten much easier. Please see this post about how to do this in ember-cli 0.0.27