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

The Art of Lazy Loading

The Art of Lazy Loading

The magic of lazy loading images and splitting bundles ✨

Houssein Djirdeh

October 03, 2018
Tweet

More Decks by Houssein Djirdeh

Other Decks in Technology

Transcript

  1. the art of lazy loading
    lazy loading
    @hdjirdeh

    View Slide

  2. lazy
    defer until the user needs it

    View Slide

  3. loading
    fetch + render

    View Slide

  4. what?

    View Slide

  5. images!

    View Slide

  6. View Slide

  7. highest
    high
    medium
    low
    low
    high
    highest
    medium
    low

    View Slide

  8. highest
    high
    medium
    low
    low
    high
    highest
    medium
    low

    View Slide

  9. low
    highest
    high
    medium
    low
    low
    high
    highest
    medium

    View Slide

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

    View Slide

  11. > 40% of data fetched = images

    View Slide

  12. scroll event listeners

    View Slide


  13. class="lazy" data-src="kittens.png"

    View Slide

  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);
    };

    View Slide

  15. intersection observer

    View Slide

  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);

    View Slide

  17. bit.ly/inter-obs

    View Slide

  18. native browser feature?

    View Slide


  19. lazyload=“on”

    View Slide

  20. View Slide

  21. what else?

    View Slide

  22. code!

    View Slide

  23. View Slide

  24. 1 KB of Image
    1 KB of JavaScript

    View Slide

  25. split, split, split ✂

    View Slide

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

    View Slide

  27. what should I do?

    View Slide

  28. audit

    View Slide

  29. View Slide

  30. View Slide

  31. View Slide

  32. audit

    fix

    View Slide

  33. View Slide

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

    View Slide

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

    View Slide

  36. Use placeholders/
    load early
    pinterest
    pinterest.com

    View Slide

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

    View Slide

  38. Use placeholders/
    load early
    Primitive
    primitive.lol

    View Slide

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

    View Slide

  40. View Slide

  41. export const routes: Routes = [
    {
    path: 'main',
    component: 'MainComponent',
    },
    {
    path: 'details',
    loadChildren: 'details/details.module#DetailsModule'
    }
    ];
    angular router

    View Slide

  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

    View Slide

  43. import { Router } from 'preact-router';
    import Home from '"../routes/home';
    import Details from 'async!./details';
    export const App = () "=> (



    "
    );
    import { Router } from 'preact-router';
    import Home from '"../routes/home';
    import Details from 'async!./details';
    export const App = () "=> (



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



    "
    );

    View Slide

  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

    View Slide

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

    View Slide

  46. import loadable from 'loadable-components';
    const DetailsComponent =
    loadable(() "=> import('./details.component'), {
    LoadingComponent: () "=> Loading""..."
    });
    import loadable from 'loadable-components';
    const DetailsComponent =
    loadable(() "=> import('./details.component'), {
    LoadingComponent: () "=> Loading""..."
    });
    import loadable from 'loadable-components';
    const DetailsComponent =
    loadable(() "=> import('./details.component'), {
    LoadingComponent: () "=> Loading""..."
    });
    smooth-code / loadable-components

    View Slide

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

    View Slide

  48. View Slide

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

    View Slide

  50. suspense

    View Slide

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

    View Slide

  52. View Slide

  53. audit

    fix

    observe

    View Slide

  54. webpack-bundle-analyzer

    View Slide

  55. size-plugin

    View Slide

  56. progressivetooling.com

    View Slide

  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

    View Slide

  58. /
    Dx
    Ux

    View Slide

  59. @hdjirdeh

    View Slide