Case study: Optimalizace výkonu dApp

Case study: Optimalizace výkonu dApp

428a9c6e5b151e618d4db288105bc5f3?s=128

Aleš Roubíček

June 06, 2019
Tweet

Transcript

  1. Case Study Optimalizace výkonu dApp @alesroubicek #TopMonksCaffe

  2. None
  3. None
  4. None
  5. 1. analýza • Hlavní úzké hrdlo - Drizzle • Kód

    v žalostném stavu • nedodržování pravidel zanesených do linteru • nedodržování návrhových vzorů • tuna mrtvého a zakomentovaného kódu • absence smysluplných testů • Spousta chyb a upozornění v konzoli
  6. –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.”
  7. Architektonické nedostatky • Render blocking operace v hlavním vlákně •

    Nedodržování vzorů vyžadovaných knihovnami • Stav managující komponenty ve view stromu • Inicializace stavových komponent s každým view • Blockchain state & view state coupling • Generátor zbytečného boilerplate
  8. Aplikační stav • React, Redux, Web3.js, Drizzle, Pixi.js • function

    view(data) {} • Single Atom Application State
  9. Původní strom v Reactu <CustomContainer> <ConnectedRouter> <DrizzleContainer> <Switch> <Route> <drizzleConnect(…)>

  10. Vysekání Drizzle z Reactu <CustomContainer> <ConnectedRouter> <DrizzleContainer> <Switch> <Route> <drizzleConnect(…)>

    <ReduxContainer> <ConnectedRouter> <Switch> <Route> <reduxConnect(…)>
  11. Redux & Sagas • Úplná extrace komunikace s web3 z

    lifecycle metod komponent do redux-saga • Maximální snaha o PureComponents • Kompletní eliminace Drizzle stavu a komponent z React stromu čistě do Redux Store • Reakce na změny v blockchainu pouze přes akce/sagas • Masivní očista kódu dle ESlint pravidel a pomocí Prettier
  12. None
  13. 2. analýza • Příliš velké moduly kódu • Přibalování přirozeně

    statických assetů • Přibalování zbytečných závislostí • Render blocking resources v HTML (fonty, scripty) • Absence pre-renderu a preloading
  14. Velikost bundle • Webpack Bundle Analyzer 
 https://github.com/webpack-contrib/webpack-bundle-analyzer

  15. None
  16. None
  17. /* 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; }
  18. 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.test.com/${network}/contracts/${version}/`; return [prefix, contract, '.json'].join(''); } const fetchContract = c \> fetch(contractUrl(c)).then(r \> r.json()); const contracts = ['SomeToken', 'OtherToken', 'FooToken', 'BarToken']; export function getContract() { return Promise.all(contracts.map(fetchContract)).then( ([SomeToken, OtherToken, FooToken, BarToken]) \> ({ SomeToken, OtherToken, FooToken, BarToken, }), ); }
  19. None
  20. package.json { "resolutions": { "bn.js": “4.11.8", } }

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

    ] }
  23. Načítání assetů • On-page optimalizace • preloading • async/defer •

    CDN optimalizace • Cachovací hlavičky
  24. Přednačítání assetů <link rel="preconnect" href="https://ajax.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect"

    href="https://fonts.gstatic.com"> <link rel="preload" as="script" crossorigin href="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"> <link rel="preload" as="font" crossorigin href="https://fonts.gstatic.com/s/vt323/v10/pxiKyp0ihIEF2isfFJXUdVNF.woff2">
  25. Asychronní fonty <script> WebFontConfig = { google: { families: [

    'Space Mono:400,700', 'Work Sans:400,600', 'VT323', ], }, }; </script> <script async crossorigin src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"> </script>
  26. script async defer

  27. CDN cache boosting 'use strict'; exports.handler = (event, context, callback)

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