Kirkbride Solutions

Using Gulp to Uglify or Minify JavaScript and CSS Files

javascriptbuild toolstutorial

Basics on How to Minify your Javascript and CSS

To start I'd like to point out if you are just looking to do a very simple minification process on a small amount of Javascript or CSS there are websites available to do it quickly and cleanly. I'll be talking about utilizing Gulp which is a very useful tool for build automation processes, but may be overkill for some cases.

If you just need to quickly minify a small amount of Javascript and you aren't going to be rebuilding and working on the project for a long time you can always go to something like JSCompress. You just copy your functions into the window and click Compress Javascript.

JSCompress Before

JSCompress After

There are of course similar websites to do this for CSS for example CSS Compressor. On this website you would follow pretty much the same process as JSCompress.

Using Gulp to "Uglify" your Files

On my GitHub I have a project called jkFramework. This project is a SPA framework leveraging Angular 1.x to create reusable Dashboard components like a Menu, Dashboard body, and configurable widgets. I currently have a set of Gulp tasks in this file and I'll be expanding on those tasks. For reference I'll be using Visual Studio Community 2015, NPM to install the Gulp packages, and the Task Runner Explorer in Visual Studio. If you are not familiar with the Task Runner Explorer you can find it by Going into Views -> Other Windows -> Task Runner Explorer or if you prefer to avoid deep diving in menus you can use the short cut Ctrl + Alt + Backspace. You may have to add it via Tools -> Extensions and Updates -> Search for Task Runner Explorer.

This tutorial is going to have two main goals. One is to specify the basic use of Gulps Uglify for js and Gulps Minify for CSS. The other focus is to implement these functions into a list of already existing Gulp tasks.

To start the first thing we need to do is pull in Gulp and the other necessary dependencies into our package.json file:

"devDependencies": {
"gulp": "^3.9.1",
"gulp-uglify": "^2.1.0",
"gulp-clean-css": "^3.0.4",
//These are only for the Dashboard specific Gulp tasks
"gulp-angular-filesort": "^1.1.1",
"gulp-angular-templatecache": "^1.8.0",
"gulp-concat": "^2.6.0",
"gulp-strip-line": "^0.0.1",
"gulp-rename": "1.2.2",
"pump":"^1.0.2"
}

The next thing we need to do is add our gulpfile.js to the root of our project. Just to note my Dashboard project uses a custom built gulpfile.js if you are using any of the new ASP.NET Core templates the gulpfile.js comes pre-populated with a lot of the code. If you'd like to see how to work with the pre-populated code in the ASP.NET Core project this blog post here by "Exception Not Found" might be more useful to you. We're going to be working from scratch here.

So to start I'll list a basic implementation of each. After I'll get into a more specific implementation where you can kind of follow along with what the files are doing and where they are going.

Javascript Uglify:

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var pump = require('pump');

gulp.task('compress', function (cb) {
pump([
gulp.src('lib/*.js'),
uglify(),
gulp.dest('dist')
],
cb
);
});

Now this example is very basic and it does add in pump. Pump is just used to help with error handling. It's not a necessity although it is recommended. I will not be using it in my jkFramework project.

CSS Clean and Minify:

var gulp = require('gulp');
var cleanCSS = require('gulp-clean-css');

gulp.task('minify-css', function() {
return gulp.src('styles/*.css')
.pipe(cleanCSS({compatibility: 'ie8'}))
.pipe(gulp.dest('dist'));
});

Once again this is a very basic implementation.

Now the following code is a lot more complicated of a process and might mimic something you could run into if you're maintaining an existing system with some task automation. I'll post in the code and explain a bit more of the process at the end.

jkFramework Tasks with Uglify and Minification:

var gulp = require('gulp');
var cleanCSS = require('gulp-clean-css');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var gulpRename = require('gulp-rename');
var angularFilesort = require('gulp-angular-filesort');
var strip = require('gulp-strip-line');
var templateCache = require('gulp-angular-templatecache');


gulp.task('buildMenuTemplateCache', function () {
return gulp
.src([
'./ext-modules/jkMenu/**/*.html'
])
.pipe(templateCache({
root: 'ext-modules/jkMenu/',
module: 'jkMenu'
}))
.pipe(gulp.dest('./ext-modules/jkMenu/'))
;
});

gulp.task('buildDashboardTemplateCache', function () {
return gulp
.src([
'./ext-modules/jkDashboard/**/*.html'
])
.pipe(templateCache({
root: 'ext-modules/jkDashboard/',
module: 'jkDashboard'
}))
.pipe(gulp.dest('./ext-modules/jkDashboard/'))
;
});

gulp.task('buildFrameworkTemplateCache', function () {
return gulp
.src([
'./ext-modules/jkFramework/**/*.html'
])
.pipe(templateCache({
root: 'ext-modules/jkFramework/',
module: 'jkFramework'
}))
.pipe(gulp.dest('./ext-modules/jkFramework/'))
;
});

gulp.task('buildJavaScript', function () {
return gulp
.src([
'./ext-modules/**/*.js'
])
.pipe(angularFilesort())
.pipe(strip(["use strict"]))
.pipe(concat('jkFramework.js'))
.pipe(gulp.dest('./dist/'))
.pipe(gulpRename('jkFramework.min.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist/'))
;
});

gulp.task('buildCSS', function () {
return gulp
.src([
'./ext-modules/**/*.css'
])
.pipe(concat('jkFramework.css'))
.pipe(gulp.dest('./dist/'))
.pipe(gulpRename('jkFramework.min.css'))
.pipe(cleanCSS())
.pipe(gulp.dest('./dist/'))
;
});

So this example might seem like a lot but it is actually pretty simple once you know what the dependencies do and what our end goal is.

The first 3 tasks are all Angular 1.x specific tasks. They are essentially taking all of the Html template files for each part of the framework and turning them into Javascript so they can be included in the dist files.

The buildJavaScript task is one of the most important ones. This task properly orders all the angular files so that the modules are listed out first so we don't run into any issues by calling angularFilesort. The strip function removes the "use strict" tags that kept me in check during development. The concat function concatenates all the javascript in the src into a single dist file named jkFramework.js. After I get that singular js file I can then create a copy and rename it jkFramework.min.js. The next step is to uglify the copied file and turn it into a minified version the actual jkFramework.min.js.

The buildCSS task is very similar, but it does have less steps. We basically concatenate all the css files into a single file, copy/rename, cleanCSS, and then we get our dist CSS files.

I generally like to include both the minified files and concatenated files. This lets those who would like to use the files have the ability to debug the js code or make minor tweaks to the css code, and use the minified versions for production.

Now that we have the tasks listed out we can simply run them from the Task Runner Explorer. That would like this:

Task Runner Exporer

As you can see you can automate these tasks to happen during or after builds, and such so you don't have to run them manually. To run a task you can double click it or right click on it and select run. For this particular case it is important to run the build template cache functions first. If I wanted these to be truly automated I would create a separate task that calls the other tasks in the proper order and only run it instead. That however is a topic for another blog post.