Concatenating CSS and Javascript files (and more)
Contents
Very often there will be several CSS files in a medium sized web app project. Wouldn’t it be nice if we could minify and concatenate these files in one step? This is where the gulp plugin gulp-usemin
comes into play. It concatenates CSS, HTML and Javascript files before storing the resulting files to their destination. But wait, don’t we have several CSS files specified in index.html
? When we concatenate them into one, do we have to modify the <link>
tags in order to reflect the change ? No, this is exactly what usemin
does for us. What we need to do is to frame the <link>
tags in index.html
files between specially formatted XHTML comments, so that usemin
can identify the location where it needs to remove the <link>
tags and replace them by a single <link>
tag which points to the resulting concatenated CSS file. But again, even if usemin does all that for us, what if we want to modfiy some CSS rules, but our original tags in index.html
are gone? Do we have to edit the cancatenated version or restore the original index.html
?
No, we don’t want our sources to be changed at all. Remember, concatenating and all that is done when you want to test or release your source code. Therefore, let these gulp tasks do their stuff and have the outcome stored somewhere else. By doing so, your sources stay unchanged, and each time you change something, you can run gulp and recreate the concatenated version again and again. Well, if you suspected that usemin not only processes CSS files but also our index.html, you are right. And because usemin already has to change the index.html file to reflect the changes of the CSS files, it can also do the HTML minification for us. Yeah, we can forget about the previous chapter about minifying HTML files, because now we use usemin. See how our next example source index.html file can look like:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Build Pipeline Demo</title> <!-- build:css css/style.css --> <link href="../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet"> <link href="../bower_components/bootstrap-drawer/dist/css/bootstrap-drawer.min.css" rel="stylesheet"> <link href="css/mystyle.css" rel="stylesheet"> <!-- endbuild --> </head> <body> Hello World! </body> </html>
See the framing comments:
<!-- build:css css/style.css --> ... <!-- endbuild -->
.All the stylesheets referenced between the opening and closing comment will be processed and the output stored in css/style.css
. What do you think will happen if you put your <script>
tags in comments like this?
<!-- build:js js/lib.js --> <script src="../bower_components/jquery/dist/jquery.min.js"></script> <script src="../bower_components/handlebars/handlebars.min.js"></script> <script src="../bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="../bower_components/bootstrap-drawer/dist/js/drawer.min.js"></script> <script src="../bower_components/rxjs/dist/rx.all.min.js"></script> <script src="../bower_components/rxjs-dom/dist/rx.dom.js"></script> <script src="js/namespace.js"></script> <script src="js/app.js"></script> <!-- endbuild -->
Yes, with the use of gulp-usemin
, what we want to do with CSS files can also be done with Javascript files. The following Gulpfile.js
will process index.html
, CSS and Javascript files and modifies the resulting index.html
so it reflects the changes. Then all files created or modified by gulp-usemin
will be stored in a folder dist
.
But first we need to install the usemin plugin:
c:> npm install gulp-usemin --save-dev
For the next example to work, Gulpfile.js
must look like this:
var gulp = require("gulp"); var minifyHtml = require('gulp-minify-html'); var usemin = require('gulp-usemin'); gulp.task('usemin', function () { return gulp.src('src/index.html') .pipe(usemin({ html: [minifyHtml({empty: true})] })) .pipe(gulp.dest('dist/')); });
The above code will take our index.html
(line 2) and pipes it to gulp-usemin
(line 3), which in turn concatenates all files that are enclosed in those framing comments. In case of index.html
, we also specified the minifyHtml
plugin (line 4) which minifies index.html
although there is no concatenation to happen with the only html file in our project. Finally, all resulting files are copied to the dist
folder in our project’s root (line 6).
Let us put more processing to our usemin task. If we want to do more than concatenating CSS and Javascript files, usemin allows us to process them before concatenation. For the next example, we need a couple of additional plugins. Enter the following commands in your terminal:
c:> npm install gulp-minify-css --save-dev
c:> npm install gulp-uglify –save-dev
.See the new package.json
after you installed the two new plugins:
{ "name": "buildpipeline", "version": "1.0.0", "description": "", "main": "Gulpfile.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Gulp" ], "author": "sgoemans", "license": "ISC", "devDependencies": { "gulp": "^3.9.1", "gulp-minify-html": "^1.0.6", "gulp-usemin": "^0.3.23", "gulp-minify-css": "^1.2.4", "gulp-uglify": "^2.0.0" } }
Now see following example and guess what’s happening:
var gulp = require("gulp"); var uglify = require("gulp-uglify"); var usemin = require('gulp-usemin'); var minifyHtml = require('gulp-minify-html'); var minifyCss = require('gulp-minify-css'); gulp.task('usemin', function () { return gulp.src('src/index.html') .pipe(usemin({ css: [minifyCSS()], html: [minifyHtml({empty: true})], js: [uglify()] })) .pipe(gulp.dest('dist/')); });
Not only will the CSS and Javascript files be concatenated, now the CSS files get minified and the Javascript files will be uglified too.
Well, that is pretty much to do for a single task. For that reason, usemin
has been put onto a blacklist. Recommendation is to use gulp-useref
instead, but the underlying principles are the same.