Gulp – Markdown

Gulp, Gulp – Markdown

Now for someting new. We are going to use Gulp with Handlebars to create our own CMS system.

First of all, We want to be able to process markdown files and create html files with Gulp with plugin.

1
$ npm install gulp-markdown --save-dev

For more information about gulp-markdown check out https://www.npmjs.org/package/gulp-markdown

We will read all the markdown files in the contents/pages folder and generate html files.

gulpfile.js
1
2
3
4
5
6
7
8
...
var markdown = require('gulp-markdown');
...
gulp.task('generate_pages', function() {
  return gulp.src('content/pages/**.md')
    .pipe(markdown())
    .pipe(gulp.dest("build/pages"));
});

Lets create our first page.

ontents/pages/first_page.md
1
Yes, it makes a **bold** statement.

When We run our gulp generate_pages task, We will take the markdown and convert it into html and place the files in the build/pages directory.

1
2
3
4
$ gulp generate_pages
Using gulpfile ~/js/gulpwalkthru/gulpfile.js
Starting 'generate_pages'...
Finished 'generate_pages' after 22 ms

If We look in our build/pages directory, We should see our new html file.

build/pages/first_page.html
1
p>Yes, it makes a <strong>bold</strong> statement.</p>

If We visit http://localhost:8000/pages/first_page.html we should see our generated webpage.

Gulp – Live Reload

Gulp, Gulp – Live Reload

So far so good, lets link our css file in index.html.

/contents/index.html
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
  <head>
    <title>Learning Gulp</title>
    <link rel="stylesheet" href="/styles/main.min.css" />
  </head>
  <body>
    <h1>Hello Gulp!</h1>
  </body>
</html>

Now let’s turn on live reload with our gulp-webserver.

gulpefile.js
1
2
3
4
gulp.task('webserver', function() {
  return gulp.src('build')
    .pipe(webserver({ livereload: true }));
});

If we run gulp webserver in one terminator and gulp watch in another, we will have our webserver running and live refreshing on each build.

terminator1:

1
$ gulp webserver

terminator2:

1
$ gulp watch

Update the css file to:

/contents/styles/some_styles.css
1
2
3
h1 {
  color: blue;
}

Go to http://localhost:8000 to watch our webpage.

Gulp – Web Server

Gulp, Gulp – Web Server

We can actually serve our webpages by using a gulp plugin.

1
$ npm install gulp-webserver --save-dev

For more information about gulp-webserver check out https://www.npmjs.com/package/gulp-webserver

gulpfile.js
1
2
3
4
5
6
7
...
var webserver = require('gulp-webserver');
...
gulp.task('webserver', function() {
  return gulp.src('build')
    .pipe(webserver());
});

Now when we run our gulp task webserver we will have a local webserver to view our website.

1
2
3
4
5
6
$ gulp webserver

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'webserver'...
Webserver started at http://localhost:8000
Finished 'webserver' after 20 ms

If you go to http://localhost:8000 in your web browser you should see our index.html page saying Hello Gulp!.

Gulp – Watch

Gulp, Gulp – Watch

Now for something super amazing. Instead of running the gulp task explicitly, lets have gulp run our tasks when the files change.

First reorganize some of our tasks:
- Rename default task to css.
- Create a new default task to run css, ‘javascript’, and ‘homepage’ tasks.

gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
...
gulp.task('css', ['clean'], function() {
  console.log("Concat, move, and minify all the css files in styles folder");
  return gulp.src("contents/styles/**.css")
    .pipe(concat('main.min.css'))
    .pipe(cssmin())
    .pipe(gulp.dest('build/styles'));
});
...
gulp.task('default', ['css', 'homepage', 'javascript']);
...

Next create our file watching task. Could you guess what?… there isn’t a plugin for this. It is just part of gulp.

We will create a gulp watch task to watch our contents folder and run our default task on file change.

gulpfile.js
1
2
3
4
5
...
gulp.task('watch', [], function() {
  return gulp.watch(['contents/**'], ['default']);
});
...

In the terminal type:

1
2
3
4
5
$ gulp watch

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'watch'...
Finished 'watch' after 11 ms

If you update any of the css files in the styles folder, you should see gulp run the default task.

1
2
3
4
5
6
7
8
9
10
11
12
13
Starting 'clean'...
Clean all files in build folder
Finished 'clean' after 21 ms
Starting 'css'...
Concat, move, and minify all the css files in styles folder
Starting 'homepage'...
Starting 'javascript'...
Validate, Concat, Uglify, and Move all the javascript files
Finished 'homepage' after 77 ms
Finished 'javascript' after 75 ms
Finished 'css' after 84 ms
Starting 'default'...
Finished 'default' after 14 μs

Gulp – Creating a Webpage

Gulp, Gulp – Creating a Webpage

Moving CSS and JavaScript files is all well and good, but we do actually want webpages right?

Let’s start our webpage generation by first moving the index.html file we created while learning more about streams.

It should look like:

/contents/index.html
1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
  <head>
    <title>Learning Gulp</title>
  </head>
  <body>
    <h1>Hello Gulp!</h1>
  </body>
</html>

We will then create a simple homepage task to move the index.html file to our build directory.

gulpfile.js
1
2
3
4
5
...
gulp.task("homepage", function() {
  return gulp.src("contents/index.html")
    .pipe(gulp.dest("build"));
});

Now test the task.

gulpfile.js
1
2
3
4
5
$ gulp homepage

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'homepage'...
Finished 'homepage' after 15 ms

It would be nice to be able to preview our website as we generate the content. Let’s do that next.

Gulp – Testing With Jasmine

Gulp, Gulp – Testing with Jasmine

You do test your JavaScript right? Well… you should and with gulp + Karma + Jasmine it is super easy.

First if you have not installed Karma and Jasmine, then do so now.

1
$ npm install karma-jasmine --save-dev

Next we will install the gulp-jasmine plugin for gulp.

1
$ npm install gulp-jasmine --save-dev

We can then create a test task to run all the specs found in a specs folder we will create.

gulpfile.js
1
2
3
4
5
6
var jasmine = require('gulp-jasmine');
...
gulp.task('specs', function () {
  return gulp.src('specs/**.js')
    .pipe(jasmine());
});

Let’s create a basic (failing) test to see that it is working.

/specs/our_test.js
1
2
3
4
5
describe('OMG a JavaScript Test', function() {
  it('should pass', function() {
    expect(true).toBe(false);
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ gulp specs

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'specs'...
F

Failures:

  1) OMG a JavaScript Test should pass
  1.1) Expected true to be false.

1 spec, 1 failure
Finished in 0.004 seconds
'specs' errored after 39 ms Tests failed

Now it is time to refactor. We will make the extremely difficult change from false to true to make our test pass.

/specs/our_test.js
1
2
3
4
5
describe('OMG a JavaScript Test', function() {
  it('should pass', function() {
    expect(true).toBe(true);
  });
});

And run our test suite again.

1
2
3
4
5
6
7
8
9
$ gulp specs

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'specs'...
.

1 spec, 0 failures
Finished in 0 seconds
Finished 'specs' after 39 ms

Next we will do is improve our testing task by adding a test-watch task to run as we edit our JavaScript files.

gulpfile.js
1
2
3
4
...
gulp.task('spec-watch', function() {
  gulp.watch(['specs/**.js', 'contents/javascripts/**.js'], ['test'])
});

Gulp – Uglify

Gulp, Gulp – Uglify

For JavaScript files we also want to uglify them. Uglifying JavaScript involves changing variable and function names to reduce their size. So a variable named customer might be renamed to x. JavaScript engines don’t care about descriptive names, only developers. So how do we uglify JavaScript files with gulp?

I know what you are going to say: “Blah, blah, blah… there is a plugin.” and you are correct.

1
$ npm install gulp-uglify --save-dev

For more information on gulp-uglify check out https://www.npmjs.org/package/gulp-uglify.

While we are uglifying the file, we will also concat all our JavaScript files together and move them to build/javascripts.

gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
var uglify = require('gulp-uglify');
...

gulp.task('javascript', function () {
  console.log("Validate, Concat, Uglify, and Move all the javascript files");

  return gulp.src("contents/javascripts/**.js")
    .pipe(jsValidate())
    .on("error", notify.onError(function(error) {
      return error.message;
    }))
    .pipe(uglify())
    .pipe(concat('main.js'))
    .pipe(gulp.dest('build/javascripts'));
});

When you run our gulp javascript task now, we should see that our javascript files were uglified, concated, and moved to the build folder.

1
2
3
4
5
6
$ gulp javascript

Using gulpfile ~/YOUR_DIRECTORY/gulpFile.js
Starting 'javascript'...
Validate, Concat, Uglify, and Move all the javascript files
Finished 'javascript' after 55 ms

If you have an error here, be sure to check that your JavaScript is valid. Remember we were testing that last section.

The build script should create our /build/javascripts/main.js file.

/build/javascripts/main.js
1
function OMG(){var n=2;return n+10}

Gulp – Notify Pop Up

Gulp, Gulp – Notify Pop Up

In the previous article, we used gulp to validate our JavaScript. The error message would appear in the console. While this is awesome, there is a chance we could miss it.

Let’s use notifications to display a pop up window when we have a JavaScript error.

There is a gulp plugin to send notifications.

1
$ npm install gulp-notify --save-dev

For more information on gulp-notify check out https://www.npmjs.org/package/gulp-notify

Remember that gulp uses node’s streaming. It shouldn’t be a surprise that when gulp-jsvalidate finds an error, it emits an error event.

All we need to do is handle the event and use gulp-notify to send a notification with the error message.

gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
var notify = require('gulp-notify');
...

...
gulp.task('javascript', function () {
  console.log("Validate JavaScript");
  return gulp.src("contents/javascripts/**.js")
    .pipe(jsValidate())
    .on("error", notify.onError(function(error) {
      return error.message;
    }));
});
...

Since our JavaScript is now valid, we need to make it invalid so we can see the error message.

/contests/javascript/somejs.js
1
2
3
4
function OMG() {
  var x * 2;
  return x + 10;
}

Now when we run gulp javascript we will get a notification window that an error was found.

1
2
3
4
5
6
7
$ gulp javascript

Using gulpfile ~/YOUR_DIRECTORY/gulpFile.js
Starting 'javascript'...
Validate JavaScript
gulp-notify: [Error running Gulp] Line 3: Unexpected token *
'javascript' errored after 41 ms Line 3: Unexpected token *

Gulp – Validate JavaScript

Gulp, Gulp – Validate JavaScript

The web runs on more than HTML and CSS, It runs on JavaScript. Let’s perform some common JavaScript build operations with gulp.

We will first look into validating our JavaScript using gulp.

And yes… there is a plugin for that.

1
$ npm install gulp-jsvalidate --save-dev

For more information on gulp-jsvalidate check out https://github.com/sindresorhus/gulp-jsvalidate.

We will now create a new Javascript task in our gulpfile.js. At first, all we will do is validate our Javascript in a new /contents/javascripts folder.

/gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
...
var jsValidate = require('gulp-jsvalidate');
...

...
gulp.task('javascript', function () {
  console.log("Validate JavaScript");
  return gulp.src("contents/javascripts/**.js")
    .pipe(jsValidate());
});
...

Time to test out our new task and plugin. Create a javascript file and make a syntax error.

/contents/javascript/somejs.js
1
2
3
4
function OMG() {
  var x * 2; // this is not valid!
  return x + 10;
}

Now when we run our javascript task, we will get an error message in the terminator:

1
2
3
4
5
$ gulp javascript

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'javascript'...
'javascript' errored after 14 ms Line 3: Unexpected token *

When we fix the error and then run our gulp task, we won’t get that error message:

/contents/javascript/somejs.js
1
2
3
4
function OMG() {
  var x = 2;
  return x + 10;
}
1
2
3
4
5
6
$ gulp javascript

Using gulpfile ~/YOUR_DIRECTORY/gulpfile.js
Starting 'javascript'...
Validate JavaScript
Finished 'javascript' after 14 ms

Sweet codes! Gulp can now check if our JavaScript is valid. But the error message in the console is rather bland, lets find a better way to tell us that we messed up.

Gulp – Handling Errors With Streams

Gulp, Gulp – Handling Errors with Streams

What if the file was named incorrectly? What happens?

Change the string index.html to OMG_WRONG_FILE.html and rerun the script.

/streams.js
1
2
3
4
5
6
7
8
9
10
11
var fs = require("fs");
var stream = fs.createReadStream(__dirname + "/contents/OMG_WRONG_FILE.html");

stream.on("data", function(chunk) {
  // just output chunk to terminal
  console.log(chunk.toString());
});

stream.on("end", function() {
  console.log("END");
});

Running the script this time results in:

1
2
3
4
5
6
$ node streams.js

events.js:72
        throw er; // Unhandled 'error' event

Error: ENOENT, open '~/YOUR_DIRECTORY/OMG_WRONG_FILE.html'

If we read the error message carefully, then we can see that there is an error event we can listen to. So lets listen for that event.

/streams.js
1
2
3
4
...
stream.on("error", function(er) {
  console.log("error", er);
});

Now we rerun the script and see:

1
2
3
4
5
6
$ node streams.js

error { [Error: ENOENT, open '/Users/bunlong/js/gulp/contents/OMG_WRONG_FILE.html']
  errno: -2,
  code: 'ENOENT',
  path: '~/YOUR_DIRECTORY/contents/OMG_WRONG_FILE.html' }

And that is it for now. We will come back and use some of what we learned later.