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

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

  2. None
  3. None
  4. Performance bottlenecks • Design issues • Delivery issues

  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.”
  6. None
  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
  8. Application state • React, Redux, Web3.js, Drizzle, Pixi.js • function

    view(data) {} • Single Atom Application State pattern • Immutable data (via persistent data structures)
  9. Original React tree <CustomContainer> <ConnectedRouter> <DrizzleContainer> <Switch> <Route> <drizzleConnect(…)>

  10. React tree without Drizzle <CustomContainer> <ConnectedRouter> <DrizzleContainer> <Switch> <Route> <drizzleConnect(…)>

    <ReduxContainer> <ConnectedRouter> <Switch> <Route> <reduxConnect(…)>
  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
  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)
  13. Comlink https://github.com/GoogleChromeLabs/comlink

  14. None
  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
  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
  17. None
  18. None
  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; }
  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, }), ); }
  21. None
  22. package.json { "resolutions": { "bn.js": "4.11.8", } }

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

    ] }
  25. Assets loading • On-page optimalisation • preloading • async/defer •

    CDN optimalisation • Caching headers
  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">
  27. script async defer

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