Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Automating Web Performance

Dean Hume
October 28, 2015

Automating Web Performance

This workshop was first presented at OSCON Conference on the 28th October 2015. It was a joint workshop with Dean Hume (http://deanhume.com/) and Robin Osborne (http://robinosborne.co.uk/)

http://conferences.oreilly.com/oscon/open-source-eu-2015

Presentation Details
----------------------------------

According to the HTTP Archive, the average web page consumes about 2 MB of total transfer size. This worrying trend is growing year on year, and as developers we need to ensure that our web pages are as mean and lean as possible. The easiest way to do this and ensure that our web pages forever stay lean is to automate our web performance workflow. As the famous meme goes – Automate all the things!

If you are lazy developers like us, then you will understand the need to automate as much of your development workflow as possible. Automation makes life easier and reduces the need to manually recreate your steps every time. However, when it comes to the different automation options out there – where do you even begin?

There are amazing open source tools that can make life a lot easier. In this talk we will run through various open source tools and libraries, and a step-by-step automation example covering web techniques, such as:

- Image compression and optimization
- Responsive images
- WebP images
- Removing unused CSS
- Critical path CSS
- Testing and benchmarking
- How to integrate this all in a continuous integration process
- Build, deployment, hosting, scaling

By the end of the session, we hope that developers will have the knowledge required to set up and automate the performance workflow of their websites. Engineers will look to attend this presentation because they can learn how to automate the performance of their websites; simple improvements can really go a long way toward improving performance.

For more information on the code repository used in this workshop, please checkout - https://github.com/rposbo/bulky-bricks-inc

Dean Hume

October 28, 2015
Tweet

More Decks by Dean Hume

Other Decks in Programming

Transcript

  1. Automating
    WEB
    Performance

    View full-size slide

  2. Robin Osborne
    @rposbo

    View full-size slide

  3. Dean Hume
    @deanohume

    View full-size slide

  4. ASP.Net is Open Source!

    View full-size slide

  5. Does
    performance
    really matter?

    View full-size slide

  6. 2.2 SECONDS
    Increased downloads by 15.4%

    View full-size slide

  7. 2.2 SECONDS
    Increased downloads by 15.4%
    60 million more downloads

    View full-size slide

  8. People != Patience

    View full-size slide

  9. whatdoesmysitecost.com

    View full-size slide

  10. It all started with...

    View full-size slide

  11. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  12. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  13. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  14. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  15. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  16. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  17. RULES
    Make Fewer HTTP Requests
    Use a Content Delivery Network
    Add an Expires Header
    Gzip Components
    Put Stylesheets at the Top
    Put Scripts at the Bottom

    View full-size slide

  18. Web
    Performance
    ain’t easy!

    View full-size slide

  19. Manual Process

    View full-size slide

  20. HTML
    CSS
    Images

    View full-size slide

  21. HTML
    CSS
    JS
    Images

    View full-size slide

  22. Steps
    1. Images

    View full-size slide

  23. Steps
    1. Images
    2. CSS

    View full-size slide

  24. Steps
    1. Images
    2. CSS
    3. JavaScript

    View full-size slide

  25. Steps
    1. Images
    2. CSS
    3. JavaScript
    4. HTML

    View full-size slide

  26. Steps
    1. Images
    2. CSS
    3. JavaScript
    4. HTML
    5. Testing

    View full-size slide

  27. HTTP2
    HTTP2
    Approved

    View full-size slide

  28. TAKE A BREAK

    View full-size slide

  29. tinyurl.com/bulkybricks

    View full-size slide

  30. index products

    View full-size slide

  31. index products
    product

    View full-size slide

  32. index products
    product
    contact

    View full-size slide

  33. index products
    product
    contact about

    View full-size slide

  34. Material Design Lite

    View full-size slide

  35. getmdl.io/started

    View full-size slide

  36. whatdoesmysitecost.com

    View full-size slide

  37. Amsterdam
    Home page

    View full-size slide

  38. Amsterdam
    Home page - 21 seconds

    View full-size slide

  39. Amsterdam
    Home page - 21 seconds & cost 5c

    View full-size slide

  40. Amsterdam
    Home page - 21 seconds & cost 5c
    Product page

    View full-size slide

  41. Amsterdam
    Home page - 21 seconds & cost 5c
    Product page - 22 seconds

    View full-size slide

  42. Amsterdam
    Home page - 21 seconds & cost 5c
    Product page - 22 seconds & cost 35c

    View full-size slide

  43. webpagetest.org

    View full-size slide

  44. developers.google.com/speed/pagespeed/insights/

    View full-size slide

  45. Automate Measuring

    View full-size slide

  46. Automate all
    the things

    View full-size slide

  47. Begin the journey
    tinyurl.com/bulkybricks

    View full-size slide

  48. optimise
    before
    deploying

    View full-size slide

  49. 764
    15,758
    145
    1,283,067
    1,691
    Grunt
    Gulp
    601
    9,883
    55
    1,356,374
    4,403
    Watchers
    Stars
    Contributors
    Downloads
    Plugins
    August 2015

    View full-size slide

  50. mod_pagespeed
    optimise
    after
    deploying

    View full-size slide

  51. 1. NodeJS
    GruntFile

    View full-size slide

  52. 1. NodeJS
    GruntFile
    2. Grunt

    View full-size slide

  53. 1. NodeJS
    GruntFile
    2. Grunt 3. GruntFile

    View full-size slide

  54. npm install grunt

    View full-size slide

  55. npm install -g grunt-cli

    View full-size slide

  56. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    cssmin: {
    dist: {
    files: [
    { src: 'stylesheets/about.css', dest: 'stylesheets/about.min.css' },
    { src: 'stylesheets/articles.css', dest: 'stylesheets/articles.min.css' },
    ]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    // Default tasks.
    grunt.registerTask('default', ['cssmin']);
    };

    View full-size slide

  57. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    cssmin: {
    dist: {
    files: [
    { src: 'stylesheets/about.css', dest: 'stylesheets/about.min.css' },
    { src: 'stylesheets/articles.css', dest: 'stylesheets/articles.min.css' },
    ]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    // Default tasks.
    grunt.registerTask('default', ['cssmin']);
    };

    View full-size slide

  58. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    cssmin: {
    dist: {
    files: [
    { src: 'stylesheets/about.css', dest: 'stylesheets/about.min.css' },
    { src: 'stylesheets/articles.css', dest: 'stylesheets/articles.min.css' },
    ]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    // Default tasks.
    grunt.registerTask('default', ['cssmin']);
    };

    View full-size slide

  59. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    cssmin: {
    dist: {
    files: [
    { src: 'stylesheets/about.css', dest: 'stylesheets/about.min.css' },
    { src: 'stylesheets/articles.css', dest: 'stylesheets/articles.min.css' },
    ]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    // Default tasks.
    grunt.registerTask('default', ['cssmin']);
    };

    View full-size slide

  60. Stack ‘em up

    View full-size slide

  61. Images are the biggest part
    of a web page
    Stylesheets,
    HTML, etc
    Images 60%
    JavaScript
    source: httparchive.org

    View full-size slide

  62. 1. Images
    Compression

    View full-size slide

  63. 160 KB 110 KB
    Before After

    View full-size slide

  64. jpegmini
    mozjpeg
    kraken.io
    jpeg png gif svg

    View full-size slide

  65. jpegmini
    mozjpeg
    kraken.io
    optipng
    pngcrush
    zopflipng
    pngmini
    kraken.io
    jpeg png gif svg

    View full-size slide

  66. jpegmini
    mozjpeg
    kraken.io
    gifsicle
    kraken.io
    optipng
    pngcrush
    zopflipng
    pngmini
    kraken.io
    jpeg png gif svg

    View full-size slide

  67. jpegmini
    mozjpeg
    kraken.io
    gifsicle
    kraken.io
    SVGO
    kraken.io
    optipng
    pngcrush
    zopflipng
    pngmini
    kraken.io
    jpeg png gif svg

    View full-size slide

  68. jpeg png gif svg
    grunt-contrib-imagemin

    View full-size slide

  69. npm install grunt-contrib-imagemin

    View full-size slide

  70. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    imagemin: {
    dist: {
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-imagemin');
    // Default tasks.
    grunt.registerTask('default', ['imagemin']);
    };

    View full-size slide

  71. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    imagemin: {
    dist: {
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-imagemin');
    // Default tasks.
    grunt.registerTask('default', ['imagemin']);
    };

    View full-size slide

  72. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    imagemin: {
    dist: {
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-imagemin');
    // Default tasks.
    grunt.registerTask('default', ['imagemin']);
    };

    View full-size slide

  73. Gruntfile.js
    module.exports = function (grunt) {
    grunt.initConfig({
    imagemin: {
    dist: {
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-imagemin');
    // Default tasks.
    grunt.registerTask('default', ['imagemin']);
    };

    View full-size slide

  74. imagemin plugins

    View full-size slide

  75. grunt-contrib-imagemin
    1. npm install

    View full-size slide

  76. grunt-contrib-imagemin
    1. npm install
    2. var plugin = require('');

    View full-size slide

  77. 1. npm install
    2. var plugin = require('');
    3. options: {use: [plugin( {config} )]}
    grunt-contrib-imagemin

    View full-size slide

  78. Squeezing the
    JPEG

    View full-size slide

  79. Before: 1.02 MB

    View full-size slide

  80. Before: 1.02 MB
    Default: 905 KB

    View full-size slide

  81. Before: 1.02 MB
    Default: 905 KB
    JPEG ReCompress: 616 KB

    View full-size slide

  82. Before: 1.02 MB
    Default: 905 KB
    JPEG ReCompress: 616 KB
    MozJPEG: 217 KB

    View full-size slide

  83. 1. npm install imagemin-mozjpeg
    grunt-contrib-imagemin

    View full-size slide

  84. 1. npm install imagemin-mozjpeg
    2. var moz= require('imagemin-mozjpeg');
    grunt-contrib-imagemin

    View full-size slide

  85. 1. npm install imagemin-mozjpeg
    2. var moz= require('imagemin-mozjpeg');
    3. options: {use: [moz( {quality:80} )]}
    grunt-contrib-imagemin

    View full-size slide

  86. var moz = require('imagemin-mozjpeg');
    grunt.initConfig({
    imagemin: {
    dist: {
    options: {
    use: [moz( {quality:80, quantTable: 3} )]
    },
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    Gruntfile.js

    View full-size slide

  87. 109 KB 34.9 KB
    Before After

    View full-size slide

  88. Bashing
    the
    PNG

    View full-size slide

  89. Before: 5.23 MB

    View full-size slide

  90. Before: 5.23 MB
    Default: 906 KB

    View full-size slide

  91. Before: 5.23 MB
    Default: 906 KB
    Default + Level 7: 905 KB

    View full-size slide

  92. Before: 5.23 MB
    Default: 906 KB
    Default + Level 7: 905 KB
    Zopfli: 851 KB

    View full-size slide

  93. var zopfli = require('imagemin-zopfli');
    grunt.initConfig({
    imagemin: {
    dist: {
    options: {
    use: [zopfli( {more: true} )]
    },
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    Gruntfile.js

    View full-size slide

  94. 3.5 MB 68 KB
    Before After

    View full-size slide

  95. HOWEVER
    Default: 15s

    View full-size slide

  96. HOWEVER
    Default: 15s
    Default + Level 7: 1m23s

    View full-size slide

  97. HOWEVER
    Default: 15s
    Default + Level 7: 1m23s
    Zopfli: 8 minutes!!

    View full-size slide

  98. grunt.initConfig({
    imagemin: {
    dist: {
    options: {
    optimizationLevel: 3, // default values, so is not even necessary
    },
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    Gruntfile.js

    View full-size slide

  99. Slashing the SVG

    View full-size slide

  100. grunt.initConfig({
    imagemin: {
    dist: {
    options: {
    svgoPlugins: [{ removeViewBox: true }]
    },
    files: [{
    expand: true,
    cwd: 'images/',
    src: ['*.{png,jpg,gif,svg}'],
    dest: 'images/dist/'
    }]
    }
    }
    })
    Gruntfile.js

    View full-size slide

  101. 14KB 4KB
    Before After

    View full-size slide

  102. We kinda
    cheated!

    View full-size slide

  103. 6.25 MB
    JPEG PNG SVG

    View full-size slide

  104. 6.25 MB
    1.09 MB

    View full-size slide

  105. Alternatives

    View full-size slide

  106. bit.ly/azure-jobs

    View full-size slide

  107. bit.ly/azure-jobs bit.ly/amazon-smush

    View full-size slide

  108. 1. Images
    Compression

    View full-size slide

  109. 1. Images
    Compression
    HTTP2
    Approved

    View full-size slide

  110. Gruntfile
    ● grunt-contrib-imagemin
    ○ imagemin-mozjpeg
    ○ imagemin-zopfli

    View full-size slide

  111. 1. Images
    Compression
    Format

    View full-size slide

  112. Baseline Progressive

    View full-size slide

  113. Converting
    the JPEG

    View full-size slide

  114. Before: 1.02 MB
    MozJPEG: 217 KB

    View full-size slide

  115. Before: 1.02 MB
    MozJPEG: 217 KB
    WebP: 196 KB

    View full-size slide

  116. Converting
    the
    PNG

    View full-size slide

  117. Before: 5.23 MB
    Zopfli: 851 KB

    View full-size slide

  118. Before: 5.23 MB
    Zopfli: 851 KB
    WebP: 139 KB

    View full-size slide

  119. 6.25 MB
    JPEG PNG SVG

    View full-size slide

  120. 6.25 MB
    335 KB

    View full-size slide

  121. npm install grunt-webp

    View full-size slide

  122. webp:{
    png: {
    files:[{
    expand: true,
    cwd: "images/",
    src: "*.png",
    dest: "images/dist/"
    }],
    options: {
    binpath: "tools/cwebp.exe",
    preset: 'picture',
    verbose: true,
    quality: 80,
    alphaQuality: 80,
    compressionMethod: 6,
    ……..
    }
    }
    Gruntfile.js

    View full-size slide

  123. 10KB
    PNG WebP
    3.5 MB

    View full-size slide

  124. 1. Images
    Compression
    Format
    HTTP2
    Approved

    View full-size slide

  125. 1. Images
    Compression
    Format
    Responsive Images

    View full-size slide

  126. npm install grunt-responsive-images

    View full-size slide

  127. brew install ImageMagick

    View full-size slide

  128. Gruntfile.js
    responsive_images: {
    images: {
    options: {
    engine: 'im',
    sizes: [
    {
    name: 'medium',
    width: 300
    },{
    name: 'large',
    width: 500,
    }]
    },
    files: { src: '../before/images/tie-fighter-large.jpg' , dest: 'images/tie-fighter.jpg'}
    }
    }

    View full-size slide

  129. Gruntfile.js
    responsive_images: {
    images: {
    options: {
    engine: 'im',
    sizes: [
    {
    name: 'medium',
    width: 300
    },{
    name: 'large',
    width: 500,
    }]
    },
    files: { 'images/tie-fighter.jpg': '../before/images/tie-fighter-large.jpg' }
    }
    }

    View full-size slide

  130. Gruntfile.js
    responsive_images: {
    images: {
    options: {
    engine: 'im',
    sizes: [
    {
    name: 'medium',
    width: 300
    },{
    name: 'large',
    width: 500,
    }]
    },
    files: { 'images/tie-fighter.jpg': '../before/images/tie-fighter-large.jpg' }
    }
    }

    View full-size slide

  131. 112 KB 70 KB

    View full-size slide

  132. 112 KB 70 KB 26 KB

    View full-size slide

  133. 1. Images
    Compression
    Format
    Responsive Images
    HTTP2
    Approved

    View full-size slide

  134. 1. Images
    Compression
    HTTP2
    Approved

    View full-size slide

  135. 1. Images
    Compression
    Format
    HTTP2
    Approved

    View full-size slide

  136. 1. Images
    Compression
    Format
    Responsive Images
    HTTP2
    Approved

    View full-size slide

  137. Gruntfile
    ● grunt-contrib-imagemin
    ○ imagemin-mozjpeg
    ○ imagemin-zopfli
    ● grunt-webp
    ● grunt-responsive-images

    View full-size slide

  138. Stop!
    Psst!
    Fancy some more info on image optimisation?
    Check out imageoptimization.info

    View full-size slide

  139. /* This is a comment */
    h1 {
    font-size: 30px;
    line-height: 36px;
    }
    h1 small {
    font-size: 18px; /* Another comment */
    }
    CSS

    View full-size slide

  140. h1{font-size:30px;line-height:36px}h1 small{font-size:18px}

    View full-size slide

  141. npm install grunt-contrib-cssmin

    View full-size slide

  142. cssmin: {
    dist: {
    files: [{
    src: ['css/material-design.css', 'css/site.css'],
    dest: 'css/result.min.css'
    }]
    }
    Gruntfile.js

    View full-size slide

  143. Clean your CSS
    div { color:red; } a { color:red ;}

    View full-size slide

  144. Clean your CSS
    div,a{color:red}

    View full-size slide

  145. Clean your CSS
    .foo { background: url('images/test.jpg'); width: 100px; }
    .bar { display: block; }
    .baz { background: url('images/test.jpg'); width: 110px; }

    View full-size slide

  146. Clean your CSS
    .baz,.foo{background:url('images/test.jpg')}
    .foo{width:100px}
    .bar{display:block}
    .baz{width:110px}

    View full-size slide

  147. Browsers don’t care!

    View full-size slide

  148. Foundation CSS
    22 % with whitespace optimizations
    29% with all optimizations

    View full-size slide

  149. 1 HTTP
    Request

    View full-size slide

  150. HTTP2
    Approved

    View full-size slide

  151. cssmin: {
    dist: {
    files: [{
    src: ['css/material-design.css', 'css/site.css'],
    dest: 'css/result.min.css'
    }]
    }
    Gruntfile.js

    View full-size slide

  152. cssmin: {
    dist: {
    files: [{
    expand: true,
    cwd: 'release/css',
    src: ['*.css', '!*.min.css'],
    dest: 'release/css',
    ext: '.min.css'
    }]
    }
    }
    Gruntfile.js

    View full-size slide

  153. Minify
    2.CSS
    HTTP2
    Approved

    View full-size slide

  154. Alternatives

    View full-size slide

  155. bit.ly/azure-jobs

    View full-size slide

  156. CSS
    Minify
    Unused

    View full-size slide

  157. Before
    107 KB
    After
    30 KB

    View full-size slide

  158. 91%
    Unused CSS

    View full-size slide

  159. 91%
    Unused CSS

    View full-size slide

  160. Deliver only the
    goods
    that will be used !

    View full-size slide

  161. Chrome
    Developer
    Tools

    View full-size slide

  162. Chrome
    Developer
    Tools

    View full-size slide

  163. npm install grunt-uncss

    View full-size slide

  164. Gruntfile.js
    uncss: {
    dist: {
    files: {
    'css/result.css': ['index.html']
    }
    }
    }

    View full-size slide

  165. uncss: {
    dist: {
    options: {
    ignore: ['#header', 'mdl-layout__header']
    },
    files: {
    'css/result.css': ['index.html']
    }
    }
    }
    Gruntfile.js

    View full-size slide

  166. uncss: {
    dist: {
    options: {
    ignore: ['#header', 'mdl-layout__header']
    },
    files: {
    'css/result.css': ['index.html']
    }
    }
    }
    Gruntfile.js

    View full-size slide

  167. CSS
    Unused
    HTTP2
    Approved

    View full-size slide

  168. CSS
    Minify
    Unused
    Critical

    View full-size slide

  169. HTML CSS JS
    Blocking Blocking

    View full-size slide

  170. “More Weight
    Doesn't Mean More
    Wait”
    Scott Jehl

    View full-size slide

  171. Finding the Critical Path

    View full-size slide



  172. /* inlined critical CSS */
    loadCSS('deferred.css');


    ...body goes here

    View full-size slide



  173. /* inlined critical CSS */
    loadCSS('deferred.css');


    ...body goes here

    View full-size slide

  174. 1 Roundtrip
    14 KB

    View full-size slide

  175. npm install grunt-critical

    View full-size slide

  176. critical: {
    dist: {
    options: {
    base: './',
    minify: true,
    dimensions: [
    { width: 1300, height: 900 },
    { width: 500, height: 900 }]
    },
    files: { src: 'index.html', dest: ['index.html'] }
    }
    }
    Gruntfile.js

    View full-size slide

  177. HTTP2
    Approved

    View full-size slide

  178. Gruntfile
    ● grunt-contrib-imagemin
    ○ imagemin-mozjpeg
    ○ imagemin-zopfli
    ● grunt-webp
    ● grunt-responsive-images
    ● grunt-contrib-cssmin
    ● grunt-critical

    View full-size slide

  179. CSS
    Summary
    Minify

    View full-size slide

  180. CSS
    Summary
    Minify
    Clean

    View full-size slide

  181. CSS
    Summary
    Minify
    Clean
    Unused

    View full-size slide

  182. CSS
    Summary
    Minify
    Clean
    Unused
    Critical

    View full-size slide

  183. JavaScript
    Minify

    View full-size slide

  184. /**
    * Upgrades a specific element rather than all in the DOM.
    * @param {HTMLElement} element The element we wish to upgrade.
    * @param {string} jsClass The name of the class we want to upgrade
    * the element to.
    */
    function upgradeElementInternal(element, jsClass) {
    // Only upgrade elements that have not already been upgraded.
    var dataUpgraded = element.getAttribute('data-upgraded');
    if (dataUpgraded === null || dataUpgraded.indexOf(jsClass) === -1) {
    // Upgrade element.
    if (dataUpgraded === null) {
    dataUpgraded = '';
    }
    element.setAttribute('data-upgraded', dataUpgraded + ',' + jsClass);
    ….
    JS

    View full-size slide

  185. function upgradeElementInternal(a,b){var c=a.getAttribute("data-
    upgraded");if(null===c||-1===c.indexOf(b)){null===c&&(c=""),a.
    setAttribute("data-upgraded",c+","+b);var d=findRegisteredClass_(b);if(!
    d)throw"Unable to find a registered component for the given class.";var
    e=new d.classConstructor(a);e[componentConfigProperty_]=d,
    createdComponents_.push(e),d.callbacks.forEach(function(b){b(a)}),d.
    widget&&(a[b]=e);var f=document.createEvent("Events");f.initEvent
    ("mdl-componentupgraded",!0,!0),a.dispatchEvent(f)}}

    View full-size slide

  186. npm install grunt-contrib-uglify

    View full-size slide

  187. uglify: {
    target: {
    files: [{
    expand: true,
    cwd: 'src',
    src: ['*.js'],
    dest: 'dest',
    ext: '.min.js'
    }]
    }
    }
    Gruntfile.js

    View full-size slide

  188. Alternatives

    View full-size slide

  189. bit.ly/azure-jobs

    View full-size slide

  190. JavaScript
    Minify
    HTTP2
    Approved

    View full-size slide







  191. Bulky Bricks




    Home
    HTML

    View full-size slide

  192. \n

    \n
    \n
    \n
    \n
    Bulky Bricks\n
    \n
    \n
    \n
    \n
    Home\n
    HTML

    View full-size slide


  193. row> Bulky Bricks layout-spacer> Home
    Products class=mdl-navigation__link href=about.html>About Usclass=mdl-navigation__link href=contact.html>Contact Us
    layout-title>Bulky Bricks

    View full-size slide

  194. npm install grunt-contrib-htmlmin

    View full-size slide

  195. htmlmin: {
    target: {
    options: {
    removeComments: true,
    collapseWhitespace: true,
    collapseBooleanAttributes: true,
    removeAttributeQuotes: true
    },
    files: { dest: 'index.min.html', src: 'index.html' }
    }
    }
    Gruntfile.js

    View full-size slide

  196. HTML
    Minify
    HTTP2
    Approved

    View full-size slide

  197. Gruntfile
    ● grunt-contrib-imagemin
    ○ imagemin-mozjpeg
    ○ imagemin-zopfli
    ● grunt-webp
    ● grunt-responsive-images
    ● grunt-contrib-cssmin
    ● grunt-critical
    ● grunt-contrib-uglify
    ● grunt-contrib-htmlmin

    View full-size slide

  198. mod_pagespeed

    View full-size slide

  199. bit.ly/akamai-bulky

    View full-size slide

  200. bit.ly/akamai-ion

    View full-size slide

  201. developers.google.com/web/tools/starter-kit

    View full-size slide

  202. ampproject.org
    Accelerated
    Mobile
    Pages

    View full-size slide

  203. Amsterdam
    Home page - 2 seconds & cost $0.01

    View full-size slide

  204. Amsterdam
    Home page - 2 seconds & cost $0.01
    Product page - 1 second & cost $0.01

    View full-size slide

  205. npm install grunt-pagespeed

    View full-size slide

  206. pagespeed: {
    options: {
    nokey: true
    },
    prod: {
    options: {
    url: "http://rposbo.github.io/bulky-bricks-inc/after/index.html",
    locale: "en_GB",
    strategy: "desktop",
    threshold: 95
    }
    }
    }
    Gruntfile.js

    View full-size slide

  207. language: node_js
    node_js:
    - "0.12"
    before_install: npm install -g grunt-cli
    install: npm install
    script: grunt test
    travis.yml

    View full-size slide

  208. {
    "dependencies": {
    "grunt": "*",
    "grunt-pagespeed": "*"
    }
    }
    package.json

    View full-size slide

  209. Check
    every
    push

    View full-size slide

  210. Alternatives

    View full-size slide

  211. Summary
    1. Images

    View full-size slide

  212. Summary
    1. Images
    2. CSS

    View full-size slide

  213. Summary
    1. Images
    2. CSS
    3. JavaScript

    View full-size slide

  214. Summary
    1. Images
    2. CSS
    3. JavaScript
    4. HTML

    View full-size slide

  215. Summary
    1. Images
    2. CSS
    3. JavaScript
    4. HTML
    5. Testing

    View full-size slide

  216. Dean Hume @deanohume
    Robin Osborne @rposbo
    tinyurl.com/bulkybricks
    Thank you!

    View full-size slide