A little bit of history
of front-end development workflow
2011
Setup phase = download & scaffold ...
<head>
<link type="text/css" rel="stylesheet" href="css/ui-lightness/jquery-ui-1.8.16.custom.css" />
<link type="text/css" rel="stylesheet" href="css/jquery.lightbox-0.5.css" />
<link type="text/css" rel="stylesheet" href="css/main.css" />
<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js"></script>
<script type="text/javascript" src="js/jquery.jplayer.min.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
<script type="text/javascript" src="js/jquery.cycle.all.min.js"></script>
<script type="text/javascript" src="js/jquery.mousewheel.js"></script>
<script type="text/javascript" src="js/jquery.jscrollpane.min.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<head/>
In 2011, we didn't need to compile anything
Minify and concatenation? We can do it manually
Deployment? Via FTP.
Testing? Waat? It works. If not, I test it manually.
Finally, in 2012, we met these guys:
$ npm install -g bower
$ bower install --save jquery
$ bower install --save jquery-ui
$ bower install --save jplayer
$ bower install --save lightbox
$ bower install --save jquery.cycle
$ bower install --save jquery.mousewheel
$ bower install --save jquery.jscrollpane
$ npm install -g yo generator-bespoke
$ yo bespoke
[?] What is the title of your presentation? Hello World
[?] Would you like to use a pre-made theme? Yes
[?] Would you like bullet lists? Yes
...
create gulpfile.js
create README.md
create .bowerrc
create src/index.jade
create src/scripts/main.js
...
I'm all done.
Run `gulp serve` to run HTTP server on localhost:8080 and open your presentation!
$ grunt
Running "jshint" (jshint) task
>> 47 file lint free.
Running "qunit" (qunit) task
Testing test/tiny-pubsub.html....OK
>> 4 assertions passed (23ms)
Running "clean:dist" (clean) task
Cleaning "dist"...OK
Running "concat:dist" (concat) task
File "dist/ba-tiny-pubsub.js" created.
Running "uglify:dist" (uglify) task
File "dist/ba-tiny-pubsub.min.js" created.
Compressed size: 119 bytes gzipped (185 bytes minified).
Done, without errors.
Frontend workflow today
$ yo webapp $ bower install --save angular $ bower install --save angular-resource
// gruntfile.js grunt.initConfig({ concat: { dist: { src: [ 'vendor/bower/angular/angular.js', 'vendor/bower/angular-resource/angular-resource.js' ], dest: 'dist/js/vendor.js' } } });
Grunt plugins allow us to:
- minify js, css, http files
- compile other syntaxes (coffeescript, sass, jade, stylus, etc.)
- hint for errors
- watch files for changes
- run a HTTP server
- run tests
- add license info
- compile HTML templates into JS
- use sourcemaps
- compress images
- move/create somes files, directories, symlinks
- deploy to server
This was fine.
But brought as to ..
Grunt's issues
Gulp task example (source)
gulp.task('scripts', function() {
return gulp.src('src/scripts/**/*.js') // <-- Read from FS
.pipe(jshint('.jshintrc'))
.pipe(concat('main.js'))
.pipe(gulp.dest('dist/assets/js')) // <-- Write to FS
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest('dist/assets/js')) // <-- Write to FS
.pipe(livereload(server));
});
Gulp API
is just four functions
gulp.task(name, [deps,], fn)
define a task with optional dependencies.gulp.src(glob)
create a stream from given file system glob.gulp.dest(folder)
save files from a stream to given directory.gulp.watch(glob, tasks)
run a task when one of the globbed files is changed.
That's it!
gulp.task(name, [deps,], fn)
gulp.src(glob)
gulp.dest(glob)
gulp.watch(glob, tasks)
How to start?
-
Install Node & Gulp
http://nodejs.org/http://gulpjs.com/ -
Install some Gulp plugins
http://gulpjs.com/plugins/ -
Create gulpfile.js and code it
- Profit!
# Enter the project's directory $ cd myapp
# Create package.json file (if nonexistent yet) $ npm init
# Install gulp & its' plugins locally # (and add them to package.json) $ npm install --save-dev gulp gulp-sass gulp-coffee
# Code the gulpfile.js file (but learn Gulp's API first) $ vim gulpfile.js
# Finally, run a gulp's task! $ gulp build
var gulp = require("gulp");
gulp.task("build", function(){
// TODO
});
gulp.task("watch", function(){
// TODO
});
gulp.task("default", ["build", "watch"]);
gulpfile.js
var paths = {
scripts: "app/js/**/*.coffee",
stylesheets: "app/css/**/*.sass"
};
gulp.task("build", ["compile-js", "compile-css"]);
gulp.task("watch", function(){
gulp.watch(paths.scripts, ["compile-js"]);
gulp.watch(paths.stylesheets, ["compile-css"]);
});
gulpfile.js
var sass = require("gulp-sass");
gulp.task("compile-css", function(){
return gulp.src(paths.stylesheets)
.pipe(sass())
.pipe(gulp.dest("build/css/"));
});
gulpfile.js
var coffee = require("gulp-coffee");
gulp.task("compile-js", function(){
return gulp.src(paths.scripts)
.pipe(coffee())
.pipe(gulp.dest("build/js/"));
});
gulpfile.js
Live demo
jtomaszewski/ionic-cordova-gulp-seedSo why it's better than Grunt?
As the gulpjs.com says:
- Speed - tasks run concurrently
- Efficiency - no unnecessary temporary files
- Simplicity - Gulpfile is much cleaner
Gulp-Links
Blog posts
- And just like that Grunt and RequireJS are out, it’s all about Gulp and Browserify now
- Getting started with Gulp
- Gulp.js, an alternative to Grunt.js
- Managing Frontend Dependencies & Deployment Part 2: Gulp
- Automating Front-end Workflow
- Automating your workflow with gulp.js
- Front-end workflows with Gulp