grunting
28 June 2015With a new site coming up I made a few changes to my CodeIgniter CMS (yes, I will move on to Laravel soon) and created a Grunt file to automate the tasks.
The main thing to do was to split my assets
folder into two -- src
and dist
. Previously it was a bit of a mess. I had a bootstrap
folder shoved into my assets/css
folder (even though it contains a load of other, non-css stuff), ckeditor
was plopped into assets/js
, basically the whole thing was pretty unstructured. It looked something like this:
├── assets
| ├── css
| | ├── images
| | | ├── [any images used by the css files]
| | ├── admin.css
| | ├── ie.css
| | ├── jquery-ui.css
| | ├── style.css
| | ├── [any plugin css files]
| ├── js
| | ├── ckeditor
| | | ├── [all ckeditors files]
| | ├── admin.js
| | ├── jquery-ui.js
| | ├── jquery.min.js
| | ├── script.js
| | ├── [any plugin js files]
| ├── scss
| | ├── .sass-cache
| | ├── breakpoints
| | ├── modules
| | ├── partials
| | ├── config.rb
| | ├── ie.scss
| | ├── style.scss
| ├── images
Note that there's no concatenation, no minification going on here. The css
and js
folders could theoretically be swollen with plugins, making them hard to read and of course making for lots of server requests on the website. The images were also not optimized.
So, last week, with a few tutorials and videos to help me out (this Scotch.io tutorial was particularly helpful), I set about gruntifying this. Since I already had node, npm and grunt installed (together with a few grunt generators), it was a relatively smooth process.
The first thing I did after cd
ing into my folder was create the package.json
file with npm init
. I then added the plugins I was going to use in the devDependencies
section. I needed to optimize images, lint my JS, concatenate and minify my JS, compile my SASS and minify the resultant CSS, and have Grunt watch the CSS and JS files for changes. This was my devDependencies
section:
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-cssmin": "latest",
"grunt-contrib-imagemin": "latest",
"grunt-contrib-jshint": "latest",
"grunt-contrib-sass": "^0.9.2",
"grunt-contrib-uglify": "latest",
"grunt-contrib-watch": "latest",
"jshint-stylish": "latest"
}
After that running npm install
installs the appropriate dependencies. The next step was to create the Gruntfile.js
file, but before I could do that I needed to think what from a purely logical point of view would be the most convenient structure for my assets. I'm not convinced I've come up with the optimal solution, but for now I decided upon a layout like this:
├── assets
| ├── src
| | ├── css
| | | ├── images
| | | ├── ie.css
| | | ├── jquery-ui.css
| | | ├── style.css
| | ├── js
| | | ├── vendor
| | | | ├── jquery.min.js
| | | | ├── jquery-ui.js
| | | ├── admin.js
| | | ├── script.js
| | ├── scss
| | | ├── [As above, but without the config.rb file]
| | ├── images
| ├── dist
| | ├── css
| | ├── images
| | ├── js
| ├── ckeditor
So at the beginning, the dist
subfolders - css
, images
and js
- are empty. I also put a vendor
folder in the src/js
folder - this made it easier to target when created the vendor.js
file in dist
. With this decided on, I put together the Gruntfile.js
with a bit of help from various tuts on and off youtube.
This was all pretty straightforward. A few wrinkles included:
- First trying out the Grunt Compass plugin, and being too impatient to figure out the various config options, which led me to go for the simpler SASS plugin.
- Confusing myself over the question of whether to concat first then minify or vice versa. Using the Concat plugin at first before realising that I could concatenate with the Uglify plugin which I was using anyway.
- Having problems with JSHint grumbling at some of my vendor JS files. I ended up excluding them from the
jshint
build step.
I won't post the whole Gruntfile.js
file here, because (a) it's long and (b) it's probably very similar to a thousand other configs out in the wild. Just look at any tutorial for hints. I will post a couple of things that relate to my 'wrinkles' above. For example, the JSHint section, with its exclusion of vendor files, ended up looking like this:
jshint: {
options: {
reporter: require('jshint-stylish')
},
build: ['Gruntfile.js','assets/src/js/*.js','!assets/src/js/vendor/*']
}
And my Uglify section - concatenating and uglifying at the same time - looks like this:
uglify: {
options: {
banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n*/\n'
},
build: {
files: {
'assets/dist/js/vendor.js':'assets/src/js/vendor/*.js',
'assets/dist/js/main.js': 'assets/src/js/script.js',
'assets/dist/js/admin.js': ['assets/src/js/admin.js','assets/src/js/app.js','assets/src/js/jquery.Jcrop.min.js','assets/src/js/pGenerator.jquery.js']
}
}
}
Note there's a few JS files being glued into one admin.js
file, and everything in the vendor
folder ends up as vendor.js
.
To cap it all I've got the Watch plugin training its beady eyes on my CSS and JS files, and running SASS, CSSMin, JSHint and Uglify whenever they change.
So that's it! Obviously I had to change some of the references in my CMS code to point to the new assets/dist
folder and its various subfolders / files, but apart from that this was a remarkably smooth process and I end up with smaller files and fewer trips to the server.