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
- 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
-
Let's see what build systems do...
- If it's handy, open your Project 2 app on Heroku
(I'll demo with Street Fighter) - Open the "Sources" tab in Chrome's Dev Tools
- Use the File Browser on the left to find the
*.js
and*.css
files inside of the assets folder.
- If it's handy, open your Project 2 app on Heroku
-
What has happened to the CSS and/or JavaScript?
-
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!
-
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?
-
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?
#### It automates mundane tasks that we otherwise would have to do manually...
-
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.
- 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 thesrc/css
folder. - JQuery from a
libs/js
folder and two app specific script files from thesrc/js
folder.
- Bootstrap from a
- 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.
- It has a minimal
-
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.
-
When all is said and done, we will want production code, including
index.html
, being served out of apublic
directory. -
"Production code" is similar to what we saw in the Rails app earlier:
- A single, minified
all.js
file served frompublic/js
. - A single, minified
all.css
file served frompublic/css
.
- A single, minified
-
Now that we know what our goal is, let's break our app by creating a
public
directory and movingindex.html
into it:? mkdir public ? mv index.html public/
-
Let's
cd
into our newpublic
directory and spin uplite-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!
-
If our goal is to load a single JavaScript and a single CSS file from the
public
folder, we'll need to tweak ourindex.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>
-
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
-
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? ...
-
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?
-
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?
-
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
-
The first line inside
gulpfile.js
will always be used to load thegulp
module:var gulp = require('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?
-
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.
-
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?
-
Our first real task will be used to concatenate our JavaScript files into an
all.js
file and write it to apublic/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?
-
Install
gulp-concat
:? npm install --save-dev gulp-concat
then in ourgulpfile.js
:var gulp = require('gulp'); var concat = require('gulp-concat'); ...
-
Now let's use our newly installed and required plugin to perform some concatenation!
-
Let's rename our
firstTask
toscripts
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...
- 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 ofjs
in thesrc
folder.
- The
- 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')
: Thegulp-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 withall.js
.gulp.dest('public/js')
: Gulp does not write anything to disk until told to and that's what we're doing here with thedest()
method that's built into Gulp.
- So, this pattern, that we just used, is popular for many tasks in Gulp:
- Use Gulp's
src()
method to grab files and turn them into a stream. - Use the
pipe()
method to provide the current stream to a plugin. - The plugin takes the stream given to it, processes it and returns it to the pipe.
- Repeat steps 2 and 3 as necessary until the stream is finally outputted with Gulp's
dest()
method.
- Use Gulp's
-
Let's run it and check it out:
? gulp scripts
Cha-ching!
-
Notice that
gulp.dest()
created thepublic/js
folder automatically! -
But upon close inspection, there's a problem here - the code won't run as expected!
Who sees the problem?
-
So, our
all.js
file won't work because thesayHello
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...
-
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!
-
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?
-
Just add another wildcard pattern to
thegulp.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...
-
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 :)
-
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?
-
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!
-
If we simply type
? gulp
Gulp will execute the task named
default
-
Let's define a
default
task that will run both thescripts
andstyles
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.
-
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 thestyles
task runs?
-
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!
-
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?
-
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.
-
Now we just type
gulp
, and it will watch for changes to the files we specified and automatically execute thedefault
task - check it out... -
Good 'ol
control-c
will end the Gulp process.
-
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?
-
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');
-
All we need to do to minify our JavaScript is pipe our stream
through thegulp-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!
#### Any questions before some final questions and move on to the lab?
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?
-
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
orless
stylesheet.