$30 off During Our Annual Pro Sale. View Details »

Performance optimisations of dApps

Performance optimisations of dApps

Aleš Roubíček
PRO

February 25, 2020
Tweet

More Decks by Aleš Roubíček

Other Decks in Technology

Transcript

  1. Performance optimisations
    of dApps
    @alesroubicek
    @PragueJS

    View Slide

  2. View Slide

  3. View Slide

  4. Performance bottlenecks
    • Design issues
    • Delivery issues

    View Slide

  5. –Aleš Roubíček
    “The state for rendering of the game should be
    separated from the actual state of the contracts,
    this will allow more asynchronous state
    propagation to rendering pipeline and improved
    timing when actual data will be shown.”

    View Slide

  6. View Slide

  7. Design issues
    • Render blocking operation in main thread
    • Not following design patterns required by libraries
    • State managing components in view tree
    • Initialisation of stateful components on every route
    • Blockchain state & view state coupling
    • Generators of unnecessary boilerplate

    View Slide

  8. Application state
    • React, Redux, Web3.js, Drizzle, Pixi.js
    • function view(data) {}
    • Single Atom Application State pattern
    • Immutable data (via persistent data structures)

    View Slide

  9. Original React tree






    View Slide

  10. React tree without Drizzle











    View Slide

  11. Redux & Sagas
    • Move all communication with web3 from lifecycle
    methods to redux-saga (out of view tree)
    • Use Pure/Functional Components where possible
    • Move all Drizzle state & components from React
    tree into Redux Store
    • Reactions to Blockchain changes only via actions/
    sagas

    View Slide

  12. WebWorkers and Comlink
    • Move all non-render related code off the main
    thread
    • Comlink helps with more transparent
    communication between render thread and worker
    • Sagas should coordinate only communication with
    Workers via Comlink (async)

    View Slide

  13. Comlink
    https://github.com/GoogleChromeLabs/comlink

    View Slide

  14. View Slide

  15. Delivery issues
    • Too big code chunks
    • Bundling of naturally static assets
    • Bundling of unnecessary dependencies
    • Render blocking resources in HTML (fonts, scripts)
    • Absence of pre-rendering and preloading

    View Slide

  16. Size of the bundle
    • Webpack Bundle Analyzer
    https://github.com/webpack-contrib/webpack-bundle-analyzer
    • Rollup plugin Visualizer
    https://www.npmjs.com/package/rollup-plugin-visualizer

    View Slide

  17. View Slide

  18. View Slide

  19. /*
    Local
    */
    // import SomeToken from '../../../ontracts/build/contracts/SomeToken.json';
    // import OtherToken from '../../../contracts/build/contracts/OtherToken.json';
    // import FooToken from '../../../contracts/build/contracts/FooToken.json';
    // import BarToken from '../../../contracts/build/contracts/BarToken.json';
    /*
    Ropsten
    */
    import SomeToken from './contracts/SomeToken.json';
    import OtherToken from './contracts/OtherToken.json';
    import FooToken from './contracts/FooToken.json';
    import BarToken from './contracts/BarToken.json';
    const contracts = {
    SomeToken,
    OtherToken,
    FooToken,
    BarToken,
    };
    export function getContract() {
    return contracts;
    }

    View Slide

  20. function contractUrl(contract) {
    const network = process.env['NETWORK'];
    const version = process.env['CONTRACTS_VERSION'];
    const isDev = process.env['NODE_ENV'] ]^_ 'production';
    const prefix = isDev
    ? `/${network}/contracts/`
    : `https://prod.example.com/${network}/contracts/${version}/`;
    return [prefix, contract, '.json'].join('');
    }
    const fetchContract = c c> fetch(contractUrl(c)).then(r c> r.json());
    const contracts = ['SomeToken', 'OtherToken', 'FooToken', 'BarToken'];
    export function getContract() {
    return Promise.all(contracts.map(fetchContract)).then(
    ([SomeToken, OtherToken, FooToken, BarToken]) c> ({
    SomeToken,
    OtherToken,
    FooToken,
    BarToken,
    }),
    );
    }

    View Slide

  21. View Slide

  22. package.json
    {
    "resolutions": {
    "bn.js": "4.11.8",
    }
    }

    View Slide

  23. View Slide

  24. webpack.js
    {
    test: /\.(jpg|png|gif)$/,
    use: [
    { loader: "file-loader" }
    ]
    }

    View Slide

  25. Assets loading
    • On-page optimalisation
    • preloading
    • async/defer
    • CDN optimalisation
    • Caching headers

    View Slide

  26. Preloading of assets


    href="https://fonts.gstatic.com/s/vt323/v10/pxiKyp0ihIEF2isfFJXUdVNF.woff2">

    View Slide

  27. script async defer

    View Slide

  28. CDN cache boosting
    'use strict';
    exports.handler = (event, context, callback) c> {
    const response = event.Records[0].cf.response;
    const headers = response.headers;
    headers['Cache-Control'.toLowerCase()] = [{
    key: 'Cache-Control',
    value: "public, max-age=31536000, immutable"
    }];
    callback(null, response);
    };

    View Slide