Performance optimisations of dApps

Performance optimisations of dApps

428a9c6e5b151e618d4db288105bc5f3?s=128

Aleš Roubíček

February 25, 2020
Tweet

Transcript

  1. 2.
  2. 3.
  3. 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.”
  4. 6.
  5. 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
  6. 8.

    Application state • React, Redux, Web3.js, Drizzle, Pixi.js • function

    view(data) {} • Single Atom Application State pattern • Immutable data (via persistent data structures)
  7. 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
  8. 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)
  9. 14.
  10. 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
  11. 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
  12. 17.
  13. 18.
  14. 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; }
  15. 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, }), ); }
  16. 21.
  17. 23.
  18. 26.

    Preloading of assets <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link

    rel="preload" as="font" crossorigin href="https://fonts.gstatic.com/s/vt323/v10/pxiKyp0ihIEF2isfFJXUdVNF.woff2">
  19. 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); };