Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Automating Your Workflow with Gulp.js - php[world] 2016

921 views

Published on

Gulp is a powerful utility for automating development workflows. Tasks are written using code, not configuration, enabling the easy creation of highly-custom and flexible automations. This talk introduces developers to the core concepts of gulp.js, and how to leverage it for new & existing projects. We’ll cover several examples of common tasks for managing CSS, JS and PHP, including: compiling Sass, minifying files, running PHP tests, checking code styles, ensuring legacy browser support & more.

Published in: Software

Automating Your Workflow with Gulp.js - php[world] 2016

  1. 1. Automating Your Workflow with Gulp.js php[world] 2016 @colinodell - joind.in/talk/17992
  2. 2. Colin O’Dell • Lead Web Developer at Unleashed Technologies • PHP League Member  league/commonmark  league/html-to-markdown • PHP 7 Upgrade Guide e-book @colinodell - joind.in/talk/17992
  3. 3. Agenda • What Are Task Runners? • Getting Started with Gulp.js • Gulp API • Task Examples • Q&A @colinodell - joind.in/talk/17992
  4. 4. What Are Task Runners? Software that automates, coordinates, and controls the process of running build tasks. • Define tasks & dependencies • Execute those tasks @colinodell - joind.in/talk/17992
  5. 5. What Are Task Runners? Three types of tasks: 1. Tranformations 2. Tests 3. Commands @colinodell - joind.in/talk/17992
  6. 6. Transformations • Compiling SASS/LESS, CoffeeScript, etc. • Combining/minifying files • Compressing images • Copying files to a different location @colinodell - joind.in/talk/17992 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010
  7. 7. Running Tests • Linting for syntax errors • Checking code styles • Running automated tests (unit, functional, etc) @colinodell - joind.in/talk/17992 0110011 1001111 0010011 1010010 ✓✗
  8. 8. Running Misc. Commands • Deleting previous builds • Installing dependencies with Composer, npm, bower, yarn, etc. • Any shell command @colinodell - joind.in/talk/17992 ✓✗
  9. 9. @colinodell - joind.in/talk/17992 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010 ✓✗ ✓✗
  10. 10. When/Where To Run Build Tasks • Locally during development • Continuous integration • Deployments @colinodell - joind.in/talk/17992
  11. 11. Different Task Runners Comparison between Apache Ant, Phing, Grunt, and Gulp @colinodell - joind.in/talk/17992
  12. 12. Apache Ant • Like Make, but built in Java • Typically installed via package manager (apt-get) • XML configuration files @colinodell - joind.in/talk/17992 <?xml version="1.0"?> <project name="Hello World Project" default="info"> <target name="info"> <echo>Hello World - Welcome to Apache Ant!</echo> </target> </project>
  13. 13. Apache Ant @colinodell - joind.in/talk/17992 <?xml version="1.0"?> <project name="Compress CSS and run PHPUnit" default="build"> <target name="build" depends="compress_css,phpunit"/> <target name="compress_css"> <apply executable="java" parallel="false"> <fileset dir="." includes="foo.css, bar.css"/> <arg line="-jar"/> <arg path="yuicompressor.jar"/> <srcfile/> <arg line="-o"/> <mapper type="glob" from="*.css" to="*-min.css"/> <targetfile/> </apply> </target> <target name="phpunit"> <exec executable="./vendor/bin/phpunit" failonerror="true"> <arg value="--configuration"/> <arg path="phpunit.xml"/> </exec> </target> </project>
  14. 14. Phing • Based on Apache Ant, but built in PHP • Typically installed via PEAR or Composer • XML configuration files @colinodell - joind.in/talk/17992 <?xml version="1.0"?> <project name="Hello World Project" default="info"> <target name="info"> <echo>Hello World - Welcome to Apache Ant!</echo> </target> </project>
  15. 15. Apache Ant @colinodell - joind.in/talk/17992 <?xml version="1.0"?> <project name="Compress CSS and run PHPUnit" default="build"> <target name="build" depends="compress_css,phpunit"/> <target name="compress_css"> <apply executable="java" parallel="false"> <fileset dir="." includes="foo.css, bar.css"/> <arg line="-jar"/> <arg path="yuicompressor.jar"/> <srcfile/> <arg line="-o"/> <mapper type="glob" from="*.css" to="*-min.css"/> <targetfile/> </apply> </target> <target name="phpunit"> <exec executable="./vendor/bin/phpunit" failonerror="true"> <arg value="--configuration"/> <arg path="phpunit.xml"/> </exec> </target> </project>
  16. 16. @colinodell - joind.in/talk/17992 <?xml version="1.0"?> <project name="Compress CSS and run PHPUnit" default="build"> <target name="build" depends="compress_css,phpunit"/> <target name="compress_css"> <apply executable="java" parallel="false"> <fileset dir="." includes="foo.css, bar.css"/> <arg line="-jar"/> <arg path="yuicompressor.jar"/> <srcfile/> <arg line="-o"/> <mapper type="glob" from="*.css" to="*-min.css"/> <targetfile/> </apply> </target> <target name="phpunit"> <phpunit pharlocation="./vendor/bin/phpunit" configuration="phpunit.xml"/> </target> </project>
  17. 17. Grunt • Built in JavaScript • Many third-party plugins; easy to install • JS-based configuration with heavy JSON usage @colinodell - joind.in/talk/17992 var grunt = require('grunt'); grunt.registerTask('default', 'The default build task', function(){ console.log('Hello World!'); });
  18. 18. @colinodell - joind.in/talk/17992 var grunt = require('grunt'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-phpunit'); grunt.initConfig({ cssmin: { target: { files: [{ src: ['foo.css', 'bar.css'], dest: 'build/css', ext: '.min.css' }] } }, phpunit: { options: { bin: 'vendor/bin/phpunit', configuration: 'phpunit.xml', coverage: false } } }); grunt.registerTask('default', 'The default build task', ['cssmin', 'phpunit']);
  19. 19. Gulp.js • Built in JavaScript • Many third-party plugins; easy to install • Uses JS code instead of configuration • Built around file streams @colinodell - joind.in/talk/17992 var gulp = require('gulp'); gulp.task('default', function() { console.log('Hello world.'); });
  20. 20. @colinodell - joind.in/talk/17992 var gulp = require('gulp'); var cssmin = require('gulp-minify-css'); var phpunit = require('gulp-phpunit'); var rename = require('gulp-rename'); gulp.task('cssmin', function() { return gulp.src(['foo.css', 'bar.css']) .pipe(minifycss()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest('build/css')); }); gulp.task('phpunit', function() { var options = { noCoverage: true }; return gulp.src('phpunit.xml') .pipe(phpunit('./vendor/bin/phpunit', options)); }); gulp.task('default', ['cssmin', 'phpunit']);
  21. 21. @colinodell - joind.in/talk/17992 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010 0110011 1001111 0010011 1010010 { … } 0110011 1001111 0010011 1010010
  22. 22. Getting Started with Gulp.js @colinodell - joind.in/talk/17992
  23. 23. Installing gulp-cli @colinodell - joind.in/talk/17992
  24. 24. Initializing npm @colinodell - joind.in/talk/17992
  25. 25. Adding gulp to a project @colinodell - joind.in/talk/17992
  26. 26. Adding gulp to a project @colinodell - joind.in/talk/17992
  27. 27. gulpfile.js @colinodell - joind.in/talk/17992 var gulp = require('gulp'); gulp.task('default', function() { // place code for your default task here });
  28. 28. gulpfile.js @colinodell - joind.in/talk/17992
  29. 29. Gulp API @colinodell - joind.in/talk/17992
  30. 30. gulp.task(name [, deps] [, fn]) • Defines tasks and their dependencies • Three parameters:  Name (required)  Array of task dependencies  Function to run @colinodell - joind.in/talk/17992 gulp.task('sometask', function() { // Do stuff }); gulp.task('sometask', ['dep1', 'dep2'], function() { // Do stuff }); gulp.task('js', ['jshint', 'jsmin']);
  31. 31. gulp.src(globs [, options]) • Two parameters:  Globs of files (required)  String or array  Options • Returns a stream of Vinyl files that can be piped to plugins @colinodell - joind.in/talk/17992 gulp.src('styles/foo.css') gulp.src('styles/*.css') gulp.src('styles/**/*.css') gulp.src(['styles/**/*.css', '!*.min.css'])
  32. 32. var themeBase = 'src/theme'; var distThemeBase = 'web/theme'; var paths = { img: [themeBase + '/img/**/*.{gif,png,jpg,svg,svgz}'], js: [themeBase + '/js/**/*.js'], font: [themeBase + '/fonts/**/*.{otf,eot,svg,ttf,woff,woff2}'], css: [themeBase + '/styles/**/*.css'], favicons: [themeBase + '/favicons/**/*.{png,xml,ico,json,svg}'], php: ['src/**/*.php'], xml: ['src/**/*.xml'], distContrib: distThemeBase + '/contrib/', distCSS: distThemeBase + '/css/', distJS: distThemeBase + '/js/', distImg: distThemeBase + '/img/', distFont: distThemeBase + '/fonts/', distFavicons: distThemeBase + '/favicons/' }; gulp.src(paths.css); @colinodell - joind.in/talk/17992
  33. 33. .pipe(destination) • Called on gulp.src() result stream • destination is a stream (typically an input stream created by a plugin) @colinodell - joind.in/talk/17992 return gulp.src(['foo.css', 'bar.css']) .pipe(minifycss()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest('build/css'));
  34. 34. gulp.dest(path [,options]) • Writes the streamed files to the given path @colinodell - joind.in/talk/17992 return gulp.src(['foo.css', 'bar.css']) .pipe(minifycss()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest('build/css'));
  35. 35. Examples Code Linting @colinodell - joind.in/talk/17992
  36. 36. jshint @colinodell - joind.in/talk/17992 var jshint = require('gulp-jshint'); gulp.task('jshint', function() { return gulp.src(paths.js) .pipe(jshint()) .pipe(jshint.reporter()) .pipe(jshint.reporter('fail')); });
  37. 37. jshint @colinodell - joind.in/talk/17992
  38. 38. csslint @colinodell - joind.in/talk/17992 var csslint = require('gulp-csslint'); gulp.task('csslint', function() { return gulp.src([paths.css, '!**/*.min.css']) .pipe(csslint('.csslintrc')) .pipe(csslint.reporter()) .pipe(csslint.failReporter()); });
  39. 39. phplint @colinodell - joind.in/talk/17992 var phplint = require('gulp-phplint'); gulp.task('phplint', function() { return gulp.src(paths.phpLint) .pipe(phplint()) .pipe(phplint.reporter('fail')); });
  40. 40. phpcs @colinodell - joind.in/talk/17992 var phpcs = require('gulp-phpcs'); gulp.task('phpcs', ['phplint'], function() { var options = { bin: 'vendor/bin/phpcs', standard: 'PSR2 }; return gulp.src(paths.php) .pipe(phpcs(options)) .pipe(phpcs.reporter('log')) .pipe(phpcs.reporter('fail')); });
  41. 41. eol @colinodell - joind.in/talk/17992 var eol = require('gulp-eol-enforce'); gulp.task('eol', function(){ var paths = [].concat(paths.php, paths.less, paths.js, paths.xml); return gulp.src(paths) .pipe(eol('n')); });
  42. 42. 'lint' task group @colinodell - joind.in/talk/17992 gulp.task('lint', ['eol', 'phpcs', 'csslint', 'jshint']); gulp.task('lint', function() { gulp.start('eol', 'phpcs', 'csslint', 'jshint'); });
  43. 43. Examples Transformations @colinodell - joind.in/talk/17992
  44. 44. Compile, autoprefix, and minify LESS @colinodell - joind.in/talk/17992 var autoprefixer = require('gulp-autoprefixer'), less = require('gulp-less'), minifycss = require('gulp-minify-css'), rename = require('gulp-rename') ; gulp.task('less', function() { return gulp.src(paths.less) .pipe(less()) .pipe(autoprefixer({ browsers: ['last 3 versions', 'ie >= 8'] })) .pipe(minifycss()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest(paths.distCSS)); });
  45. 45. Compile, autoprefix, and minify SASS @colinodell - joind.in/talk/17992 var autoprefixer = require('gulp-autoprefixer'), sass = require('gulp-sass'), minifycss = require('gulp-minify-css'), rename = require('gulp-rename') ; gulp.task('sass', function() { return gulp.src(paths.sass) .pipe(sass()) .pipe(autoprefixer({ browsers: ['last 3 versions', 'ie >= 8'] })) .pipe(minifycss()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest(paths.distCSS)); });
  46. 46. Compressing Images @colinodell - joind.in/talk/17992 var imagemin = require('gulp-imagemin'); gulp.task('images', function () { var options = { svgoPlugins: [{removeViewBox: false}] }; return gulp.src(paths.img) .pipe(imagemin(options)) .pipe(gulp.dest(paths.distImg)); });
  47. 47. Examples Unit Tests @colinodell - joind.in/talk/17992
  48. 48. PHPUnit Tests @colinodell - joind.in/talk/17992 var phpunit = require('gulp-phpunit'); gulp.task('phpunit', function () { return gulp.src('phpunit.xml') .pipe(phpunit('./vendor/bin/phpunit', {notify: true})); });
  49. 49. Examples Command Line Scripts @colinodell - joind.in/talk/17992
  50. 50. Run Shell Commands @colinodell - joind.in/talk/17992 var shell = require('gulp-shell'); gulp.task('deps', shell.task([ 'composer install', 'npm install', 'bower install' ]));
  51. 51. Examples Task Groups @colinodell - joind.in/talk/17992
  52. 52. Task Groups @colinodell - joind.in/talk/17992 gulp.task('lint', function() { gulp.start('eol', 'phpcs', 'csslint', 'jshint'); }); gulp.task('build', function() { gulp.start('css', 'images', 'js', 'fonts', 'favicons'); }); gulp.task('test', function() { gulp.start('lint', 'phpcs'); }); gulp.task('default', function() { gulp.start('test', 'build'); });
  53. 53. @colinodell - joind.in/talk/17992
  54. 54. @colinodell - joind.in/talk/17992
  55. 55. Useful Utilities @colinodell - joind.in/talk/17992
  56. 56. gulp-changed @colinodell - joind.in/talk/17992 var imagemin = require('gulp-imagemin'); gulp.task('images', function () { var options = { svgoPlugins: [{removeViewBox: false}] }; return gulp.src(paths.img) .pipe(imagemin(options)) .pipe(gulp.dest(paths.distImg)); });
  57. 57. gulp-changed @colinodell - joind.in/talk/17992 var changed = require('gulp-changed'); var imagemin = require('gulp-imagemin'); gulp.task('images', function () { var options = { svgoPlugins: [{removeViewBox: false}] }; return gulp.src(paths.img) .pipe(changed(paths.distImg)) .pipe(imagemin(options)) .pipe(gulp.dest(paths.distImg)); });
  58. 58. gulp-newer @colinodell - joind.in/talk/17992 var gulp = require('gulp'); var newer = require('gulp-newer'); var concat = require('gulp-concat'); gulp.task('concat', function() { return gulp.src('lib/*.js') .pipe(newer('dist/all.js')) .pipe(concat('all.js')) .pipe(gulp.dest('dist')); });
  59. 59. var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); gulp.task('build-js', function() { return gulp.src(paths.js) .pipe(concat('app.js')) .pipe(uglify()) .pipe(gulp.dest(paths.distJs)); }); gulp-sourcemaps @colinodell - joind.in/talk/17992
  60. 60. var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); gulp.task('build-js', function() { return gulp.src(paths.js) .pipe(sourcemaps.init()) .pipe(concat('app.js')) .pipe(uglify()) .pipe(sourcemaps.write()) .pipe(gulp.dest(paths.distJs)); }); gulp-sourcemaps @colinodell - joind.in/talk/17992
  61. 61. gulp-load-plugins @colinodell - joind.in/talk/17992 { "devDependencies": { "gulp": "~3.9", "gulp-autoprefixer": "~2.3.1", "gulp-bower": "~0.0.10", "gulp-changed": "~1.2.1", "gulp-csslint": "~0.1.5", "gulp-eol-enforce": "*", "gulp-imagemin": "~2.3.0", "gulp-jshint": "~1.11.2", "gulp-less": "~3.0.3", "gulp-minify-css": "~1.2.0", "gulp-phpcs": "~0.6.0", "gulp-rename": "~1.2.2", "gulp-uglify": "~1.2.0" } } var gulp = require('gulp'), autoprefixer = require('gulp-autoprefixer'), bower = require('gulp-bower'), changed = require('gulp-changed'), csslint = require('gulp-csslint'), eol = require('gulp-eol-enforce'), imagemin = require('gulp-imagemin'), jshint = require('gulp-jshint'), less = require('gulp-less'), minifycss = require('gulp-minify-css'), phpcs = require('gulp-phpcs'), rename = require('gulp-rename'), uglify = require('gulp-uglify');
  62. 62. gulp-load-plugins @colinodell - joind.in/talk/17992 { "devDependencies": { "gulp": "~3.9", "gulp-autoprefixer": "~2.3.1", "gulp-bower": "~0.0.10", "gulp-changed": "~1.2.1", "gulp-csslint": "~0.1.5", "gulp-eol-enforce": "*", "gulp-imagemin": "~2.3.0", "gulp-jshint": "~1.11.2", "gulp-less": "~3.0.3", "gulp-minify-css": "~1.2.0", "gulp-phpcs": "~0.6.0", "gulp-rename": "~1.2.2", "gulp-uglify": "~1.2.0" } } var gulp = require('gulp'), plugins = require('gulp-load-plugins')(); // ... .pipe(plugins.changed('app.css')) .pipe(plugins.less()) // ...
  63. 63. gulp.watch(paths, tasks) @colinodell - joind.in/talk/17992 gulp.task('watch', function() { gulp.watch(paths.less, ['css']); gulp.watch(paths.img, ['images']); gulp.watch(paths.js, ['js']); gulp.watch(paths.font, ['fonts']); gulp.watch(paths.favicons, ['favicons']); gulp.watch(paths.php, ['phpcs']); });
  64. 64. gulp.watch(paths, tasks) @colinodell - joind.in/talk/17992 • Example: https://youtu.be/9d9756j2pq8?t=100
  65. 65. Other Plugins & Integrations • Browsersync – Live browser reloads • gulp-notify – Sends notifications to OS notification center or Growl • gulp-autopolyfiller – Like autoprefixer, but for JS polyfills • gulp-git – Run Git commands within Gulp • gulp-ssh – Connect to servers via SSH and SFTP @colinodell - joind.in/talk/17992
  66. 66. Summary @colinodell - joind.in/talk/17992 • Task runners help automate build processes • Automate during development, CI, and deployment • Gulp is fast, easy-to-use, and has tons of great plugins
  67. 67. Questions? @colinodell - joind.in/talk/17992
  68. 68. Thanks! Slides/Feedback: https://joind.in/talk/17992 @colinodell - joind.in/talk/17992

×