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 Slide

  2. Robin Osborne
    @rposbo

    View Slide

  3. Dean Hume
    @deanohume

    View Slide

  4. View Slide

  5. ASP.Net is Open Source!

    View Slide

  6. Does
    performance
    really matter?

    View Slide

  7. 2.2 SECONDS

    View Slide

  8. 2.2 SECONDS
    Increased downloads by 15.4%

    View Slide

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

    View Slide

  10. People != Patience

    View Slide

  11. whatdoesmysitecost.com

    View Slide

  12. View Slide

  13. View Slide

  14. It all started with...

    View 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 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 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 Slide

  18. 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 Slide

  19. 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 Slide

  20. 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 Slide

  21. 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 Slide

  22. Web
    Performance
    ain’t easy!

    View Slide

  23. View Slide

  24. Manual Process

    View Slide

  25. View Slide

  26. View Slide

  27. HTML

    View Slide

  28. HTML
    CSS

    View Slide

  29. HTML
    CSS
    Images

    View Slide

  30. HTML
    CSS
    JS
    Images

    View Slide

  31. Steps
    1. Images

    View Slide

  32. Steps
    1. Images
    2. CSS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  36. HTTP2

    View Slide

  37. HTTP2
    HTTP2
    Approved

    View Slide

  38. View Slide

  39. TAKE A BREAK

    View Slide

  40. tinyurl.com/bulkybricks

    View Slide

  41. View Slide

  42. index

    View Slide

  43. index products

    View Slide

  44. index products
    product

    View Slide

  45. index products
    product
    contact

    View Slide

  46. index products
    product
    contact about

    View Slide

  47. View Slide

  48. View Slide

  49. Material Design Lite

    View Slide

  50. getmdl.io/started

    View Slide

  51. whatdoesmysitecost.com

    View Slide

  52. Amsterdam

    View Slide

  53. Amsterdam
    Home page

    View Slide

  54. Amsterdam
    Home page - 21 seconds

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  59. webpagetest.org

    View Slide

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

    View Slide

  61. 53

    View Slide

  62. Automate Measuring

    View Slide

  63. Automate all
    the things

    View Slide

  64. Begin the journey
    tinyurl.com/bulkybricks

    View Slide

  65. optimise
    before
    deploying

    View Slide

  66. Grunt
    Gulp

    View Slide

  67. Grunt
    Gulp

    View Slide

  68. Gulp Grunt

    View Slide

  69. 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 Slide

  70. mod_pagespeed
    optimise
    after
    deploying

    View Slide

  71. Gulp Grunt

    View Slide

  72. GruntFile

    View Slide

  73. 1. NodeJS
    GruntFile

    View Slide

  74. 1. NodeJS
    GruntFile
    2. Grunt

    View Slide

  75. 1. NodeJS
    GruntFile
    2. Grunt 3. GruntFile

    View Slide

  76. nodejs.org

    View Slide

  77. NPM

    View Slide

  78. npm install grunt

    View Slide

  79. npm install -g grunt-cli

    View Slide

  80. 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 Slide

  81. 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 Slide

  82. 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 Slide

  83. 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 Slide

  84. Stack ‘em up

    View Slide

  85. View Slide

  86. 1. Images

    View Slide

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

    View Slide

  88. 1. Images
    Compression

    View Slide

  89. 160 KB 110 KB
    Before After

    View Slide

  90. 50KB

    View Slide

  91. Manual

    View Slide

  92. jpegmini
    mozjpeg
    kraken.io
    jpeg png gif svg

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  96. Automated

    View Slide

  97. jpeg png gif svg
    grunt-contrib-imagemin

    View Slide

  98. npm install grunt-contrib-imagemin

    View Slide

  99. 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 Slide

  100. 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 Slide

  101. 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 Slide

  102. 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 Slide

  103. imagemin plugins

    View Slide

  104. grunt-contrib-imagemin
    1. npm install

    View Slide

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

    View Slide

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

    View Slide

  107. Squeezing the
    JPEG

    View Slide

  108. Before: 1.02 MB

    View Slide

  109. Before: 1.02 MB
    Default: 905 KB

    View Slide

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

    View Slide

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

    View Slide

  112. ~80%

    View Slide

  113. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  117. 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 Slide

  118. 109 KB 34.9 KB
    Before After

    View Slide

  119. Bashing
    the
    PNG

    View Slide

  120. Before: 5.23 MB

    View Slide

  121. Before: 5.23 MB
    Default: 906 KB

    View Slide

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

    View Slide

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

    View Slide

  124. ~85%

    View Slide

  125. 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 Slide

  126. 3.5 MB 68 KB
    Before After

    View Slide

  127. HOWEVER
    Default: 15s

    View Slide

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

    View Slide

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

    View Slide

  130. 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 Slide

  131. Slashing the SVG

    View Slide

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

    View Slide

  133. 14KB 4KB
    Before After

    View Slide

  134. 70%

    View Slide

  135. We kinda
    cheated!

    View Slide

  136. 6.25 MB
    JPEG PNG SVG

    View Slide

  137. 6.25 MB

    View Slide

  138. 6.25 MB
    1.09 MB

    View Slide

  139. 5.16 MB

    View Slide

  140. ~83%

    View Slide

  141. Alternatives

    View Slide

  142. bit.ly/azure-jobs

    View Slide

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

    View Slide

  144. ?

    View Slide

  145. 86

    View Slide

  146. 1. Images
    Compression

    View Slide

  147. 1. Images
    Compression
    HTTP2
    Approved

    View Slide

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

    View Slide

  149. 1. Images
    Compression
    Format

    View Slide

  150. Progressive

    View Slide

  151. Baseline Progressive

    View Slide

  152. WebP

    View Slide

  153. Converting
    the JPEG

    View Slide

  154. Before: 1.02 MB
    MozJPEG: 217 KB

    View Slide

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

    View Slide

  156. Converting
    the
    PNG

    View Slide

  157. Before: 5.23 MB
    Zopfli: 851 KB

    View Slide

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

    View Slide

  159. 6.25 MB
    JPEG PNG SVG

    View Slide

  160. 6.25 MB

    View Slide

  161. 6.25 MB
    335 KB

    View Slide

  162. 5.9 MB

    View Slide

  163. ~94%

    View Slide

  164. npm install grunt-webp

    View Slide

  165. 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 Slide

  166. 10KB
    PNG WebP
    3.5 MB

    View Slide

  167. 1. Images
    Compression
    Format
    HTTP2
    Approved

    View Slide

  168. 1. Images
    Compression
    Format
    Responsive Images

    View Slide

  169. View Slide

  170. 72%

    View Slide

  171. View Slide







  172. View Slide







  173. View Slide







  174. View Slide

  175. npm install grunt-responsive-images

    View Slide

  176. brew install ImageMagick

    View Slide

  177. 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 Slide

  178. 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 Slide

  179. 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 Slide

  180. View Slide

  181. 112 KB

    View Slide

  182. 112 KB 70 KB

    View Slide

  183. 112 KB 70 KB 26 KB

    View Slide

  184. 77%

    View Slide

  185. 1. Images
    Compression
    Format
    Responsive Images
    HTTP2
    Approved

    View Slide

  186. 1. Images
    Compression
    HTTP2
    Approved

    View Slide

  187. 1. Images
    Compression
    Format
    HTTP2
    Approved

    View Slide

  188. 1. Images
    Compression
    Format
    Responsive Images
    HTTP2
    Approved

    View Slide

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

    View Slide

  190. Stop!

    View Slide

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

    View Slide

  192. 2.CSS

    View Slide

  193. Minify
    2.CSS

    View Slide

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

    View Slide

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

    View Slide

  196. npm install grunt-contrib-cssmin

    View Slide

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

    View Slide

  198. But wait...

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  203. Browsers don’t care!

    View Slide

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

    View Slide

  205. 155 KB

    View Slide

  206. 118 KB

    View Slide

  207. 25%

    View Slide

  208. 1 HTTP
    Request

    View Slide

  209. HTTP2
    Approved

    View Slide

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

    View Slide

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

    View Slide

  212. 118 KB

    View Slide

  213. Minify
    2.CSS
    HTTP2
    Approved

    View Slide

  214. Alternatives

    View Slide

  215. bit.ly/azure-jobs

    View Slide

  216. CSS
    Minify
    Unused

    View Slide

  217. Before
    107 KB
    After
    30 KB

    View Slide

  218. 91%
    Unused CSS

    View Slide

  219. 91%
    Unused CSS

    View Slide

  220. Deliver only the
    goods
    that will be used !

    View Slide

  221. Chrome
    Developer
    Tools

    View Slide

  222. Chrome
    Developer
    Tools

    View Slide

  223. npm install grunt-uncss

    View Slide

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

    View Slide

  225. 118 KB

    View Slide

  226. 24 KB

    View Slide

  227. But wait...

    View Slide

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

    View Slide

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

    View Slide

  230. CSS
    Unused
    HTTP2
    Approved

    View Slide

  231. CSS
    Minify
    Unused
    Critical

    View Slide

  232. HTML

    View Slide

  233. HTML CSS

    View Slide

  234. HTML CSS JS

    View Slide

  235. HTML CSS JS
    Blocking Blocking

    View Slide

  236. View Slide

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

    View Slide

  238. Finding the Critical Path

    View Slide

  239. View Slide

  240. 14 KB

    View Slide

  241. View Slide



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


    ...body goes here

    View Slide



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


    ...body goes here

    View Slide

  244. 1 Roundtrip
    14 KB

    View Slide

  245. npm install grunt-critical

    View Slide

  246. 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 Slide

  247. HTTP2
    Approved

    View Slide

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

    View Slide

  249. CSS
    Summary
    Minify

    View Slide

  250. CSS
    Summary
    Minify
    Clean

    View Slide

  251. CSS
    Summary
    Minify
    Clean
    Unused

    View Slide

  252. CSS
    Summary
    Minify
    Clean
    Unused
    Critical

    View Slide

  253. Stop!

    View Slide

  254. ?

    View Slide

  255. 94

    View Slide

  256. JavaScript

    View Slide

  257. JavaScript
    Minify

    View Slide

  258. /**
    * 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 Slide

  259. 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 Slide

  260. npm install grunt-contrib-uglify

    View Slide

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

    View Slide

  262. 140 KB

    View Slide

  263. 60 KB

    View Slide

  264. 40%

    View Slide

  265. Alternatives

    View Slide

  266. bit.ly/azure-jobs

    View Slide

  267. JavaScript
    Minify
    HTTP2
    Approved

    View Slide

  268. HTML

    View Slide

  269. HTML
    Minify

    View Slide







  270. Bulky Bricks




    Home
    HTML

    View Slide

  271. \n

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

    View Slide


  272. 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 Slide

  273. npm install grunt-contrib-htmlmin

    View Slide

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

    View Slide

  275. 28.2 KB

    View Slide

  276. 19.3 KB

    View Slide

  277. 30%

    View Slide

  278. HTML
    Minify
    HTTP2
    Approved

    View Slide

  279. 95

    View Slide

  280. 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 Slide

  281. All In One

    View Slide

  282. mod_pagespeed

    View Slide

  283. ION

    View Slide

  284. bit.ly/akamai-bulky

    View Slide

  285. bit.ly/akamai-ion

    View Slide

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

    View Slide

  287. ampproject.org
    Accelerated
    Mobile
    Pages

    View Slide

  288. Amsterdam

    View Slide

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

    View Slide

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

    View Slide

  291. Testing

    View Slide

  292. View Slide

  293. Regression

    View Slide

  294. Automated

    View Slide

  295. npm install grunt-pagespeed

    View Slide

  296. 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 Slide

  297. Fail
    a
    Build

    View Slide

  298. View Slide

  299. View Slide

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

    View Slide

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

    View Slide

  302. Check
    every
    push

    View Slide

  303. View Slide

  304. Alternatives

    View Slide

  305. View Slide

  306. Summary

    View Slide

  307. Summary
    1. Images

    View Slide

  308. Summary
    1. Images
    2. CSS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide