Skip to content

Instantly share code, notes, and snippets.

@jim-clark
Last active February 24, 2017 14:12
Show Gist options
  • Save jim-clark/91e96a1b272f38e8d74f to your computer and use it in GitHub Desktop.
Save jim-clark/91e96a1b272f38e8d74f to your computer and use it in GitHub Desktop.


Learning Objectives


Students will be able to:

  • Describe the Use Case for Gulp
  • Install & Set Up Gulp
  • Create a Gulp Task
  • Use Gulp to Create Production Ready Code

Roadmap


  • What is Gulp and what is it used for?
  • What else can Gulp do?
  • Gulp vs. Grunt
  • Review Starter Project
  • Today's Goal
  • Installing Gulp
  • Setting up Gulp
  • Writing our first Gulp Task - Concatenation
  • The default task
  • Watching for changes
  • Minification
  • Essential Questions
  • Lab

What is Gulp
and
what is it used for?


What is Gulp?

Build System?
What the heck is a build system?


What's a Build System?


  • Let's see what build systems do...

    1. If it's handy, open your Project 2 app on Heroku
      (I'll demo with Street Fighter)
    2. Open the "Sources" tab in Chrome's Dev Tools
    3. Use the File Browser on the left to find the *.js and *.css files inside of the assets folder.
  • What has happened to the CSS and/or JavaScript?


What's a Build System? (cont.)


  • Those stylesheets and script files were minified and concatenated by the Rails build system known as the
    Asset Pipeline and implemented by the Sprockets gem.

  • Rails automatically produces production ready code with its built-in build system - thanks Rails!


What's a Build System? (cont.)


  • Now let's open your deployed Project 3 Node app and check the "Sources" tab again (I'll demo using the Food Fight app).

  • This time we'll find several separate (not concatenated),
    non-minified stylesheets and script as written by Team Food Fight.

  • What explains the difference between the two projects?


What's a Build System? (cont.)


  • So, Rails automatically built our code into production code.

  • NodeJS did not.

  • So, which type of app, Rails or Node, is a more likely use case for a build system like Gulp?


What else can
Gulp do?


What else can Gulp do?


First and foremost:
Increase developer productivity!



#### It automates mundane tasks that we otherwise would have to do manually...

This is why Gulp is also known as a Task Runner,
not just a build system!


Let's discover what type of tasks Gulp can run!


What else can Gulp do? (cont.)


  • Gulp uses plugins designed to complete certain tasks.

  • There are numerous plugins available that can be installed using npm.

  • Do a search for "gulpjs plugins" and take note of the name of a few plugins and what they do.

  • I'll ask you to share your findings in 3 minutes.


In summary,
what is the use case for Gulp?

(what is it used for & when would you use it?)



So, let's get this out of the way...



Review the Starter Project


Review the Starter Project


  • Reviewing the project, we find:
    • It has a minimal index.html that loads:
      • Bootstrap from a libs/css folder and two app specific CSS files from the src/css folder.
      • JQuery from a libs/js folder and two app specific script files from the src/js folder.
    • Directory structure:
      • libs: Contains third-party vendor library files.
      • src: This is where we put the code we write,
        our app's pre-processed CSS & JS files.

Review the Starter Project (cont.)


  • Right-click on index.html in Sublime and open it in the browser.

  • You should see the app with the CSS looking sweet and the JS behaving as expected when the Say Hello button is clicked.


Today's Goal


Today's Goal


  • When all is said and done, we will want production code, including index.html, being served out of a public directory.

  • "Production code" is similar to what we saw in the Rails app earlier:

    • A single, minified all.js file served from public/js.
    • A single, minified all.css file served from public/css.

"Break" our App (on purpose)

  • Now that we know what our goal is, let's break our app by creating a public directory and moving index.html into it:

     ? mkdir public
     
     ? mv index.html public/
  • Let's cd into our new public directory and spin up lite-server.

  • Notice that index.html will load just fine, but our CSS & JS will not.

  • Don't worry, we're going to fix our app with production ready code!


Modify "public/index.html" to Include our Production Code

  • If our goal is to load a single JavaScript and a single CSS file from the public folder, we'll need to tweak our index.html to reflect this objective!

     <head>
     	<meta charset="utf-8">
     	<title>Gulp.js</title>
     	<link rel="stylesheet" href="libs/css/bootstrap.min.css">
     	<!-- <link rel="stylesheet" href="src/css/styles.css">
     	<link rel="stylesheet" href="src/css/more-styles.css"> -->
     	<link rel="stylesheet" href="css/all.css">
     	
     	<script src="libs/js/jquery-2.1.4.min.js"></script>
     	<!-- <script src="src/js/hello-module.js"></script>
     	<script src="src/js/app.js"></script> -->
     	<script src="js/all.js"></script>
     </head>

Installing Gulp


Installing Gulp


  • We will be using Gulp as a command line utility in Terminal like this:

     ? gulp myTask 

    So we need to install it globally with the -g option:

     ? npm install -g gulp

Installing Gulp (cont.)


  • Gulp also requires that we install its module locally.

  • What file do we need to keep track of Node module dependencies?

  • What's the best way to generate that file? ...


Installing Gulp (cont.)


  • Create our package.json file:

     ? npm init -f

    ...the -f option forces defaults - no questions asked :)

  • What type of dependency will Gulp be?
    Hint: Does our app use it when it's running?


Installing Gulp (cont.)


  • Install Gulp locally:

     ? npm install --save-dev gulp
  • Why is it important to have our app's dependencies (dev and non-dev) listed in the package.json file?


Setting up Gulp


Setting up Gulp


  • Gulp runs tasks that we code.

  • We always define and code our tasks in a file named gulpfile.js.

  • Let's create our gulpfile.js:

     ? touch gulpfile.js

Setting up Gulp (cont.)


  • The first line inside gulpfile.js will always be used to load the gulp module:

     var gulp = require('gulp');	

Congrats, we've accomplished our objective of installing &
setting up Gulp!


#### Review Questions:
  • Gulp looks for tasks in a file named _________?

  • In this file, we must require what Node module?

  • Other than requiring our modules at the top, what are we going to put in this file?


Writing Our First Gulp Task


Writing Our First Gulp Task


  • Let's start with the absolute minimum so that we can check that we're wired-up and ready to go:

     var gulp = require('gulp');
     
     gulp.task('firstTask', function() {
     	console.log('Hello');
     });
  • We're using Gulp's task() method to define the task and passing it our task's name and an anonymous function to execute.


Writing Our First Gulp Task (cont.)


  • Then, in our terminal type:

     ? gulp firstTask
  • You should see a result similar to:

     [15:17:46] Starting 'firstTask'...
     Hello
     [15:17:46] Finished 'firstTask' after 99 μs


    Everyone chill?


Writing Our First Gulp Task (cont.)


  • Our first real task will be used to concatenate our JavaScript files into an all.js file and write it to a public/js folder.

  • Of the plugins we discussed earlier, which one can we use to concatenate files?

  • What are the two steps necessary before we can use this plugin (or any plugin) in our gulpfile.js?


Writing Our First Gulp Task (cont.)


  • Install gulp-concat:

     ? npm install --save-dev gulp-concat	 


    then in our gulpfile.js:

     var gulp = require('gulp');
     var concat = require('gulp-concat');
     ...

Writing Our First Gulp Task (cont.)


  • Now let's use our newly installed and required plugin to perform some concatenation!

  • Let's rename our firstTask to scripts and write this code:

     var concat = require('gulp-concat');
    
     gulp.task('scripts', function() {
     	return gulp.src('src/**/*.js')
     		.pipe(concat('all.js'))
     		.pipe(gulp.dest('public/js'));
     });

    What's going on here...


Writing Our First Gulp Task (cont.)


  • Here's what's going on:
    • The return statement is optional, but it lets Gulp know when a task, which runs asynchronously, has finished running.
    • gulp.src('src/**/*.js'): Grabs a file or files that match the given string pattern.

      Of interest here is the ** which matches all folders, all of their nested folders, or no folders at all. So, basically, this particular pattern string will grab all files with the extension of js in the src folder.

Writing Our First Gulp Task (cont.)


  • Here's what's going on (continued):
    • pipe(): Gulp takes advantage of high-performance Node streams.
      In Gulp we "pipe" our data stream from one plugin to another.
    • concat('all.js'): The gulp-concat plugin will take the file streams piped to it and merge them into a single stream named whatever name we pass in like we did here with all.js.
    • gulp.dest('public/js'): Gulp does not write anything to disk until told to and that's what we're doing here with the dest() method that's built into Gulp.

Writing Our First Gulp Task (cont.)


  • So, this pattern, that we just used, is popular for many tasks in Gulp:
    1. Use Gulp's src() method to grab files and turn them into a stream.
    2. Use the pipe() method to provide the current stream to a plugin.
    3. The plugin takes the stream given to it, processes it and returns it to the pipe.
    4. Repeat steps 2 and 3 as necessary until the stream is finally outputted with Gulp's dest() method.

Writing Our First Gulp Task (cont.)


  • Let's run it and check it out:

     ? gulp scripts

    Cha-ching!

  • Notice that gulp.dest() created the public/js folder automatically!

  • But upon close inspection, there's a problem here - the code won't run as expected!
    Who sees the problem?


Determining the Sequence of Concatenation


  • So, our all.js file won't work because the sayHello function expression is not defined before being called - which will lead to seeing red in the console!

  • However, the solution does not lie with gulp-concat, it simply concatenates in the order it receives the files...


Determining the Sequence of Concatenation (cont.)

  • It just so happens that Gulp's src() method can also take an array of files/patterns and the order they are listed in the array determines the order of the stream:

     gulp.src(['src/js/hello-module.js', 'src/**/*.js'])
  • Don't fret, Gulp is smart enough not to duplicate any file it's already included!

     ? gulp scripts

    Nice swap-a-roo!


Including Vendor Libraries


  • Our quest to return a single JavaScript file to the browser will require that we include any vendor libraries necessary in our concatenated all.js.

  • Should we include vendor libraries before or after our app's scripts?


Including Vendor Libraries (cont.)


  • Just add another wildcard pattern to
    the gulp.src():

     gulp.task('scripts', function() {
     	return gulp.src([
     		'libs/**/*.js',
     		'src/js/hello-module.js',
     		'src/**/*.js'
     	])
     	.pipe(concat('all.js'))
     	.pipe(gulp.dest('public/js'));
     });


    Then...


Including Vendor Libraries (cont.)


  • Comment out the <script> tag for jQuery:

     <head>
     	...
     	<!-- <script src="libs/js/jquery-2.1.4.min.js"></script>
     	<script src="src/js/hello-module.js"></script>
     	<script src="src/js/app.js"></script> -->
     	<script src="js/all.js"></script>
     </head>
  • Run ? gulp scripts again, then refresh the browser!

  • It's still ugly, but our JS is back in action :)


Congrats on Creating Your First
Gulp Task!
Another Objective Bites the Dust!


Review Questions:

  • What Gulp method do we use to chain our plugins together and provide them with a data stream?

  • What do we do if we need our source files streamed in a certain order?


Individual Practice


Concatenation
(10 minutes)


Individual Practice - Concatenation

  • We've combined all our JavaScript into one file.

  • Now it's your turn to use the gulp-concat plugin to do the same with our CSS!

  • Name your new task styles.

  • Be sure to include the Bootstrap library.
    Is the load order important for CSS like it is for JavaScript?

  • Don't forget to comment out the <link> for Bootstrap.

  • 10 minutes - You got this!


Your app should be functioning now!


But we're not quite production ready,
we still need to minify.


However, there's a couple of other tricks we want to learn about first!


The default Task


The default Task


  • If we simply type

     ? gulp

    Gulp will execute the task named default


The default Task (cont.)

  • Let's define a default task that will run both the scripts and styles tasks:

     gulp.task('default', ['scripts', 'styles']);
  • So, we can define new tasks that run other tasks!

  • Think of it as being able to use tasks like functions, allowing us to modularize and reuse them!

  • The tasks listed in the array are run in parallel.


Task Dependencies


  • The tasks in our default task will run in parallel. This is great for maximum performance, but sometimes you may need to ensure a certain task or tasks are completed first.

  • For example, what if we needed the scripts task for some reason to be completed before the styles task runs?


Task Dependencies (cont.)


  • One way we can achieve this is by specifying dependencies like this:

     gulp.task('styles', ['scripts'], function() {
       return gulp.src(['libs/**/*.css', 'src/**/*.css'])
         .pipe(concat('styles.css'))
         .pipe(gulp.dest('public/css'));
     });
  • By including an array of dependency tasks after the task name, Gulp will ensure that those tasks are completed first!


Review Questions:


  • What is the name of the task that is executed if we just type "gulp"?

  • Why do we use return within our function when defining our tasks?


Watching For Changes


Watching For Changes

  • So, I think we can all agree that having to manually run our build tasks is tedious. It can lead to boo boos as well - what if we forgot to build before we deployed? Yikes!

  • Gulp's watch method to the rescue:

     gulp.watch(['src/**/*.js', 'src/**/*.css'], ['default']);

    watch also has other signatures that can provide more control/power, however, to accomplish our goal, this minimal version will suffice.


Watching For Changes (cont.)


  • Now we just type gulp, and it will watch for changes to the files we specified and automatically execute the default task - check it out...

  • Good 'ol control-c will end the Gulp process.


Minification


Minification


  • So, the final hurdle to completing our objective of using Gulp to build our production code is to minifify our JavaScript.

  • What plugin we can use?

  • What do we have to do to use it?


Minification (cont.)


  • This should look pretty familiar:

     ? npm install --save-dev gulp-uglify			

    and

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

Minification (cont.)


  • All we need to do to minify our JavaScript is pipe our stream
    through the gulp-uglify plugin like so:

     gulp.task('scripts', function() {
     	return gulp.src(['libs/**/*.js',
     		'src/js/hello-module.js',
     		'src/**/*.js'])
     		.pipe(concat('all.js'))
     		.pipe(uglify())
     		.pipe(gulp.dest('public/js'));
     });
  • Type gulp and check your app's source files!

  • There are also minifyer plugins available for CSS!


Misson Accomplished!


We have now accomplished our goal of producing production code ready to deploy


#### Any questions before some final questions and move on to the lab?

Essential Questions


Essential Questions


Take a couple of minutes to discuss these questions with your pair...

  • In your own words, describe the difference between production and non-production code.

  • What type of tool is Gulp?

  • What programming language are Gulp tasks written in?

  • What is the name of the file we must put our tasks in?


Lab / After Hours Practice


  • Those of you that have started MEAN Stack apps for project 4 have a great project to practice using Gulp. However, those without an app started, should use the current project to:

    • Minify the CSS like we did with the JavaScript.
    • Research and use a plugin to compile a sass or less stylesheet.

References


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment