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 full-size slide

  2. lazy
    defer until the user needs it

    View full-size slide

  3. loading
    fetch + render

    View full-size slide

  4. highest
    high
    medium
    low
    low
    high
    highest
    medium
    low

    View full-size slide

  5. highest
    high
    medium
    low
    low
    high
    highest
    medium
    low

    View full-size slide

  6. low
    highest
    high
    medium
    low
    low
    high
    highest
    medium

    View full-size slide

  7. highest
    high
    medium
    low
    low
    high
    highest
    medium
    medium
    low

    View full-size slide

  8. > 40% of data fetched = images

    View full-size slide

  9. scroll event listeners

    View full-size slide


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

    View full-size slide

  11. 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 full-size slide

  12. intersection observer

    View full-size slide

  13. 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 full-size slide

  14. bit.ly/inter-obs

    View full-size slide

  15. native browser feature?

    View full-size slide


  16. lazyload=“on”

    View full-size slide

  17. 1 KB of Image
    1 KB of JavaScript

    View full-size slide

  18. split, split, split ✂

    View full-size slide

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

    View full-size slide

  20. what should I do?

    View full-size slide

  21. audit

    fix

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  24. Use placeholders/
    load early
    pinterest
    pinterest.com

    View full-size slide

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

    View full-size slide

  26. Use placeholders/
    load early
    Primitive
    primitive.lol

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. 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 full-size slide

  30. 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 full-size slide

  31. 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 full-size slide

  32. 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 full-size slide

  33. 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 full-size slide

  34. 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 full-size slide

  35. 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 full-size slide

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

    View full-size slide

  37. audit

    fix

    observe

    View full-size slide

  38. webpack-bundle-analyzer

    View full-size slide

  39. progressivetooling.com

    View full-size slide

  40. 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 full-size slide