The Art of Lazy Loading

The Art of Lazy Loading

The magic of lazy loading images and splitting bundles ✨

4e3a8581bae65a5a8d89dc5015aac185?s=128

Houssein Djirdeh

October 03, 2018
Tweet

Transcript

  1. the art of lazy loading lazy loading @hdjirdeh

  2. lazy defer until the user needs it

  3. loading fetch + render

  4. what?

  5. images!

  6. None
  7. highest high medium low low high highest medium low

  8. highest high medium low low high highest medium low

  9. low highest high medium low low high highest medium

  10. highest high medium low low high highest medium medium low

  11. > 40% of data fetched = images

  12. scroll event listeners

  13. <img class="lazy" data-src="kittens.png"> class="lazy" data-src="kittens.png"

  14. let image = document.querySelector("img.lazy"); const lazyLoad = () "=> {

    setTimeout(() "=> { if ( image.getBoundingClientRect().top "<= window.innerHeight "&& image.getBoundingClientRect().bottom ">= 0 ) { image.src = image.dataset.src; } }, 200); }; document.addEventListener("scroll", lazyLoad); let image = document.querySelector("img.lazy"); const lazyLoad = () "=> { setTimeout(() "=> { if ( image.getBoundingClientRect().top "<= window.innerHeight "&& image.getBoundingClientRect().bottom ">= 0 ) { image.src = image.dataset.src; } }, 200); } document.addEventListener("scroll", lazyLoad); };
  15. intersection observer

  16. let image = document.querySelector("img.lazy"); let lazyObserver = new IntersectionObserver(entry "=>

    { if (entry.isIntersecting) { const image = entry.target; image.src = lazyImage.dataset.src; lazyObserver.unobserve(image); } }); lazyObserver.observe(image); let image = document.querySelector("img.lazy"); let lazyObserver = new IntersectionObserver(entry "=> { if (entry.isIntersecting) { const image = entry.target; image.src = lazyImage.dataset.src; lazyObserver.unobserve(image); } }); lazyObserver.observe(image);
  17. bit.ly/inter-obs

  18. native browser feature?

  19. <img lazyload=“on”> lazyload=“on”

  20. None
  21. what else?

  22. code!

  23. None
  24. 1 KB of Image 1 KB of JavaScript ≠

  25. split, split, split ✂

  26. import('lodash.sortby') .then(module "=> module.default) .then(doSomethingCool) import('lodash.sortby') .then(module "=> module.default) .then(doSomethingCool)

    dynamic import
  27. what should I do?

  28. audit

  29. None
  30. None
  31. None
  32. audit fix ✂

  33. None
  34. Use a library lozad.js lazysizes yall.js

  35. Use IO + polyfill Use a library Use placeholders/ load

    early
  36. Use placeholders/ load early pinterest pinterest.com

  37. Use placeholders/ load early lqip-loader github.com/zouhir/lqip-loader

  38. Use placeholders/ load early Primitive primitive.lol

  39. Use placeholders/ load early sqip github.com/technopagan/sqip SQIP LQIP Image

  40. None
  41. export const routes: Routes = [ { path: 'main', component:

    'MainComponent', }, { path: 'details', loadChildren: 'details/details.module#DetailsModule' } ]; angular router
  42. const DetailsComponent = () "=> import(‘./details.vue'); export const router =

    new VueRouter({ routes: [ { path: '/details', component: DetailsComponent }, ] }) const DetailsComponent = () "=> import(‘./details.vue'); export const router = new VueRouter({ routes: [ { path: '/details', component: DetailsComponent }, ] }) const DetailsComponent = () "=> import(‘./details.vue'); export const router = new VueRouter({ routes: [ { path: '/details', component: DetailsComponent }, ] }) export const router = new VueRouter({ routes: [ { path: '/details', component: DetailsComponent }, ] }) vue router
  43. import { Router } from 'preact-router'; import Home from '"../routes/home';

    import Details from 'async!./details'; export const App = () "=> ( <Router> <Home path="/" "/> <Details path="/details/" "/> "</Router> ); import { Router } from 'preact-router'; import Home from '"../routes/home'; import Details from 'async!./details'; export const App = () "=> ( <Router> <Home path="/" "/> <Details path="/details/" "/> "</Router> ); preact cli import { Router } from 'preact-router'; import Home from '"../routes/home'; import Details from 'async!./details'; export const App = () "=> ( <Router> <Home path="/" "/> <Details path="/details/" "/> "</Router> );
  44. const loadPage = (page) "=> (dispatch) "=> { switch(page) {

    case 'view1': import('"../my-view1.js').then((module) "=> { "// ""... }); break; "//""... } dispatch(updatePage(page)); }; const loadPage = (page) "=> (dispatch) "=> { switch(page) { case 'view1': import('"../my-view1.js').then((module) "=> { "// ""... }); break; "//""... } dispatch(updatePage(page)); }; const loadPage = (page) "=> (dispatch) "=> { switch(page) { case 'view1': import('"../my-view1.js').then((module) "=> { "// ""... }); break; "//""... } dispatch(updatePage(page)); }; polymer pwa-starter-kit
  45. import Loadable from 'react-loadable'; const DetailsComponent = Loadable({ loader: ()

    "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }); import Loadable from 'react-loadable'; const DetailsComponent = Loadable({ loader: () "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }); import Loadable from 'react-loadable'; const DetailsComponent = Loadable({ loader: () "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }); jamiebuilds / react-loadable
  46. import loadable from 'loadable-components'; const DetailsComponent = loadable(() "=> import('./details.component'),

    { LoadingComponent: () "=> <div>Loading""..."</div> }); import loadable from 'loadable-components'; const DetailsComponent = loadable(() "=> import('./details.component'), { LoadingComponent: () "=> <div>Loading""..."</div> }); import loadable from 'loadable-components'; const DetailsComponent = loadable(() "=> import('./details.component'), { LoadingComponent: () "=> <div>Loading""..."</div> }); smooth-code / loadable-components
  47. import LoadableVisibility from ‘react-loadable-visibility/react-loadable' const DetailsComponent = LoadableVisibility({ loader: ()

    "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }) import LoadableVisibility from ‘react-loadable-visibility/react-loadable' const DetailsComponent = LoadableVisibility({ loader: () "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }) import LoadableVisibility from ‘react-loadable-visibility/react-loadable' const DetailsComponent = LoadableVisibility({ loader: () "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, }) stratiformltd / react-loadable-visibility
  48. None
  49. const DetailsComponent = Loadable({ loader: () "=> import('./details.component'), loading: ()

    "=> <div>Loading""..."</div>, delay: 300, }); jamiebuilds / react-loadable const DetailsComponent = Loadable({ loader: () "=> import('./details.component'), loading: () "=> <div>Loading""..."</div>, delay: 300, });
  50. suspense

  51. bit.ly/lazy-metro metro (react native)

  52. None
  53. audit fix ✂ observe

  54. webpack-bundle-analyzer

  55. size-plugin

  56. progressivetooling.com

  57. responsive images with srcset preload critical chunks convert gifs to

    .mp4 pre-cache assets using a service worker compress assets remove unused packages module / nomodule
  58. / Dx Ux

  59. @hdjirdeh