Slide 1

Slide 1 text

Performance optimisations of dApps @alesroubicek @PragueJS

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Performance bottlenecks • Design issues • Delivery issues

Slide 5

Slide 5 text

–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.”

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Original React tree

Slide 10

Slide 10 text

React tree without Drizzle

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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)

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

/* 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; }

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Preloading of assets

Slide 27

Slide 27 text

script async defer

Slide 28

Slide 28 text

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