devObjective Automate Your Site's Front End Performance

devObjective Automate Your Site's Front End Performance

Automating your site's front-end performance metric gathering using Grunt, grunt-based tools and Webpagetest. No devops experience needed.

3f2f0c0fbc7be587727cdfff33c8be43?s=128

Kitt Hodsden

May 14, 2015
Tweet

Transcript

  1. 10.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 10 Determine key metrics

    Establish a baseline Make a change Measure effects
  2. 11.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 11 Determine key metrics

    Establish a baseline Make a change Measure effects
  3. 13.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 13 40% will abandon

    a website that takes more than 3 seconds to load.
  4. 49.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 49 { "engines": {

    "node": ">= 0.12.0" }, "devDependencies": { "grunt": "~0.4.2", "grunt-contrib-jshint": "~0.7.2", "grunt-contrib-watch": "~0.5.3", } } This is what a package.json file looks like
  5. 50.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 50 { "engines": {

    "node": ">= 0.12.0" }, "devDependencies": { "grunt": "~0.4.2", "grunt-contrib-jshint": "~0.7.2", "grunt-contrib-watch": "~0.5.3", } } This is what a package.json file looks like
  6. 51.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 51 $ npm install

    With a package.json file, you can install the needed packages easily.
  7. 52.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 52 $ npm install

    No -g here! With a package.json file, you can install the needed packages easily.
  8. 53.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 53 $ ls Gemfile

    README.txt fonts node_modules tpl Gemfile.lock config.rb img package.json widgets Gruntfile.js css js scss
  9. 54.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 Check dependencies into the

    repo? http://addyosmani.com/blog/checking-in-front-end-dependencies/ http://redotheweb.com/2013/09/12/should-you-commit-dependencies.html 54 Total sidebar on checking dependencies into the repo or not
  10. 55.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 55 module.exports = function(grunt)

    { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%="yyyy-mm-dd") %> */\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); };
  11. 56.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 56 module.exports = function(grunt)

    { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%="yyyy-mm-dd") %> */\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); }; A basic Gruntfile.js file
  12. 57.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 57 module.exports = function(grunt)

    { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%="yyyy-mm-dd") %> */\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); }; A basic Gruntfile.js file
  13. 58.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 58 module.exports = function(grunt)

    { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%="yyyy-mm-dd") %> */\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); }; A basic Gruntfile.js file
  14. 60.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 60 ... // load

    all the grunt modules instead of one each line require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks); grunt.registerTask('checkjs', ['jshint']); grunt.registerTask('watchjs', ['jshint', 'watch']); grunt.registerTask('gruntjs', ['jshint:gruntfile', 'watch']);
  15. 64.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 64 devperf: { options:

    { urls: [ 'http://localhost:8000' ] } } … grunt.registerTask('pe', ['devperf']);
  16. 66.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 66 … devperf: {

    options: { urls: [ 'http://fromthemiddle.io/' ], numberOfRuns: 5, openResults: true, resultsFolder: './devperf', phantomasOptions: { 'film-strip': true } } } … grunt.registerTask('pe', ['devperf']);
  17. 76.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 Remove HTML Comments? 76

    https://github.com/gruntjs/grunt-contrib-htmlmin
  18. 78.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 78 … htmlmin: {

    dist: { options: { removeComments: true, collapseWhitespace: true }, files: { 'dist/index.html': 'src/index.html', 'dist/contact.html': 'src/contact.html' } }, dev: { files: { 'dist/index.html': 'src/index.html', 'dist/contact.html': 'src/contact.html' } } } … grunt.registerTask(‘comments-be-gone‘, ['htmlmin']);
  19. 85.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 npm install grunt-cssstats --save-dev

    85 https://github.com/cssstats/grunt-cssstats Look at the site’s CSS statistics
  20. 92.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 92 grunt-cssstats configuration https://github.com/cssstats/grunt-cssstats

    cssstats: { dev: { options: {}, files: { 'stats/css-stats.json': ['css/example.css'] }, } } … grunt.registerTask('stats', ['cssstats']);
  21. 93.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 93 grunt-cssstats configuration https://github.com/cssstats/grunt-cssstats

    cssstats: { dev: { options: { safe: false }, // Barf on invalid CSS files: { 'stats/cssstats-dev.json': ['app/styles/main.css'] } }, prod: { files: { 'stats/cssstats.json': ['dist/styles.css'] } } }
  22. 94.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 94 grunt-cssstats configuration https://github.com/cssstats/grunt-cssstats

    cssstats: { dev: { options: { safe: false }, // Barf on invalid CSS files: { 'stats/cssstats-dev.json': ['app/styles/main.css'] } }, prod: { files: { 'stats/cssstats.json': ['dist/styles.css'] } } }
  23. 100.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 100 grunt.initConfig({ montage: {

    iconaroo: { files: { "images/sprites": [ "images/icons/*.png" ] }, options: { size: 32, outputImage: "sprite-icons.png", outputStylesheet: "sprite-icons.css" } } } }); Sample grunt-montage configuration
  24. 102.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 102 imagemin: { prod:

    { files: [{ expand: true, cwd: 'imgs-src/', src: ['**/*.{png,jpg,gif}'], dest: 'imgs/' }] } }
  25. 104.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 104 grunt.initConfig({ svgmin: {

    // Task options: { // Configuration that will be passed directly to SVGO plugins: [ { removeViewBox: false }, { removeUselessStrokeAndFill: false } ] }, dist: { // Target files: [{ // Dictionary of files expand: true, // Enable dynamic expansion. cwd: 'img/src', // Src matches are relative to this path. src: ['**/*.svg'], // Actual pattern(s) to match. dest: 'img/', // Destination path prefix. ext: '.min.svg' // Dest filepaths will have this extension. // ie: optimise img/src/branding/logo.svg and store it in img/branding/logo.min.svg }] } }); grunt.loadNpmTasks('grunt-svgmin'); grunt.registerTask('default', ['svgmin']); Sample grunt-svgmin configuration
  26. 106.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 npm install grunt-responsive-images --save-dev

    106 Responsive images by resizing https://github.com/andismith/grunt-responsive-images
  27. 107.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 107 grunt.initConfig({ responsive_images: {

    myTask: { options: { sizes: [{ width: 320, height: 240 },{ name: 'large', width: 640 },{ name: "large", width: 1024, suffix: "_x2", quality: 60 }] }, files: [{ expand: true, src: ['assets/**.{jpg,gif,png}'], cwd: 'test/', dest: 'resize/{%= width %}/' }] } }, }); Sample grunt-responsive-images configuration
  28. 108.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 npm install grunt-grunticon --save-dev

    108 SVG with PNG fallbacks https://github.com/filamentgroup/grunticon
  29. 117.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 117 http://www.webpagetest.org/getkey.php Limits of

    public use The API key is provisioned for up to 200 page loads per day … sufficient for most low-volume use cases and for building a proof-of- concept for larger testing
  30. 121.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 121 perfbudget: { default:

    { options: { url: ‘http://example.io/', key: 'PUT_YOUR_API_KEY_HERE' } } } … grunt.registerTask('budg', ['perfbudget']);
  31. 122.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 122 perfbudget: { default:

    { options: { url: 'http://fromthemiddle.io/', key: 'thisismykey', wptInstance: 'ec2.us-west-2.amazonaws.com', location: 'us-west-2_wptdriver', pollResults: 10, connectivity: '3G', runs: 1, timeout: 240 } } }
  32. 123.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 123 perfbudget: { default:

    { options: { url: 'http://fromthemiddle.io/', key: 'thisismykey', wptInstance: 'ec2.us-west-2.amazonaws.com', location: 'us-west-2_wptdriver', pollResults: 10, connectivity: '3G', runs: 1, timeout: 240 } } }
  33. 124.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 124 perfbudget: { default:

    { options: { url: 'http://fromthemiddle.io/', key: 'thisismykey', wptInstance: 'ec2.us-west-2.amazonaws.com', location: 'us-west-2_wptdriver', pollResults: 10, connectivity: '3G', runs: 1, timeout: 240 } } }
  34. 126.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 126 perfbudget: { default:

    { options: { url: 'http://fromthemiddle.io/', … connectivity: '3G', timeout: 240, budget: { render: '3000', SpeedIndex: '7500', visualComplete: '6000' } } } }
  35. 134.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 npm install grunt-wpt --save-dev

    134 https://github.com/sideroad/grunt-wpt https://github.com/sideroad/grunt-wpt-page
  36. 135.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 135 wpt: { options:

    { url: 'http://fromthemiddle.io/', server: 'ec2.us-west-2.amazonaws.com', dest: 'wpt/' }, ftm: { options: { server: 'http://ec2.us-west-2.amazonaws.com', url: ['http://fromthemiddle.io/'] }, dest: 'wpt/', } } … grunt.registerTask('wptrun', ['wpt']);
  37. 138.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 npm install grunt-shell --save-dev

    138 Installing the grunt shell package to get to everything else
  38. 139.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 139 function log(err, stdout,

    stderr, cb) { console.log(stdout); cb(); } grunt.initConfig({ shell: { dirListing: { command: 'ls', options: { callback: log } } } });
  39. 144.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 144 $ cat tests.json

    [ { "name": "From the Middle", "url": "http://fromthemiddle.io/", "type": "home" }, { "name": "Kitt Hodsden", "url": "https://kitt.hodsden.org/", "type": "away" } ]
  40. 149.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 Worth looking at: https://github.com/andyshora/grunt-yslow

    https://github.com/jrcryer/grunt-pagespeed https://github.com/addyosmani/psi/ http://www.sitespeed.io/ http://perf-tooling.today/tools 149
  41. 182.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 182 $ vi ~/.ssh/authorized_keys

    dd # delete the first line [esc] # trigger the vi command sequence :wq # save the file and quit
  42. 183.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 183 sudo vi /var/www/webpagetest/www/settings/settings.ini

    # update publishTo with ec2 hostname # update ec2 = 0 # update ec2_locations = 0 # add EC2.us-west-2.securityGroup line from sample # add EC2.us-west-2.subnetId line from sample #
  43. 184.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 184 sudo vi /var/www/webpage/test/www/settings/keys.ini

    [server] secret=addarandomstringhere key=addakeyhere [addakeyhere] description=Web UI ;contact=me@me.com limit=0 [thisisyourapikey] description=API Key ;contact=me@me.com limit=0
  44. 185.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 185 $ cd /var/www/webpage/test/www/settings/

    $ sudo cp locations.ini.EC2-sample locations.ini # delete extra locations # update key values to your thisisyourkey value
  45. 188.

    Kitt Hodsden • @kitt • http://ki.tt/do2015 188 EC2 server key

    in settings.ini (more complicated to set up, better automation management)