Category - Tutorials
Using Grunt to compile SASS
Overview
During this tutorial we will explore how to use Grunt, which is a task runner, to compile SASS files. Typically programmers would write shell scripts that they could execute to create, compress and modify a large number of files at once. Alternately, the IDE's (Integrated Development Environment) and frameworks have been building functionality to automatically process or perform tasks for you.
Examples of common tasks include; minifying css files, compiling less or sass files, compressing image files, and automatically running tests.
Using a task runner like Grunt or Gulp put you in complete control of this process and allow you to perform whatever actions you wish. Even going so far as to watch for changed or new files and rerunning tasks.
The most common task runners are Grunt and Gulp. Both use Node.js to run. These two task runners differ in how they are used. Grunt favors configuration for the tasks it uses. Gulp uses conventions (specifically named files). Normally, I prefer convention as it tends to mean less code for the developer. However, you lose some control. Though I tend to prefer convention, the popularity of Grunt is undeniable. As of 6/2015, there are over 4,400 Grunt Plugins compared to 1,500 Gulp Plugins.
For this tutorial we will focus on using Grunt to compile SASS css preprocessor files. Previously, this depended on Ruby to be installed. However, now there is a c++ compiler and an easy grunt plugin you can download to do this. We will even be able to set it to recompile everytime we save our sass file. This will constantly ensure we have an updated minified CSS file with no extra work for us.
Setup
In order to set this up, the first thing we must do is install a few items.
- Node.js - To install go to http://nodejs.org. Once you have node installed, be sure to restart the computer. Programs that tie into your CLI (command line interface) don't always tie in very well until you reboot the PC.
- Project - Open visual studios and create a new web application. For easy setup, choose an MVC application. The easiest way to create the package file that node uses is to go through node's helper command line tool.
- In the Solution Explorer, right click on the project and choose "Open Folder in File Explorer".
- Go up one folder.
- Hold shift and right click on the folder and choose "Open command window here"
- You should now be in the command prompt in your project folder. Type: "npm init"
- You must type a name and a version. You can use the values they suggest in the parens. It will show you the structure of the json when it is done and ask you to confirm. Keep this command line window open, we will be using it a lot!
- Go back to visual studios, show all files, and refresh the solution explorer. You should now see the package.json file in the root of the project.
- Grunt - When installing NPM (Node Package Manager) packages, you will sometimes install plugins globally to allow reuse. For this tutorial, I won't be using any global packages. This will ensure if the project is shared, all will be installing the needed packages when they work with it. We will instead be saving the dependency in the package.json file. The easiest way to do so is in the command window type: "npm install grunt -save". After the package is installed reload the package.json file. You will see a new "dependency" object.
- Grunt CLI - The other way to install packages is to open the package.json file and modify the dependencies. The pattern is "package":"version" for each dependency comma separated. You can use special symbols like ^ which will automatically install any newer versions that are not a breaking change. For example if you had "^1.3.0", npm would install 1.3.1 or 1.4.0 etc, however, it would not install 2.0.0 as this would signify a breaking change. Alternately, the ~ will match minor versions. "~1.3.0" would install 1.3.1 but not 1.4.0 or higher.
- Modify the package json file's dependency object to look like so:
"dependencies": { "grunt": "^0.4.5", "grunt-cli": "^0.1.13" }
- In the command window type "npm install".
- Alternately, you could have typed "npm install grunt-cli -save" and the above two steps would have been done automatically.
- Modify the package json file's dependency object to look like so:
- Grunt SASS - Next we will install a task to compile our sass files. You can either install this in one of two ways:
- You can modify the package.json file with the dependency of "grunt-sass":"^1.0.0", save it and then type "npm install" in the prompt.
- Or just type "npm install grunt-sass -save" in the command prompt.
- Grunt Contrib Watch - Finally, let's install the watch plugin. This will give us the ability to have grunt automatically run when we add new files or save an existing file. You can install this either way as well, though for now, let's just type "npm install grunt-contrib-watch -save" in the command window.
Grunt Config File
As mentioned earlier grunt is a configuration based task runner. This means we need to configure a few things. In Visual Studios right click on the project root and create a javascript file called Gruntfile.js and enter the following code.
module.exports = function (grunt) { //Configuration setup grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { dist: { files: { 'content/demo.css' : 'sass/demo.scss' } } } }); //load npm tasks grunt.loadNpmTasks('grunt-sass'); //register tasks grunt.registerTask('default', ['sass']); };
Let's examine the pieces:
- Grunt uses the AMD (asynchronous module definition) pattern that all node packages uses. Module.exports is defining what is publically exposed for this file. Which is a large function that accepts a parameter that represents the grunt object.
- On that grunt parameter we call the initConfig method and pass a javascript object. The pkg property tells grunt where to look for our other node packages from. We can also pass additional properties for the configuration of those packages. We are passing the sass object that grunt-sass will look for. It tells it where to distribute the files and where to save the css file and which sass file to look for.
- Next we use the grunt parameter to call the loadNpmTasks() method and pass it the string name of the npm package. As your grunt configuration expands you will have a call to loadNpmTasks() for each npm package grunt will use.
- The registerTask() method allows us to group several different actions together. Note that this accept the name of the object we passed through the initConfig. Later we will setup other tasks.
SASS
To learn more about SASS, I encourage you to read my previous blog post for an indepth look at using SASS at Working with SASS and Visual Studio. For now I'll touch on just the basics!
In Visual Studio on the root project folder create a new folder called "sass", and then create a file called "demo.scss".
Mindscape WorkBench/Web Essentials - If you have either of these install be sure to go to the options and disable the auto compiling. I should mention that the reason I started using Grunt was entirely due to the buggy nature of web essentials and the conflicts that mindscape workbench caused with visual studios intellisense support.
In the demo.scss file place the following code:
$cPrimary : red; div.jumbotron { border: 1px solid $cPrimary; h1 { border-bottom: 1px solid $cPrimary; } }
Running Grunt
Enough work, time to enjoy the spoils! Go to the command prompt and type "grunt" to run the default task.
You may have to install grunt "globally" in order to run grunt from the command line. If you see an error that says "grunt is unrecognized", then in the command line type "npm install -g grunt-cli". You will need to have administrator permissions to install node packages globally.
Refresh the content folder and you will see a demo.css file! Open up the "App_Start/BundleConfig.cs" and modify the file per below:
bundles.Add(new StyleBundle("~/Content/css").Include( "~/Content/bootstrap.css", "~/Content/site.css", "~/Content/demo.css"));
Save, build the project, and then load the site. You should see the main jumbotron surrounded by a red border and the h1 with a bottom border. This works well, but this would be very annoying for development to have to constantly run the command line prompt.
Grunt Watch
Let's use the grunt watch plugin to look for changes to our files and constantly recompile it. Go to your Gruntfile.js and modify it per below:
module.exports = function (grunt) { //Configuration setup grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { dist: { files: { 'content/demo.css': 'sass/demo.scss' } } }, watch: { scripts: { files: ['sass/*.scss'], tasks: ['sass'] } } }); //load npm tasks grunt.loadNpmTasks('grunt-sass'); grunt.loadNpmTasks('grunt-contrib-watch'); //register tasks grunt.registerTask('process', ['sass', 'watch']); grunt.registerTask('default', ['sass']); };
Above we added a new configuration for a watch object that keeps an eye on all .scss files in the sass folder and runs the sass task on them. We loaded the npm task and registered a new task called process. When we run the process task it will compile the sass files and then start watching the files for changes. When they are changed, it will run sass on them.
Go to the command prompt and type "grunt process". To exit the running task hit Ctrl+C and then hit Y to cancel the task.
Conclusion
We have just touched the surface of what you can do. You can of course create the sourceMaps and even minify the css files. Though since I'm using .NET's bundling function, the minification is not a need for me.
I encourage you to check out the Grunt Sass documentation.
To use compass without the headaches of ruby check out Compass Mixins. Which has the majority of the functionality of compass pulled to scss files that can be easily included and compiled.
You must be logged in to comment.