Showing posts with label js. Show all posts
Showing posts with label js. Show all posts

Tuesday, January 05, 2016

Using Gulp for WordPress Automation

Using Gulp for WordPress Automation

If you are not using Gulp or any task runner, believe me when I say that you are missing out on all the front-end fun stuff. Today, I intend to share my advanced Gulp based automatted workflow for building WordPress themes, with the community.

I remember the time when I had to minify CSS and JS files, compress the images and the fuss of testing my designs across different browsers let alone devices — oh my. If my recollection of lost isn't misleading me then I used to spend like 30% of my productive hours on this stuff.

Thankfully, someone wrote a piece about DRY (Don't Repeat Yourself) and it got me thinking about the flaws in my workflow. I believe a tweet from Chris Coyer led me to start using Grunt in 2012 or a little later. I used it for over a year and boy it was a fun ride.

Why Gulp?

While Grunt took care of optimizing images, compressing scripts, and compiling Sass, I never really enjoyed writing Grunt files. Then in Dec 2013, I heard about this new task runner called Gulp. On a Sunday morning, I thought to create a dummy project and try Gulp, to say that I was hooked would be an understatement.

Why Do I Like Gulp?

At that time, there was hardly any documentation available for using Gulp with WordPress, but thanks to the awesome helping community at Stack Exchange, I was able to make it work. I found Gulp to be a lot better than Grunt. Here is why:

  • Gulp is easier to understand and more efficient
  • Gulp has a JavaScript syntax unlike JSON syntax of Grunt
  • Gulp is faster than Grunt (One of my theme's compile time went from 12secs to 300ms)
  • Gulp is intuitive and gets 20K-25k downloads a day, which is equal to or great than Grunt downloads
  • Gulp's code-over-configuration makes it not only easy to write tasks for, but also much easier to read and maintain

That said, let's leave the story for now and see what it is like to be using Gulp with WordPress.

Do I Need to Use Gulp?

Are you a web developer? Do you program in HTML/CSS sometimes?

— Yes!

Did you ever use a task-runner? Feel like you belong to the stone age while all the crazy kids in town are using awesome advanced workflows?

— Yes! :(.

OK! let's get you started then.

Since this article is about an advanced Gulp based workflow, explaining how to do basic Gulp related stuff is out of the scope. But instead of leaving you (beginners) in the middle of nowhere, I'd like to suggest a few articles to help you get started.


If having a basic Gulp workflow is nothing new for you, then maybe you'll enjoy reading my advanced gulp workflow.

Advanced Gulp WordPress Workflow

While building premium themes for WordPress, I end up with a lot of grunt work which includes:

  • Minifying & optimizing CSS with stylesheets and Sass
  • Custom JavaScripts and 3rd Party Scripts via Bower
  • Synced cross-browser design testing on different devices
  • Tunneling my localhost dev branch to a random public URL for public access
  • Building an installable zip theme file without any node modules, cache files or .Dot files data in it

Let's explore how I get all this stuff done with Gulp.

I have set up a Github repository called Advanced Gulp WordPress. You can check out the structure of files inside it for better understanding.

Using Gulp for WordPress Automation

A Look at gulpfile.js

Now let's take a look at gulpfile.js which is present in the root folder of our theme. I will explain each task one by one to make it easier for you to understand. You'll find completed gulpfile.js at the end of this post.

Since I assume you already know how Gulp works, I will not be explaining how to put all the plugins/packages in package.json file and other basic setup related steps.

Step #1: Setting Up the Variables

First of all I am going to set up certain variables so that I don't have to change everything for every other theme I create. Let's review the code:

/**
 *
 * Gulpfile setup
 *
 * @since 1.0.0
 * @authors Ahmad Awais, @digisavvy, @desaiuditd, @jb510, @dmassiani and @Maxlopez
 * @package neat
 * @forks _s & some-like-it-neat
 */


// Project configuration
var project   = 'neat', // Project name, used for build zip.
 url   = 'neat.dev', // Local Development URL for BrowserSync. Change as-needed.
 bower   = './assets/bower_components/'; // Not truly using this yet, more or less playing right now. TO-DO Place in Dev branch
 build   = './buildtheme/', // Files that you want to package into a zip go here
 buildInclude  = [
    // include common file types
    '**/*.php',
    '**/*.html',
    '**/*.css',
    '**/*.js',
    '**/*.svg',
    '**/*.ttf',
    '**/*.otf',
    '**/*.eot',
    '**/*.woff',
    '**/*.woff2',

    // include specific files and folders
    'screenshot.png',

    // exclude files and folders
    '!node_modules/**/*',
    '!assets/bower_components/**/*',
    '!style.css.map',
    '!assets/js/custom/*',
    '!assets/css/patrials/*'

   ];

I've set up variables for:

  • L#12: Project name
  • L#13: Project URL at localhost
  • L#14: Path to folder of Bower Components
  • L#15: Name of the folder which will be created for building an installable theme zip file
  • L#16: Variable buildInclude contains the paths to files or folders which are to be included and excluded in while building a clean theme inside buildTheme folder for creating a zip file

Step #2: Loading Gulp Plugins

I am using quite a few gulp plugins to help manage everything we discussed above.

// Load plugins
 var  gulp         = require('gulp'),
  browserSync  = require('browser-sync'), // Asynchronous browser loading on .scss file changes
  reload       = browserSync.reload,
  autoprefixer = require('gulp-autoprefixer'), // Autoprefixing magic
  minifycss    = require('gulp-uglifycss'),
  filter       = require('gulp-filter'),
  uglify       = require('gulp-uglify'),
  imagemin     = require('gulp-imagemin'),
  newer        = require('gulp-newer'),
  rename       = require('gulp-rename'),
  concat       = require('gulp-concat'),
  notify       = require('gulp-notify'),
  cmq          = require('gulp-combine-media-queries'),
  runSequence  = require('gulp-run-sequence'),
  sass         = require('gulp-sass'),
  plugins      = require('gulp-load-plugins')({ camelize: true }),
  ignore       = require('gulp-ignore'), // Helps with ignoring files and directories in our run tasks
  rimraf       = require('gulp-rimraf'), // Helps with removing files and directories in our run tasks
  zip          = require('gulp-zip'), // Using to zip up our packaged theme into a tasty zip file that can be installed in WordPress!
  plumber      = require('gulp-plumber'), // Helps prevent stream crashing on errors
  cache        = require('gulp-cache'),
  sourcemaps   = require('gulp-sourcemaps');

The plugins I am using to are as follows:

  • Gulp — Pretty much self-explanatory
  • BrowserSyn — Amazing Time-saving synchronized browser testing
  • AutoPrefixer — Auto prefix CSS for legacy browsers
  • UglifyCSS — For CSS Minification
  • Filter — Enables you to work on a subset of the original files by filtering them using globbing.
  • UglifyJS — Minifies JS files
  • ImageMin — Minifies PNG, JPEG, GIF and SVG images
  • Newer — For passing through only those source files that are newer than corresponding destination files.
  • Rename — To easily rename files
  • Concat — To concatenate JS files
  • Notify — To send notification to OS based on node notifier module
  • Combine Media Queries — To combine repetitive media queries after Sass or Less
  • Run Sequence — Run a series of dependent gulp tasks in order
  • Gulp Sass — Gulp plugin for Sass which is based on libSass
  • Load Plugins — To automatically load in gulp plugins
  • Ignore — To ignore files in the stream based on file characteristics
  • Zip — To zip or compress files
  • Plumber — Fix node pipes, prevent them from breaking due to an error
  • Cache — A cache proxy task for Gulp
  • Source Maps — Source map support for CSS partial files

Phew! That was a lot. Well, at the end of the day, it's all worth the effort.

Step #3: Task to Setup Browser Sync

Let's dive a little deeper and create some awesome tasks to automate our workflow. Browsersync is one of my favorite plugins.

/**
 * Browser Sync
 *
 * Asynchronous browser syncing of assets across multiple devices!! Watches for changes to js, image and php files
 * Although, I think this is redundant, since we have a watch task that does this already.
*/
gulp.task('browser-sync', function() {
 var files = [
   '**/*.php',
   '**/*.{png,jpg,gif}'
      ];
 browserSync.init(files, {

  // Read here http://www.browsersync.io/docs/options/
  proxy: url,

  // port: 8080,

  // Tunnel the Browsersync server through a random Public URL
  // tunnel: true,

  // Attempt to use the URL "http://my-private-site.localtunnel.me"
  // tunnel: "ppress",

  // Inject CSS changes
  injectChanges: true

 });
});

I used to have LiveReload in my workflow, which would reload the web page whenever a file gets edited and saved. But when Browsersync was introduced, it helped me cut down half of the shitty things I had to do in order to automate syncing between different browsers. Browsersync helps me with the following stuff;

  • Injecting CSS changes without any web page getting reloaded
  • Change the port and set up a tunnel through a random public URL, which means my teammates can access the dev branch live at my localhost in a matter of minutes
  • Synced testing across different browsers, where I open the given URL at my Desktop, Laptop, Tab, and mobile to test same features in a single go with synced scroll, clicks, form inputs, etc. Watch the video at Browsersync.

Step #4: Gulp Style Task

Let's take a look at the styles task I built. In this task, there is a lot going on. We are compiling Sass, creating minified CSS and optimizing media queries.

/**
 * Styles
 *
 * Looking at src/sass and compiling the files into Expanded format, Autoprefixing and sending the files to the build folder
 *
 * Sass output styles: https://web-design-weekly.com/2014/06/15/different-sass-output-styles/
*/
gulp.task('styles', function () {
 return      gulp.src('./assets/css/*.scss')
   .pipe(plumber())
   .pipe(sourcemaps.init())
   .pipe(sass({
    errLogToConsole: true,
 
    //outputStyle: 'compressed',
    outputStyle: 'compact',
    // outputStyle: 'nested',
    // outputStyle: 'expanded',
    precision: 10
   }))
   .pipe(sourcemaps.write({includeContent: false}))
   .pipe(sourcemaps.init({loadMaps: true}))
   .pipe(autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
   .pipe(sourcemaps.write('.'))
   .pipe(plumber.stop())
   .pipe(gulp.dest('./'))
   .pipe(filter('**/*.css')) // Filtering stream to only css files
   .pipe(cmq()) // Combines Media Queries
   .pipe(reload({stream:true})) // Inject Styles when style file is created
   .pipe(rename({ suffix: '.min' }))
   .pipe(minifycss({
    maxLineLen: 80
   }))
   .pipe(gulp.dest('./'))
   .pipe(reload({stream:true})) // Inject Styles when min style file is created
   .pipe(notify({ message: 'Styles task complete', onLast: true }))
});

Let me explain line by line, what's going on in there:

  • L#1 – L#8: I created the styles task
  • L#9: Here I provided the source of Sass file, which is a style.scss file present at ./assets/css/style.scss
  • L#10: Initiated plumber to avoid pipe breaking due to minor CSS errors when I save a file
  • L#11: Sourcemaps got initiated. A source map provides a way of mapping code within a compressed file back to its original position in a source file. This means that – with the help of a bit of software – you can easily debug your applications even after your assets have been optimized. The Chrome and Firefox developer tools both ship with built-in support for source maps.
  • L#12 – L#20: Sass is being compiled in compact format, you can read about Sass formats here
  • L#23: I am prefixing CSS with autoprefixer. The legacy browsers which should be supported are mentioned inside the arguments array
  • L#26: Here I have saved the final compiled CSS file for our WordPress theme in the root directory. Since style.scss was being compiled, the output will be style.css file. Now all you need to do is make sure you use a "!" in the comments at the top of the style.scss file so that, even when the compiling/compressing happens, the comment remains: i.e. /*! Theme Name: Your Theme etc... */
  • L#27: I filtered all the .css files in the root directory, which at the moment is one style.css file
  • L#28: Combined the media queries inside selected files
  • L#30: Renamed the file to style.min.css
  • L#31 – L#33: Minified the style.min.css file
  • L#34: Output was saved as a style.min.css file in the root of WP theme folder

Step #5: Scripts Minification and Concatenation

Now to deal with custom JavaScript files and 3rd Party JS files, I have created two tasks called vendorsJs and scriptsJs. They both are pretty much similar. Let's review the code.

/**
 * Scripts: Vendors
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/
gulp.task('vendorsJs', function() {
 return      gulp.src(['./assets/js/vendor/*.js', bower+'**/*.js'])
   .pipe(concat('vendors.js'))
   .pipe(gulp.dest('./assets/js'))
   .pipe(rename( {
    basename: "vendors",
    suffix: '.min'
   }))
   .pipe(uglify())
   .pipe(gulp.dest('./assets/js/'))
   .pipe(notify({ message: 'Vendor scripts task complete', onLast: true }));
});


/**
 * Scripts: Custom
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/

gulp.task('scriptsJs', function() {
 return      gulp.src('./assets/js/custom/*.js')
   .pipe(concat('custom.js'))
   .pipe(gulp.dest('./assets/js'))
   .pipe(rename( {
    basename: "custom",
    suffix: '.min'
   }))
   .pipe(uglify())
   .pipe(gulp.dest('./assets/js/'))
   .pipe(notify({ message: 'Custom scripts task complete', onLast: true }));
});

Here is what's happening in there:

  • I selected the vendor JS files paths with bower path at L#7 and the custom JS files paths at L#27
  • Concatenated the files to two single files called vendors.js and custom.js
  • Saved the output in ./assets/js/ folder
  • Renamed the files to with .min suffix
  • Minified/uglified the files
  • And saved two more files called vendors.min.js and custom.js

Step #6: Image Optimization Task

There nothing new in the image optimization task. Look at the code below.

/**
 * Images
 *
 * Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('images', function() {

// Add the newer pipe to pass through newer images only
 return  gulp.src(['./assets/img/raw/**/*.{png,jpg,gif}'])
    .pipe(newer('./assets/img/'))
    .pipe(rimraf({ force: true }))
    .pipe(imagemin({ optimizationLevel: 7, progressive: true, interlaced: true }))
    .pipe(gulp.dest('./assets/img/'))
    .pipe( notify( { message: 'Images task complete', onLast: true } ) );
});

  • I selected the ./assets/img/raw/**/*.{png,jpg,gif} path as a source
  • Optimized the images and placed them in ./assets/img/ folder

Step #7: Building a Clean Installable Theme Zip File

This is a group of tasks which are responsible for creating a clean copy of installable theme zip file. Take a quick look at the code. There is nothing much to it, it is all basic copy pasting and deleting or ignoring of files/folders.

/**
 * Clean gulp cache
 */
 gulp.task('clear', function () {
   cache.clearAll();
 });


 /**
  * Clean tasks for zip
  *
  * Being a little overzealous, but we're cleaning out the build folder, codekit-cache directory and annoying DS_Store files and Also
  * clearing out unoptimized image files in zip as those will have been moved and optimized
 */

 gulp.task('cleanup', function() {
  return  gulp.src(['./assets/bower_components', '**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
   .pipe(ignore('node_modules/**')) //Example of a directory to ignore
   .pipe(rimraf({ force: true }))
   // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });
 gulp.task('cleanupFinal', function() {
  return  gulp.src(['./assets/bower_components','**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
   .pipe(ignore('node_modules/**')) //Example of a directory to ignore
   .pipe(rimraf({ force: true }))
   // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });

 /**
  * Build task that moves essential theme files for production-ready sites
  *
  * buildFiles copies all the files in buildInclude to build folder - check variable values at the top
  * buildImages copies all the images from img folder in assets while ignoring images inside raw folder if any
  */

  gulp.task('buildFiles', function() {
   return  gulp.src(buildInclude)
    .pipe(gulp.dest(build))
    .pipe(notify({ message: 'Copy from buildFiles complete', onLast: true }));
  });


/**
* Images
*
* Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('buildImages', function() {
 return  gulp.src(['assets/img/**/*', '!assets/images/raw/**'])
   .pipe(gulp.dest(build+'assets/img/'))
   .pipe(plugins.notify({ message: 'Images copied to buildTheme folder', onLast: true }));
});

 /**
  * Zipping build directory for distribution
  *
  * Taking the build folder, which has been cleaned, containing optimized files and zipping it up to send out as an installable theme
 */
 gulp.task('buildZip', function () {
  // return  gulp.src([build+'/**/', './.jshintrc','./.bowerrc','./.gitignore' ])
  return  gulp.src(build+'/**/')
   .pipe(zip(project+'.zip'))
   .pipe(gulp.dest('./'))
   .pipe(notify({ message: 'Zip task complete', onLast: true }));
 });


 // ==== TASKS ==== //
 /**
  * Gulp Default Task
  *
  * Compiles styles, fires-up browser sync, watches js and php files. Note browser sync task watches php files
  *
 */

 // Package Distributable Theme
 gulp.task('build', function(cb) {
  runSequence('styles', 'cleanup', 'vendorsJs', 'scriptsJs',  'buildFiles', 'buildImages', 'buildZip','cleanupFinal', cb);
 });

This task will run only when I will use gulp build command. Let's review what happens when this command is run:

  • clear: Task to clear the gulp cache
  • cleanup: Task to remove sass-cache, bower_components and .DS_Store files in the stream. It also ignores the node_modules folder
  • cleanupFinal: Another cleanup task to be run at the end of build sequence. It may or may not have any difference from cleanup task
  • buildFiles: Build task that moves essential theme files to the buildTheme folder
  • buildImages: Task to build and copy the final set of images to the buildTheme folder
  • buildZip: Task to create an installable Zip file of the buildTheme folder
  • build: Main task which runs styles task to compile CSS then cleans up everything with a cleanup task. After that, it runs all the scripts related and build related tasks and a final cleanup task at the end to produce a theme zip file via buildTheme folder.

Step #8: Watch Task

Finally, there is a watch task which helps in automatically running the styles, scripts, images and browser-sync related tasks in case of any change that occurs in the below-mentioned folder.

// Watch Task
 gulp.task('default', ['styles', 'vendorsJs', 'scriptsJs', 'images', 'browser-sync'], function () {
  gulp.watch('./assets/img/raw/**/*', ['images']); 
  gulp.watch('./assets/css/**/*.scss', ['styles']);
  gulp.watch('./assets/js/**/*.js', ['scriptsJs', browserSync.reload]);

 });

Final gulpfile.js

/**
 *
 * Gulpfile setup
 *
 * @since 1.0.0
 * @authors Ahmad Awais, @digisavvy, @desaiuditd, @jb510, @dmassiani and @Maxlopez
 * @package neat
 * @forks _s & some-like-it-neat
 */


// Project configuration
var project   = 'neat', // Project name, used for build zip.
 url    = 'neat.dev', // Local Development URL for BrowserSync. Change as-needed.
 bower    = './assets/bower_components/'; // Not truly using this yet, more or less playing right now. TO-DO Place in Dev branch
 build    = './buildtheme/', // Files that you want to package into a zip go here
 buildInclude  = [
      // include common file types
      '**/*.php',
      '**/*.html',
      '**/*.css',
      '**/*.js',
      '**/*.svg',
      '**/*.ttf',
      '**/*.otf',
      '**/*.eot',
      '**/*.woff',
      '**/*.woff2',

      // include specific files and folders
      'screenshot.png',

      // exclude files and folders
      '!node_modules/**/*',
      '!assets/bower_components/**/*',
      '!style.css.map',
      '!assets/js/custom/*',
      '!assets/css/patrials/*'

     ];

// Load plugins
 var gulp     = require('gulp'),
  browserSync  = require('browser-sync'), // Asynchronous browser loading on .scss file changes
  reload       = browserSync.reload,
  autoprefixer = require('gulp-autoprefixer'), // Autoprefixing magic
  minifycss    = require('gulp-uglifycss'),
  filter       = require('gulp-filter'),
  uglify       = require('gulp-uglify'),
  imagemin     = require('gulp-imagemin'),
  newer        = require('gulp-newer'),
  rename       = require('gulp-rename'),
  concat       = require('gulp-concat'),
  notify       = require('gulp-notify'),
  cmq          = require('gulp-combine-media-queries'),
  runSequence  = require('gulp-run-sequence'),
  sass         = require('gulp-sass'),
  plugins      = require('gulp-load-plugins')({ camelize: true }),
  ignore       = require('gulp-ignore'), // Helps with ignoring files and directories in our run tasks
  rimraf       = require('gulp-rimraf'), // Helps with removing files and directories in our run tasks
  zip          = require('gulp-zip'), // Using to zip up our packaged theme into a tasty zip file that can be installed in WordPress!
  plumber      = require('gulp-plumber'), // Helps prevent stream crashing on errors
  cache        = require('gulp-cache'),
  sourcemaps   = require('gulp-sourcemaps');


/**
 * Browser Sync
 *
 * Asynchronous browser syncing of assets across multiple devices!! Watches for changes to js, image and php files
 * Although, I think this is redundant, since we have a watch task that does this already.
*/
gulp.task('browser-sync', function() {
 var files = [
     '**/*.php',
     '**/*.{png,jpg,gif}'
    ];
 browserSync.init(files, {

  // Read here http://www.browsersync.io/docs/options/
  proxy: url,

  // port: 8080,

  // Tunnel the Browsersync server through a random Public URL
  // tunnel: true,

  // Attempt to use the URL "http://my-private-site.localtunnel.me"
  // tunnel: "ppress",

  // Inject CSS changes
  injectChanges: true

 });
});



/**
 * Styles
 *
 * Looking at src/sass and compiling the files into Expanded format, Autoprefixing and sending the files to the build folder
 *
 * Sass output styles: https://web-design-weekly.com/2014/06/15/different-sass-output-styles/
*/
gulp.task('styles', function () {
  gulp.src('./assets/css/*.scss')
  .pipe(plumber())
  .pipe(sourcemaps.init())
  .pipe(sass({
   errLogToConsole: true,
 
   //outputStyle: 'compressed',
   outputStyle: 'compact',
   // outputStyle: 'nested',
   // outputStyle: 'expanded',
   precision: 10
  }))
  .pipe(sourcemaps.write({includeContent: false}))
  .pipe(sourcemaps.init({loadMaps: true}))
  .pipe(autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
  .pipe(sourcemaps.write('.'))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./'))
  .pipe(filter('**/*.css')) // Filtering stream to only css files
  .pipe(cmq()) // Combines Media Queries
  .pipe(reload({stream:true})) // Inject Styles when style file is created
  .pipe(rename({ suffix: '.min' }))
  .pipe(minifycss({
   maxLineLen: 80
  }))
  .pipe(gulp.dest('./'))
  .pipe(reload({stream:true})) // Inject Styles when min style file is created
  .pipe(notify({ message: 'Styles task complete', onLast: true }))
});


/**
 * Scripts: Vendors
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/
gulp.task('vendorsJs', function() {
 return  gulp.src(['./assets/js/vendor/*.js', bower+'**/*.js'])
    .pipe(concat('vendors.js'))
    .pipe(gulp.dest('./assets/js'))
    .pipe(rename( {
     basename: "vendors",
     suffix: '.min'
    }))
    .pipe(uglify())
    .pipe(gulp.dest('./assets/js/'))
    .pipe(notify({ message: 'Vendor scripts task complete', onLast: true }));
});


/**
 * Scripts: Custom
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/

gulp.task('scriptsJs', function() {
 return  gulp.src('./assets/js/custom/*.js')
    .pipe(concat('custom.js'))
    .pipe(gulp.dest('./assets/js'))
    .pipe(rename( {
     basename: "custom",
     suffix: '.min'
    }))
    .pipe(uglify())
    .pipe(gulp.dest('./assets/js/'))
    .pipe(notify({ message: 'Custom scripts task complete', onLast: true }));
});


/**
 * Images
 *
 * Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('images', function() {

// Add the newer pipe to pass through newer images only
 return  gulp.src(['./assets/img/raw/**/*.{png,jpg,gif}'])
    .pipe(newer('./assets/img/'))
    .pipe(rimraf({ force: true }))
    .pipe(imagemin({ optimizationLevel: 7, progressive: true, interlaced: true }))
    .pipe(gulp.dest('./assets/img/'))
    .pipe( notify( { message: 'Images task complete', onLast: true } ) );
});


/**
 * Clean gulp cache
 */
 gulp.task('clear', function () {
   cache.clearAll();
 });


 /**
  * Clean tasks for zip
  *
  * Being a little overzealous, but we're cleaning out the build folder, codekit-cache directory and annoying DS_Store files and Also
  * clearing out unoptimized image files in zip as those will have been moved and optimized
 */

 gulp.task('cleanup', function() {
  return  gulp.src(['./assets/bower_components', '**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
     .pipe(ignore('node_modules/**')) //Example of a directory to ignore
     .pipe(rimraf({ force: true }))
     // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });
 gulp.task('cleanupFinal', function() {
  return  gulp.src(['./assets/bower_components','**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
     .pipe(ignore('node_modules/**')) //Example of a directory to ignore
     .pipe(rimraf({ force: true }))
     // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });

 /**
  * Build task that moves essential theme files for production-ready sites
  *
  * buildFiles copies all the files in buildInclude to build folder - check variable values at the top
  * buildImages copies all the images from img folder in assets while ignoring images inside raw folder if any
  */

  gulp.task('buildFiles', function() {
   return  gulp.src(buildInclude)
      .pipe(gulp.dest(build))
      .pipe(notify({ message: 'Copy from buildFiles complete', onLast: true }));
  });


/**
* Images
*
* Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('buildImages', function() {
 return  gulp.src(['assets/img/**/*', '!assets/images/raw/**'])
     .pipe(gulp.dest(build+'assets/img/'))
     .pipe(plugins.notify({ message: 'Images copied to buildTheme folder', onLast: true }));
});

 /**
  * Zipping build directory for distribution
  *
  * Taking the build folder, which has been cleaned, containing optimized files and zipping it up to send out as an installable theme
 */
 gulp.task('buildZip', function () {
  // return  gulp.src([build+'/**/', './.jshintrc','./.bowerrc','./.gitignore' ])
  return  gulp.src(build+'/**/')
     .pipe(zip(project+'.zip'))
     .pipe(gulp.dest('./'))
     .pipe(notify({ message: 'Zip task complete', onLast: true }));
 });


 // ==== TASKS ==== //
 /**
  * Gulp Default Task
  *
  * Compiles styles, fires-up browser sync, watches js and php files. Note browser sync task watches php files
  *
 */

 // Package Distributable Theme
 gulp.task('build', function(cb) {
  runSequence('styles', 'cleanup', 'vendorsJs', 'scriptsJs',  'buildFiles', 'buildImages', 'buildZip','cleanupFinal', cb);
 });


 // Watch Task
 gulp.task('default', ['styles', 'vendorsJs', 'scriptsJs', 'images', 'browser-sync'], function () {
  gulp.watch('./assets/img/raw/**/*', ['images']); 
  gulp.watch('./assets/css/**/*.scss', ['styles']);
  gulp.watch('./assets/js/**/*.js', ['scriptsJs', browserSync.reload]);

 });

Saturday, November 07, 2015

Synchronous and asynchronous sequential execution of functions

Synchronous and asynchronous sequential execution of functions

This blog post examines three ways of executing function sequentially:

  • Synchronously
  • Asynchronously, via Promises
  • Asynchronously, via the library co

Tuesday, October 13, 2015

Async/Await: The Hero JavaScript Deserved

Async/Await: The Hero JavaScript Deserved

Writing asynchronous code is hard. When it comes to JavaScript we rely heavily on callback functions to accomplish asynchronous tasks which can be unintuitive. This cognitive overhead creates a barrier to entry for newcomers to programming and the language and even causes frequent heartburn for those of us who have been using the language a while.

Wednesday, September 09, 2015

A Guide to Vanilla Ajax Without jQuery

A Guide to Vanilla Ajax Without jQuery
Short for Asynchronous JavaScript and XML, Ajax is a mechanism for making partial page updates. It enables you to update sections of a page with data that comes from the server, whilst avoiding the need for a full refresh. Making partial updates in this way can be effective in creating fluid user experiences and can decrease the load put on the server.

Tuesday, July 07, 2015

How to Become a Great JavaScript Developer

JavaScript Developer

When I was growing up, my interests spanned various, seemingly unrelated fields. I loved maths as much as I loved history. I aimed to be a Renaissance man -a polymath-, that excelled at multiple fields. This turned out to be an arduous task and suddenly I faced the danger of being a jack of all trades, master of none.

Sunday, May 31, 2015

A re-introduction to JavaScript (JS tutorial)

JavaScript
Why a re-introduction? Because JavaScript is notorious for being the world's most misunderstood programming language. While it is often derided as a toy, beneath its deceptive simplicity lie some powerful language features. JavaScript is now used by an incredible number of high-profile applications, showing that deeper knowledge of this technology is an important skill for any web or mobile developer.

Tuesday, April 14, 2015

Keeping it simple: coding a carousel

coding a carousel

One of the things that drives me crazy in our "modern development" world is our fetish of over-complicating things. We build solutions, and then we add layers and layers of complexity for the sake of "making them easier to maintain". In many cases, this is a fool's errand as the layers of complexity and with them the necessary documentation make people not use our solutions. Instead, in many cases, people build their own, simpler, versions of the same thing and call it superior. Until this solution gets disputed and the whole dance happens once again.

In this article I want to approach the creation of a carousel differently: by keeping it as simple as possible whilst not breaking backwards compatibility or have any dependencies. Things break on the web. JavaScript might not be loaded, CSS capabilities vary from browser to browser. It is not up to us to tell the visitor what browser to use. And as good developers we shouldn't create interfaces that look interactive but do nothing when you click them.

So, let's have a go at building a very simple carousel that works across browsers without going overboard. You can see the result and get the code on GitHub.

The HTML structure of a carousel

Let's start very simple: a carousel in essence is an ordered list in HTML. Thus, the basic HTML is something like this:

  1. 1
  2. 2
  3. 3
  4. 4

Using this, and a bit of CSS we have something that works and looks good. This is the base we are starting from.

The basic CSS

The CSS used here is simple, but hints at some of the functionality we rely on later:

.carouselbox {
  font-family: helvetica,sans-serif;
  font-size: 14px;
  width: 100px;
  position: relative;
  margin: 1em;
  border: 1px solid #ccc;
  box-shadow: 2px 2px 10px #ccc;
  overflow: hidden;
}

.content {
  margin: 0;
  padding: 0;
}

.content li {
  font-size: 100px;
  margin: 0;
  padding: 0;
  width: 100%;
  list-style: none;
  text-align: center;
}

The main thing here is to position the carousel box relatively, allowing us to position the list items absolutely inside it. This is how we'll achieve the effect. The hidden overflow ensures that later on only the current item of the carousel will be shown. As there is no height set on the carousel and the items aren't positioned yet, we now see all the items.

coding a carousel

The carousel visuals in CSS

A lot of carousel scripts you can find will loop through all the items, or expect classes on each of them. They then hide all and show the current one on every interaction. This seems overkill, if you think about it. All we need is two classes:

  • We need a class on the container element that triggers the functional display of our carousel. This one gets applied with JavaScript as this means the look and feel only changes when the browser is capable of showing the effect.
  • We need a class on the currently visible carousel element. This is the odd one out. All the others don't need any classes.

We can hard-code these for now:

  1. 1
  2. 2
  3. 3
  4. 4

All we need to show and hide the different carousel items is to change the height of the carousel container and position all but the current one outside this height:

.active {
  height: 130px;
}

.active li {
  position: absolute;
  top: 200px;
}

.active li.current {
  top: 30px;
}

You can see this in action here. Use your browser developer tools to move the current class from item to item to show a different one.

coding a carousel

Interaction with Javascript

To make the carousel work, we need controls. And we also need some JavaScript. Whenever you need a control that triggers functionality that only works when JavaScript is executed, a button is the thing to use. These magical things were meant for exactly this use case and they are keyboard, mouse, touch and pen accessible. Everybody wins.

In this case, I added the following controls in our HTML:

  1. 1
  2. 2
  3. 3
  4. 4

Now, here is where the hard-liners of semantic markup could chime in and chide me for writing HTML that is dependent on JavaScript instead of creating the HTML using JavaScript. And they'd be correct to do so. There is nothing that stops me from wrapping this chunk of HTML in a DOM call or innerHTML write-out. However, as buttons are meant to trigger JS functionality, I think it is easier to just keep that in the HTML and allow us thus to style them with much less hassle. As a security precaution, we hide them in the non-active state and show them when the "active" class has been applied:

.active .buttons {
  padding: 5px 0;
  background: #eee;
  text-align: center;
  z-index: 10;
  position: relative;
}

.carouselbox button {
  border: none;
  display: none;
}

.active button {
  display: block;
}

.offscreen {
  position: absolute;
  left: -2000px;
}

The offscreen parts are there to explain what these buttons really mean as the triangle is not enough for some people.

All that is left to make the carousel work is the JavaScript. And here it is:

carousel = (function(){
  var box = document.querySelector('.carouselbox');
  var next = box.querySelector('.next');
  var prev = box.querySelector('.prev');
  var items = box.querySelectorAll('.content li');
  var counter = 0;
  var amount = items.length;
  var current = items[0];
  box.classList.add('active');
  function navigate(direction) {
    current.classList.remove('current');
    counter = counter + direction;
    if (direction === -1 && 
        counter < 0) { 
      counter = amount - 1; 
    }
    if (direction === 1 && 
        !items[counter]) { 
      counter = 0;
    }
    current = items[counter];
    current.classList.add('current');
  }
  next.addEventListener('click', function(ev) {
    navigate(1);
  });
  prev.addEventListener('click', function(ev) {
    navigate(-1);
  });
  navigate(0);
})();
As you can see, by relying on CSS and its built-in crawling of the DOM, there is no need for any loop whatsover. Here's what's going on in this script:
  • We grab all the HTML elements we need with querySelector.
  • We set the counter to 0 – this is the variable that keeps track of which item of the carousel is currently shown.
  • We read the amount of items in the carousel and store them in a variable – this allows us to loop the carousel.
  • We set the current item as the first one in the carousel. The current variable will contain a reference to the element currently visible. All we do when the carousel state changes is remove the CSS class from it and shift it to the other one.
  • We add the class of active to the container element to change its styling and trigger the CSS functionality explained earlier.
  • The navigate method takes a parameter called direction which defines if we should go backwards (negative values) or forwards in the carousel. It starts by removing the current class from the current carousel item, thus hiding it. We then modify the counter and make sure it doesn't go beyond the amount of items available or below 0. In each case we move to the other extreme, thus making the carousel an endless rotating one. We define the new current item and add the class to show it.
  • We apply event handlers to the buttons to navigate forwards and backwards.
  • We show the first carousel item by calling navigate with 0 as the value.
Pretty simple, isn't it? By allowing CSS to do what it is good at, our JavaScript more or less is only about keeping state and shifting classes around.

Getting fancy

The showing and hiding of the items by positioning them in a container with overflow hidden should work in any browser in use these days – even the ones who should be retired. And as all we do is add and remove CSS classes, we can now tap into the beautiful features browsers have these days. Using transition, opacity and transformation, we can add a pretty effect with a few lines of CSS:

.active li {
  position: absolute;
  top: 130px;
 
  opacity: 0;
  transform: scale(0);
  transition: 1s;
}

.active li.current {
  top: 30px;
 
  opacity: 1;
  transform: scale(1);
  transition: 1s;
}

coding a carousel
The beauty of this is that the performance handling, the timing (in case you click too fast) is handled by the browser for us. No need to count FPS or juggle timeouts. As CSS is a one-off state, this also means that browsers that do not support these features simply don't show them instead of throwing an error.

Bullet-proofing our Javascript

When a browser in use doesn't support some JavaScript feature we use, things get trickier. We get an error and things break. Thus, it makes sense to test for the things we use and move on only when there is support for them. In this code, we rely on classList and querySelector, so let's just check for this:

if (!document.querySelector || !('classList' in document.body)) {
    return false;
}

We could get much more paranoid and ensure that all the DOM elements are available before proceeding but this is overkill. If a maintainer forgets to add the carouselbox class to the main element, the error thrown is pretty obvious.

Bonus round: stacking with CSS

One last trick to mention is that if you were to stack all the elements of the carousel visually and only use opacity to blend them then there is a problem with links. You'd always get the link of the first item, no matter which one is shown.

The trick to work around that is user pointer-events: none in your CSS:

.active li {
  position: absolute;
  top: 130px;
 
  pointer-events: none;
  opacity: 0;
  transform: scale(0);
  transition: 1s;
}

.active li.current {
  top: 30px;
 
  pointer-events: auto;
  opacity: 1;
  transform: scale(1);
  transition: 1s;
}

You can see this workaround in action here.

Where to go now

The natural drive as a developer now is to enhance this to allow users to define a different starting element to show, to define lots of preset effects that can be chosen with the data attribute, to allow for non-looping carousels and to define an API to allow other components on the page to interact with the carousel. And an API to create and remove and shuffle items of the carousel. And, and and... All of these are great exercises, but let's ask ourselves: who do we do that for?

We have such amazing functionality built into the platform of the web now. Maybe it is time to stop writing the perfect generic re-usable widget and just stick with simple things and let people extend them when they need to? Who knows, by not doing the work for them, people might learn to be better coders themselves.

Tuesday, April 07, 2015

Simple Inheritance with JavaScript

Simple Inheritance with JavaScript

JavaScript uses a different approach than C# or C++ to create an object-oriented language. It is a prototype-based language. The concept of prototyping implies that behavior can be reused by cloning existing objects that serve as prototypes. Every object in JavaScript decends from a prototype which defines a set of functions and members that the object can use. There is no class. Just objects. Every object can then be used as a prototype for another object.

This concept is extremely flexible and we can use it to simulate some concepts from OOP like inheritance.

Implementing Inheritance

Let's visualize what we want to create with this hierarchy using JavaScript:

Simple Inheritance with JavaScript

First of all, we can create ClassA easily. Because there are no explicit classes, we can define a set of behavior (A class so…) by just creating a function like this:

var ClassA = function() {
    this.name = "class A";
}

This "class" can be instantiated using the new keyword:

var a = new ClassA();
ClassA.prototype.print = function() {
    console.log(this.name);
}

And to use it using our object:

a.print();

Fairly simple, right?

The complete sample is just 8 lines long:

var ClassA = function() {
    this.name = "class A";
}
 
ClassA.prototype.print = function() {
    console.log(this.name);
}
 
var a = new ClassA();
 
a.print();

Now let's add a tool to create "inheritance" between classes. This tool will just have to do one single thing: clone the prototype:

var inheritsFrom = function (child, parent) {
    child.prototype = Object.create(parent.prototype);
};

This is exactly where the magic happens! By cloning the prototype, we transfer all members and functions to the new class.

So if we want to add a second class that will be a child of the first one, we just have to use this code:

var ClassB = function() {
    this.name = "class B";
    this.surname = "I'm the child";
}
 
inheritsFrom(ClassB, ClassA);

Then because ClassB inherited the print function from ClassA, the following code is working:

var b = new ClassB();
b.print();

And produces the following output:

class B

We can even override the print function for ClassB:

ClassB.prototype.print = function() {
    ClassA.prototype.print.call(this);
    console.log(this.surname);
}

In this case, the produced output will look like this:

class B 
I'm the child

The trick here is to the call ClassA.prototype to get the base print function. Then thanks to call function we can call the base function on the current object (this).

Creating ClassC is now obvious:

var ClassC = function () {
    this.name = "class C";
    this.surname = "I'm the grandchild";
}
 
inheritsFrom(ClassC, ClassB);
 
ClassC.prototype.foo = function() {
    // Do some funky stuff here...
}
 
ClassC.prototype.print = function () {
    ClassB.prototype.print.call(this);
    console.log("Sounds like this is working!");
}
 
var c = new ClassC();
c.print();

And the output is:

class C 
I'm the grandchild 
Sounds like this is working!

More Hands-on with JavaScript

It might surprise you a bit, but Microsoft has a bunch of free learning on many open source JavaScript topics and we’re on a mission to create a lot more with Project Spartan coming. Check out my own:


And some free tools: Visual Studio Community, Azure Trial, and cross-browser testing tools for Mac, Linux, or Windows.

Tuesday, March 31, 2015

A Baseline for Front-End [JS] Developers: 2015

A Baseline for Front-End [JS] Developers
It's been almost three years since I wrote A Baseline for Front-End Developers, probably my most popular post ever. Three years later, I still get Twitter mentions from people who are discovering it for the first time.

In some ways, my words have aged well: there is, shockingly, nothing from that 2012 post that has me hanging my head in shame. Still, though: three years is a long time, and a whole lot has changed. In 2012 I encouraged people to learn browser dev tools and get on the module bandwagon; CSS pre-processors and client-side templating were still worthy of mention as new-ish things that people might not be sold on; and JSHint was a welcome relief from the #getoffmylawn admonitions – accurate though they may have been – of JSLint.

It's 2015. I want to write an update, but as I sit down to do just that, I realize a couple of things. One, it's arguably not fair to call this stuff a "baseline" – if you thought that about the original post, you'll find it doubly true for this one. One could argue we should consider the good-enough-to-get-a-job skills to be the "baseline". But there are a whole lot of front-end jobs to choose from, and getting one doesn't establish much of a baseline. For me, I don't want to get a job; I want to get invited to great jobs. I don't want to go to work; I want to go to work with talented people. And I don't want to be satisfied with knowing enough to do the work that needed to be done yesterday; I want to know how to do the work that will need to get done tomorrow.

Two, my world has become entirely JavaScript-centric: knowledge of the ins and outs of CSS has become less and less relevant to my day-to-day work, except where performance is concerned. I know there are plenty of very smart front-end developers for whom this isn't true, but I have also noticed a growing gulf between those who focus on CSS and those who focus on JavaScript. That's probably a subject for another blog post, but I bring it up just to say: I am woefully unequipped to make recommendations about what you should know about CSS these days, so I'm not going to try.

In short: if this list of things doesn't fit your vision of the front-end world, that's OK! We're both still good people. Promise.

JavaScript

Remember back in 2009 when you read that HTML5 would be ready to use in 2014, and that seemed like a day that would never come? If so, you're well prepared for the slow-but-steady emergence of ES6 (which is now called ES2015, a name that is sure to catch on any day now), the next version of JavaScript. Getting my bearings with ES6 – er, ES2015 – is hands-down my biggest JavaScript to-do item at the moment; it is going to be somewhere between game-changing and life-altering, what with classes, real privacy, better functions and arguments, import-able modules, and so much more. Those who are competent and productive with the new syntax will have no trouble standing out in the JS community. Required reading:

  • Understanding ES6, a work-in-progress book being developed in the open by Nicholas Zakas.
  • BabelJS, a tool that lets you write ES6 today and "compile" it to ES5 that will run in current browsers. They also have a good learning section.
  • ES6 Rocks, with various posts that explore ES6 features, semantics, and gotchas.

Do you need to be an ES6/ES2015 expert? Probably not today, but you should know at least as much about it as your peers, and possibly more. It's also worth at least entertaining the possibility of writing your next greenfield project using ES6; the future will be here before you know it.

New language features aside, you should be able to speak fluently about the asynchronicity of JavaScript, and using callbacks and promises to manage it. You should have well-formed opinions about strategies for loading applications in the browser and communicating between pieces of an application. You should maybe have a favorite application development framework, but not at the expense of having a general understanding of how other frameworks operate, and the tradeoffs you accept when you choose one.

Modules & Build Tools

There's no debate that modules should be the building blocks of client-side web applications. Back in 2012, there was lots of debate about what kind of modules we should use for building apps destined for the browser – AMD or CommonJS. The somewhat-gross UMD wrapper arose to try to avoid answering the question while still allowing code reuse – because hey, what's a few more bytes between friends?

I don't feel like this debate is anywhere near resolved, but this is the area where I feel like we've seen the largest transformation since my 2012 article, though perhaps that's a reflection of my personal change of heart. I'm not ready to say that I'm done with AMD, but let's just say I'm floored by how practical it has become to develop and deploy web applications using CommonJS, including modules imported with npm.

With much love for all that RequireJS has contributed to the module conversation, I'm a bit enamored of webpack right now. Its features – such as easy-to-understand build flags – feel more accessible than RequireJS. Its hot-swap builds via its built-in dev server make for a fast and delightful development story. It doesn't force an AMD vs. CommonJS decision, because it supports both. It also comes with a ton of loaders, making it fairly trivial to do lots of common tasks. Browserify is worth knowing about, but lags far behind Webpack in my opinion. Smart people I trust tell me that systemjs is also a serious contender in this space, but I haven't used it yet, and its docs leave me wanting. Its companion package manager jspm is intriguing, allowing you to pull in modules from multiple sources including npm, but I'm a bit wary of combining those two concerns. Then again, I never thought I'd break up with AMD, yet here I seem to be, so we'll see.

I still long for a day when we stop having module and build tool debates, and there is a single module system and sharing code between arbitrary projects becomes realistic and trivial without the overhead of UMD. Ideally, the arrival of ES6 modules will bring that day – and transpilers will fill in the gaps as the day draws closer – but I find it just as likely that we'll keep finding ways to make it complicated.

In the meantime, front-end developers need to have an opinion about at least a couple of build tools and the associated module system, and that opinion should be backed up by experience. For better or worse, JavaScript is still in a state where the module decision you make will inform the rest of your project.

Testing

Testing of client-side code has become more commonplace, and a few new testing frameworks have arrived on the scene, including Karma and Intern. I find Intern's promise-based approach to async testing to be particularly pleasing, though I confess that I still write most of my tests using Mocha – sometimes I'm just a creature of habit.

The main blocker to testing is the code that front-end devs tend to write. I gave a talk toward the end of 2012 about writing testable JavaScript, and followed up with an article on the topic a few months later.

The second biggest blocker to testing remains the tooling. Webdriver is still a huge pain to work with. Continuous automated testing of a complex UI across all supported browsers continues to be either impossible, or so practically expensive that it might as well be impossible – and never mind mobile. We're still largely stuck doing lightweight automated functional tests on a small subset of supported browser/device/OS combinations, and leaning as hard as we can on lower-level tests that can run quickly and inexpensively. This is a bummer.

If you're interested in improving the problem of untested – or untestable – code, the single most valuable book you can read is Working Effectively with Legacy Code. The author, Michael Feathers, defines "legacy code" as any code that does not have tests. On the topic of testing, the baseline is to accept the truth of that statement, even if other constraints are preventing you from addressing it.

Process Automation

You, hopefully, take for granted the existence of Grunt for task automation. Gulp and Broccoli provide a different approach to automating builds in particular. I haven't used Broccoli, and I've only dabbled in Gulp, but I've definitely come to appreciate some of the limitations of Grunt when it comes to automating complex tasks that depend on other services – especially when that task needs to run thousands of times a day.

The arrival of Yeoman was a mere 45 days away when I wrote my 2012 post. I confess I didn't use it when it first came out, but recently I've been a) starting projects from scratch using unfamiliar tech; and b) trying to figure out how to standardize our approach to developing third-party JS apps at Bazaarvoice. Yeoman really shines in both of these cases. A simple yo react-webpack from the command line creates a whole new project for you, with all the bells and whistles you could possibly want – tests, a dev server, a hello world app, and more. If React and Webpack aren't your thing, there's probably a generator to meet your needs, and it's also easy to create your own.

Given that Yeoman is a tool that you generally use only at the start of a project, and given that new projects don't get started all the time, it's mostly just something worth knowing about. Unless, of course, you're also trying to standardize practices across projects – then it might be a bit more valuable.

Broccoli has gotten its biggest adoption as the basis for ember-cli, and folks I trust suggest that pairing may get a makeover – and a new name – to form the basis of a Grunt/Yeoman replacement in the future. Development on both Grunt and Yeoman has certainly slowed down, so it will be interesting to see what the future brings there.

Code Quality

If you, like me, start to twitch when you see code that violates a project's well-documented style guide, then tools like JSCS and ESLint are godsends, and neither of them existed for you to know about them back in 2012. They both provide a means to document your style guide rules, and then verify your code against those rules automatically, before it ever makes it into a pull request. Which brings me to…

Git

I don’t think a whole lot has changed in the world of Git workflows since 2012, and I'd like to point out Github still hasn't made branch names linkable on the pull request page, for f@#$s sake.

You should obviously be comfortable working with feature branches, rebasing your work on the work of others, squashing commits using interactive rebase, and doing work in small units that are unlikely to cause conflicts whenever possible. Another Git tool to add to your toolbox if you haven't already is the ability to run hooks – specifically, pre-push and pre-commit hooks to run your tests and execute any code quality checks. You can write them yourself, but tools like ghooks make it so trivial that there's little excuse not to integrate them into your workflow.

Client-Side Templating

This may be the thing I got the most wrong in my original post, for some definition of "wrong". Client-side templating is still highly valuable, of course – so valuable that it will be built-in to ES2015 – but there can be too much of a good thing. It's been a hard-earned lesson for lots of teams that moving all rendering to the browser has high costs when it comes to performance, and thus has the "generate all the HTML client-side" approach rightfully fallen out of favor. Smart projects are now generating HTML server-side – maybe even pre-generating it, and storing it as static files that can be served quickly – and then "hydrating" that HTML client-side, updating it with client-side templates as events warrant.

The new expectation here – and I say this to myself as much as to anyone else – is that you are considering the performance implications of your decisions, and maybe not restricting yourself quite so thoroughly to the realm of the browser. Which, conveniently, leads to…

Node

You say you know JavaScript, so these days I expect that you can hop on over to the Node side of things and at least pitch in, if not get at least knee-deep. Yes, there are file systems and streams and servers – and some paradigms that are fundamentally different from front-end dev – but front-end developers who keep the back end at arm's length are definitely limiting their potential.

Even if your actual production back-end doesn't use Node, it's an invaluable tool when it comes to keeping you from getting blocked by back-end development. At the very least, you should be familiar with how to initialize a Node project; how to set up an Express server and routes; and how use the request module to proxy requests.

via rmurphey.com by

Sunday, June 29, 2014

How to Learn AngularJS - Your AngularJS Sherpa

AngularJS
Learning AngularJS can be complex. There are an overwhelming number resources available on the web. The blog posts can be conflicting and confusing, and a simple google search can turn up 5 articles all describing the same thing in a completely different way.

Sunday, May 25, 2014

Frame-by-frame animation with HTML and JavaScript

Frame-by-frame animation with HTML and JavaScript

Animations can make your project stand out from the crowd. Good animations enhance the user interface, make navigation feel smoother and offer a superior esthetic experience (bad animation does the opposite, so be careful). Modern browsers support animations quite well, but there are so many different ways of animating HTML elements that it often confuses even experienced developers.

Saturday, May 24, 2014

JavaScript Prototypes, Scopes, and Performance: What You Need to Know

JavaScript: More than meets the eye

JavaScript can seem like a very easy language to learn at first. Perhaps it's because of its flexible syntax. Or perhaps it's because of its similarity to other well known languages like Java. Or perhaps it's because it has so few data types in comparison to languages like Java, Ruby, or .NET.

Saturday, May 24, 2014

Parallax Done Right

Parallax Done Right

Getting great performance with parallax is tough. Here's how to make it happen.

Tldr; There are an easy handful of things you can do to get buttery parallax scroll. Check out a demo I cooked up to see it in action.

Saturday, May 10, 2014

The Absolute Beginner's Guide to Node.js

The Absolute Beginner's Guide to Node.js

This is a republished blog post by Brandon Cannaday. Brandon is the CTO of Modulus, a Node.js application hosting platform. Brandon organizes the Indianapolis Node.js meetup and enjoys speaking at conferences about Node's horizontal scalability. Prior to Modulus, Brandon worked in the chemical detection and telecommunications industries.

Monday, May 05, 2014

Injecting SVG With JavaScript

Injecting SVG With JavaScript

"Injecting SVG" – it sounds kinda complicated I know, but trust me it's not. It's actually super-simple! Right now you're probably thinking "Why would you use JavaScript to inject SVG markup? What is it? And how does it work?". Let me explain.

Saturday, April 26, 2014

Using Media Queries in JavaScript

Using Media Queries in JavaScript

If you practice responsive design then you use a lot of media queries. Media Queries are a CSS feature that gives designers the power to add something like if statements. By this I mean that it allows you to apply rules only if the current page meets certain conditions. In this article I'll show you how I use media queries in JavaScript.

Saturday, April 26, 2014

How to Create Custom HTML Elements

Custom HTML Elements
Photo by Kenny Louie / Flickr

An exciting feature of the HTML specification that's been getting a bit of hype recently is custom HTML elements. These allow you to create your own HTML elements along with their own JavaScript API. This can be useful when building interfaces with components that are reused throughout an application.

Sunday, March 09, 2014

Why You Should Care About Web Components

Web Components
Since there is no standard way to define a component, every framework has to invent its own and JavaScript is a flexible enough language to allow that. Unfortunately, this results in fragmentation: components built using different frameworks do not interoperate with each other. Web components are a set of specifications solving this problem.

Two Date Pickers

Let's take a simple component that you are likely to see in pretty much any application - the date picker component.

Friday, January 31, 2014

Scattered Polaroids Gallery

A flat-style Polaroid gallery where the items are scattered randomly in a container. When a specific item is selected, it will move to the middle while the other Polaroids will make space for it by moving to the sides. Optionally, an item can have a backface which will be shown by flipping the Polaroid when clicking on the current navigation dot again.

Scattered Polaroids Gallery

Monday, January 27, 2014

Validation and Exception Handling: From the UI to the Backend

Sooner or later in your programming career you will be faced with the dilemma of validation and exception handling. This was the case with me and my team also. A couple or so years ago we reached a point when we had to take architectural actions to accommodate all the exceptional cases our quite large software project needed to handle. Below is a list of practices we came to value and apply when it comes to validation and exception handling.