div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*RSFFO9MBdVfriltE)"></div>
</div>
</div>
</a>
</div><h2 id="4469">Use faster loops and data transducers.</h2><p id="8a81">Native loop functions, like map, reduce,forEach, filter are terrible with bulk operations and don’t manage memory heap well.</p><figure id="1145"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*[email protected]"><figcaption></figcaption></figure><p id="73b8">The projects listed below are very good for faster iteration and data mutation. They generally outperform with larger datasets</p><div id="523d" class="link-block">
<a href="https://github.com/jlongster/transducers.js">
<div>
<div>
<h2>jlongster/transducers.js</h2>
<div><h3>A small library for generalized transformation of data (inspired by Clojure's transducers) - jlongster/transducers.js</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*tnMZXALPzdrJMYDw)"></div>
</div>
</div>
</a>
</div><div id="cd5b" class="link-block">
<a href="https://github.com/selfrefactor/rambda">
<div>
<div>
<h2>selfrefactor/rambda</h2>
<div><h3>Rambda is smaller and faster alternative to the popular functional programming library Ramda. - Documentation You can…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*rt6p4ivaF0ff5bcM)"></div>
</div>
</div>
</a>
</div><h2 id="c466">Use memoization</h2><p id="f1fb">Memoizing in react should be utilized more than often. Especially on components that have to perform heavy renders or have heavy Intense lifecycle hooks.</p><p id="e5a8">Reactive codebases have a bad habit of executing a lot of code during render cycles.</p><p id="2bae">engineers also gravitate to the easiest place to put code, in the render method. We also map Over arrays in render methods quite often. Memoizing some older legacy code with heavy renders is a quick fix. Applying memoization in utility functions like URL parsers can also save time, especially if they are executed multiple times, yielding the same result</p><div id="2aeb" class="link-block">
<a href="https://github.com/theKashey/memoize-state">
<div>
<div>
<h2>theKashey/memoize-state</h2>
<div><h3>Caching (aka memoization) is very powerful optimization technique - however it only makes sense when maintaining the…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*ONlQiPUnnzJKUNCM)"></div>
</div>
</div>
</a>
</div><h2 id="62ae">Use more sophisticated preloading</h2><p id="74f5">In combination with TTI callbacks. Lazy preloading links can be beneficial.</p><div id="b6d2" class="link-block">
<a href="https://github.com/ibrahimcesar/react-quicklink">
<div>
<div>
<h2>ibrahimcesar/react-quicklink</h2>
<div><h3>⚡️ Faster subsequent page-loads by prefetching in-viewport links during idle time for React, port of…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*GM0CbKnVDSiqz1lY)"></div>
</div>
</div>
</a>
</div><div id="534a" class="link-block">
<a href="https://github.com/GoogleChromeLabs/quicklink">
<div>
<div>
<h2>GoogleChromeLabs/quicklink</h2>
<div><h3>Faster subsequent page-loads by prefetching in-viewport links during idle time Quicklink attempts to make navigations…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*yaqFezZrFCIimSuk)"></div>
</div>
</div>
</a>
</div><h2 id="8037">Take Advantage of Multi-Threading</h2><p id="1e91">Worker pools are not easy to configure in a seamless manner.</p><p id="f1ea">Using <code>workerpool</code> and <b>Webpack 5’s Module Federation</b>, we can use advanced architectural patterns with cutting edge tech in webpack 5.</p><p id="ad22">Federated worker threads allow you to use the Host’s own remote as a way to hand off and work to another thread, its very seamless to do so with MF and this approach can work server or client-side (with a little change) Ill be writing about universal worker pools soon as I have the motivation to finish it.</p><p id="9d30">Here's what the setup looks like:</p><ol><li>I'll need to configure ModuleFederationPlugin</li></ol><div id="6220"><pre><span class="hljs-symbol">plugins:</span> [
new webpack.container.ModuleFederationPlugin(<span class="hljs-punctuation">{</span>
<span class="hljs-symbol"> name:</span> <span class="hljs-string">"dashboard"</span>,
<span class="hljs-symbol"> filename:</span> <span class="hljs-string">"static/runtime/remoteEntry.js"</span>,
<span class="hljs-symbol"> exposes:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-string">"./utils"</span>: <span class="hljs-string">"./lighthouse/utils"</span>,
<span class="hljs-punctuation">}</span>,
<span class="hljs-symbol"> remotes:</span> <span class="hljs-punctuation">{</span>
<span class="hljs-symbol"> dashboard:</span>
<span class="hljs-string">"dashboard@http://localhost:3000/_next/static/runtime/remoteEntry.js"</span>,
<span class="hljs-punctuation">}</span>,
<span class="hljs-punctuation">}</span>),
],</pre></div><p id="6126">2. Ill create a worker file, just for more efficient handoff (avoiding serialization of functions)</p><div id="5d65"><pre><span class="hljs-comment">//worker.js</span>
<span class="hljs-keyword">const</span> <span class="hljs-title function_">federatedWorkerImport</span> = <span class="hljs-keyword">async</span> (<span class="hljs-params">containerPath, shareInit</span>) => {
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>);
<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = federatedWorkerImport;</pre></div><p id="4549">3. I need to create a helper function to generate a worker</p><div id="1126"><pre><span class="hljs-keyword">const</span> createWorker = <span class="hljs-keyword">async</span> (data, request, moduleExport) => {
<span class="hljs-keyword">if</span> (!process.browser) {
<span class="hljs-keyword">const</span> path = non_webpack_require(<span class="hljs-string">"path"</span>);
<span class="hljs-comment">// could also make this an external, then just use "require"</span>
<span class="hljs-keyword">const</span> initRemote = non_webpack_require(
<span class="hljs-comment">// needs webpack runtime to get webpack_require</span>
<span class="hljs-comment">// externally require the worker code with node.js This could be inline,</span>
<span class="hljs-comment">// but i decided to move the bootstapping code somewhere else. Technically if this were not next.js</span>
<span class="hljs-comment">// we should be able to import('dashboard/utils')</span>
<span class="hljs-comment">// workers/index.js was in this file, but its cleaner to just move the boilerplate</span>
path.<span class="hljs-keyword">join</span>(process.cwd(), <span class="hljs-string">"workers/index.js"</span>)
);
<span class="hljs-comment">// essentially do what webpack is supposed to do in a proper environment.</span>
<span class="hljs-comment">// attach the remote container, initialize share scopes.</span>
<span class="hljs-comment">// The webpack parser does something similer when you require(app1/thing), so make a RemoteModule</span>
<span class="hljs-keyword">const</span> federatedRequire = <span class="hljs-keyword">await</span> initRemote(
path.<span class="hljs-keyword">join</span>(process.cwd(), <span class="hljs-string">".next/server/static/runtime/remoteEntry.js"</span>),
() => ({
initSharing: __webpack_init_sharing__,
shareScopes: __webpack_share_scopes__,
})
);
<span class="hljs-comment">// the getter, but abstracted. This async gets the module via the low-level api.</span>
<span class="hljs-comment">// The remote requires utils (basically this file lol) and i pull toFixed off its exports.</span>
<span class="hljs-comment">// alternatively i could copy paste, but MF provides me the power to import the current file as an entrypoint</span>
<span class="hljs-keyword">const</span> RemoteModule = <span class="hljs-keyword">await</span> federatedRequire(request);
<span class="hljs-keyword">return</span> RemoteModule[moduleExport](data);
}
};</pre></div><p id="6540">4. Now to create a function that hands-off data processing to a thread in the worker pool</p><div id="eb54"><pre>const generateScatterChartData = async (data) => {
<span class="hljs-keyword">if</span> (!process.browser) {
<span class="hljs-keyword">return</span> pool
.exec(createWorker, [data, <span class="hljs-string">"./utils"</span>, <span class="hljs-string">"generateScatterChartProcessor"</span>])
.<span class="hljs-keyword">then</span>(<span class="hljs-keyword">function</span> <span class="hljs-title"></span>(result) {
<span class="hljs-keyword">return</span> <span class="hljs-type">result</span>;
})
.catch(<span class="hljs-keyword">function</span> <span class="hljs-title"></span>(err) {
console.error(err);
})
.<span class="hljs-keyword">then</span>(<span class="hljs-keyword">function</span> <span class="hljs-title"></span>(result) {
<span class="hljs-keyword">return</span> <span class="hljs-type">result</span>;
});
}
<span class="hljs-keyword">return</span> {};
};</pre></div><p id="d7fc">5. And here we are, using this function in <code>getInitialProps</code></p><div id="d004"><pre><span class="hljs-keyword">Report</span>.getInitialProps = async ({ <span class="hljs-keyword">query</span> }) => {
<span class="hljs-keyword">const</span> { <span class="hljs-keyword">meta</span>, ...<span class="hljs-keyword">report</span> } = await fetch(
hostname + <span class="hljs-string">"api/get-report?report="</span> + <span class="hljs-keyword">query</span>.<span class="hljs-keyword">report</span>
).then((res) => res.json()); </pre></div><div id="eb62"><pre> const [
<span class="hljs-built_in"> scatterChartData,</span>
<span class="hljs-built_in"> whiskerChartData,</span>
<span class="hljs-built_in"> multiSeriesChartData,</span>
] = await Promise.all([
generateScatterChartData(report), //worker <span class="hljs-keyword">thread</span>
generateWhiskerChartData(report), //worker <span class="hljs-keyword">thread</span>
generateMultiSeriesChartData(report), //worker <span class="hljs-keyword">thread</span>
])<span class="hljs-comment">;</span>
<span class="hljs-keyword">return</span> {
<span class="hljs-built_in"> scatterChartData,</span>
<span class="hljs-built_in"> whiskerChartData,</span>
<span class="hljs-built_in"> multiSeriesChartData,</span>
<span class="hljs-built_in"> meta,</span>
<span class="hljs-title"> appKeys:</span> Object.keys(report),
<span class="hljs-built_in"> query,</span>
}<span class="hljs-comment">;</span>
}<span class="hljs-comment">;</span></pre></div><p id="48bc">I used <code>workerpool</code> to create universal workers on both node and client.</p><div id="4f5d" class="link-block">
<a href="https://github.com/josdejong/workerpool">
<div>
<div>
<h2>josdejong/workerpool</h2>
<div><h3>offers an easy way to create a pool of workers for both dynamically offloading computations as well as managing a pool…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*zp4IQ-uhDrZJfVGq)"></div>
</div>
</div>
</a>
</div><p id="346a">Doing so gave me a<b> 400% boost in-app</b> performance and server response times</p><p id="0a58">Other options, I have not tried — like parallel.js</p><div id="26f2" class="link-block">
<a href="https://github.com/parallel-js/parallel.js">
<div>
<div>
<h2>parallel-js/parallel.js</h2>
<div><h3>Easy Parallel Computing with Javascript Parallel.js is a library for to make parallel computing in Javascript simple…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*QwWtgFSSk1T-2gkq)"></div>
</div>
</div>
</a>
</div><p id="a4ee">I’m also experimenting on ways to grant access to the dom from inside Web workers, this could potentially reduce vendor impact if some of them are able to work inside a worker with a shimmed DOM API</p><div id="79bb" class="link-block">
<a href="https://github.com/ampproject/worker-dom">
<div>
<div>
<h2>ampproject/worker-dom</h2>
<div><h3>The same DOM API and Frameworks you know, but in a Web Worker. - ampproject/worker-dom</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*MkkjmDoUMfLQNNZW)"></div>
</div>
</div>
</a>
</div><h2 id="749a">Monitor performance at the module level.</h2><p id="11d3">This method is very useful for finding heavy modules that should be code split or pre-heated. You can then go back and retroactively work to improve the worst offending modules.</p><div id="8f69" class="link-block">
<a href="https://github.com/SinaMFE/perf-module-webpack-plugin">
<div>
<div>
<h2>SinaMFE/perf-module-webpack-plugin</h2>
<div><h3>the plugin computing time of all the modules bundled by webpack,and show the list of the top N modules who cost self…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*IId0kpaAxkhBkwOZ)"></div>
</div>
</div>
</a>
</div><div id="151c" class="link-block">
<a href="https://github.com/bfrost2893/user-timing-plus">
<div>
<div>
<h2>bfrost2893/user-timing-plus</h2>
<div><h3>Enhanced User Timing API. Contribute to bfrost2893/user-timing-plus development by creating an account on GitHub.</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*HYmDoMDGv_X40ECQ)"></div>
</div>
</div>
</a>
</div><h2 id="1579">Great Vendors for Monitoring</h2><p id="2aad">While module level and user timings are helpful — it can be more effort to set up a Kibana dashboard to plot all this data. Especially RUM information.</p><p id="7fa3"><a href="https://www.bluetriangle.com/"><b>Blue Triangle</b></a><b> is one of my favorite</b> vendors when it comes to performance. Some of the <b>core features I love</b> are:</p><ul><li>Realtime RUM data</li><li>Reports on Core Web Vitals metrics</li><li>You can run synthetic samples</li><li>They can accurately calculate the missed revenue opportunity caused by poor performance</li><li>Similar to Gate, Blue Triangle has the ability to calculat
Options
e TTI on the client-side in RUM.</li><li>Its got a great data science engine, I've used this to diagnose specific issues at specific internet exchange nodes.</li><li>It's POWERFUL</li><li>The staff are AMAZING to work with and are there to support their clients.</li><li>The company takes user input seriously</li></ul><p id="ee97">RUM information helps see what impact your code is having on user devices. Thanks to blue triangle, I'm able to deploy experimental performance enhancements (inside a try-catch) into production. Then can look at the RUM data. Within 5 minutes I usually have my answer, they will either merge to master or re-deploy the master branch and continue working on my experiment till i see the impact I expect.</p><p id="b05a">You are also able to send custom measurement timing back to BTT</p><p id="1c6e">There are some <b>things I would like to see Blue Triangle improve</b> on the product.</p><ul><li>Expose your RUM measurement functions as callback events.
Since BT already reports all this RUM data back to its servers. It would be AMAZING to have something like <code>window.btt.events.isInteractive(myCallback</code> and <code>window.btt.networkType // returns [3G,WIFI,LTE]</code>not only would BT be able to measure RUM, but actually provide callbacks that help engineers improve. If you know the network speed/quality of a device, it would be amazing to hook into that information. I could build adaptive systems backed by RUM data</li><li>Report back the standard <code>performance.mark</code> user timings API. Id like to be able to graph component level performance without using a custom marker.</li></ul><p id="ae99"><a href="https://sentry.io/"><b>Sentry</b></a><b> </b>is another critical vendor worth investing in.</p><p id="be1b">You need to know if there are race conditions that were not picked up in standard regressions and QA. Error reporting and fast deploy pipelines let you move faster and rollback quickly.</p><p id="1825">Spending time exploring sentry APIs and available webhook options will be very valuable. I'm planning to use Sentry, Blue Triangle, and the still-in-beta <b>Federation Dashboard</b> to leverage <b>Module Federation</b> and command control systems that will be capable of automatically adapting how and what version of federated code gets attached to the host. I'll publish a separate article on what an architecture designed to be self-healing and self-regulating would look like. The good news is; a system like that is not too hard to make since I own the tooling to make it possible.</p><h2 id="b01e">Graphana and Kibana</h2><p id="8e17">Fantastic tools for charting and consuming large amounts of data.
These have been my go-to at previous companies — having data is priceless. You can sell any initiative if you have data.</p><p id="9763">This article (a little old compared to module federation these days) goes into a little depth on what data i was plotting and how those graphana dashboards led us to outperform backend fragment caches</p><div id="6932" class="link-block">
<a href="https://levelup.gitconnected.com/micro-frontend-architecture-replacing-a-monolith-from-the-inside-out-61f60d2e14c1">
<div>
<div>
<h2>Micro Frontend Architecture: Replacing a monolith from the inside out</h2>
<div><h3>How to modernize a legacy application with micro-frontend technology</h3></div>
<div><p>levelup.gitconnected.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*P7xZ-hErIvKArY3DDY18mQ.jpeg)"></div>
</div>
</div>
</a>
</div><p id="69d6">Using these dashboarding tools, you get a huge amount of data in high resolution. Especially on the frontend. I use a proxy to emit logs based on POST requests ill send to the endpoint. Graphing any and all frontend metrics is how you remain online and stable.</p><p id="10a4">I good monitoring tactic is to attach events to business-critical flows. Like, add to cart. Graphing clicks and successful calls lets you create a moving average, then any metrics fall below the standard moving average — alerts are triggered and notifications are sent to slack.</p><p id="fcb5">I've relied on this to locate bad deploy issues. Graphana has also saved some serious revenue. I was able to react and respond to the famous east coast AWS outage before Amazon had updated their status. By the time the AWS status page showed East Coast outage. We had already moved production to our backup data center in Europe.</p><h2 id="2727">Consider lite hydration for quicker initial startup.</h2><p id="98b5">This method works by replacing ReactDOM with something lightweight. It can help with initial hydration times to get an app partially or fully interactive. You can also use a smaller dom library to handle only the initial hydration. Then re-hydrate with ReactDOM during idle time</p><div id="cfe4" class="link-block">
<a href="https://github.com/dai-shi/react-hooks-worker">
<div>
<div>
<h2>dai-shi/react-hooks-worker</h2>
<div><h3>React custom hooks for web workers. Web Workers are another thread from the main thread in browsers. We can run heavy…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*JjxYKWk-XUASh_T5)"></div>
</div>
</div>
</a>
</div><div id="58d0" class="link-block">
<a href="https://github.com/alewin/useWorker">
<div>
<div>
<h2>alewin/useWorker</h2>
<div><h3>Run expensive function without blocking UI (Show live gif) Supports Promises pattern instead of event-messages Size:…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*RvQ010DD2RgUg8sV)"></div>
</div>
</div>
</a>
</div><div id="f9a6" class="link-block">
<a href="https://github.com/LukasBombach/next-super-performance">
<div>
<div>
<h2>LukasBombach/next-super-performance</h2>
<div><h3>Partial hydration for Next.js with Preact X. Explanation: At spring we are creating websites for newspapers and we are…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*5XrIVFfh9HzonenB)"></div>
</div>
</div>
</a>
</div><div id="8bf6" class="link-block">
<a href="https://github.com/jiayihu/react-tiny-dom">
<div>
<div>
<h2>jiayihu/react-tiny-dom</h2>
<div><h3>react-tiny-dom is a minimal implementation of react-dom as custom renderer using React 16 official Renderer API. The…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*3k47f_45QJ7xQIwi)"></div>
</div>
</div>
</a>
</div><div id="fe3f" class="link-block">
<a href="https://github.com/web-perf/react-worker-dom">
<div>
<div>
<h2>web-perf/react-worker-dom</h2>
<div><h3>A React Custom renderer using Web Workers. All the Virtual DOM reconcilliations happen in a WebWorker thread. Only node…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*Zn_A1vBlloEH4O9r)"></div>
</div>
</div>
</a>
</div><div id="9c03" class="link-block">
<a href="https://github.com/NervJS/nerv">
<div>
<div>
<h2>NervJS/nerv</h2>
<div><h3>A blazing fast React alternative, compatible with IE8 and React 16. - NervJS/nerv</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*DVGTnrG49VmB_r6T)"></div>
</div>
</div>
</a>
</div><div id="0f6a" class="link-block">
<a href="https://github.com/sophiebits/react-dom-mini">
<div>
<div>
<h2>sophiebits/react-dom-mini</h2>
<div><h3>Toy React renderer from my React Conf 2019 talk, "Building a Custom React Renderer" Dismiss GitHub is home to over 50…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*ObDuQc8kFzJ5nN-R)"></div>
</div>
</div>
</a>
</div><h2 id="f33c">Or try debounced render HOCs</h2><p id="a25e">This is a new trick I am experimenting with (right now)</p><p id="59bc">My <code>Link</code> component is slow. Children change, props change. Each time I need to parse the URL and figure out if its an internal router link, or an external hyperlink.</p><p id="c260">While this isn't the most optimized solution, it was very effective under the conditions I'm trying it out against.</p><p id="fc82">Parsing the URL takes about 1ms, the whole component takes a little around 1–2ms. Overall, this is how much time the component takes (for all links combined)</p><figure id="d048"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*jQT3-tPnwdolzYECqmw_Sw.png"><figcaption></figcaption></figure><p id="4a7b">Around 50ms per render! Ouch!</p><p id="4f4e">Since this article pushed me to get universal workers up and running. I decided to see how much <code>link</code> would improve if I moved URL parsing to a <code>workerpool</code> I had been using lazy hydration to improve the time, but I needed to open PR to enable hydration without wrapper components.</p><p id="2693">I moved the URL parsing into a worker, then created a <code>useEffect</code> hook to update hyperlinks once there is a response from the workers, which let me process all links in parallel, off the main thread. which would save around 200ms.</p><div id="e584"><pre>const [match, setMatch] = React.useState({});
React.useEffect(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
process.browser
&& requestIdleCallback(<span class="hljs-function"><span class="hljs-params">()</span> =></span> {
pool
.sendCommand(<span class="hljs-string">'doesMatchRoute'</span>, [url, publicConfig])
.<span class="hljs-keyword">then</span>(<span class="hljs-function"><span class="hljs-params">(data)</span> =></span> {
setMatch(data);
})
.<span class="hljs-keyword">catch</span>(<span class="hljs-function"><span class="hljs-params">(err)</span> =></span> {});
});
}, [url]);
const { routeMatch, relativeURL } = process.browser
? match
: doesMatchRoute(url);</pre></div><p id="ce83">I don't want flicker to happen since I no longer have the props that were passed to its child markup. So rendering could flash if I <code>return null</code> till the worker is done. <b>This is SSR</b> so maintaining the initial markup is important. Till I move back to lazy hydration, ill just treat all links are <code><a></code></p><p id="eacc">Even when I removed the flicker — those workers had to re-compute the same URLs a few times, with nothing important actually changing that requires an immediate 50ms re-render. This got me thinking about debouncing the component's re-render cycle. If props change many times, let's debounce how quickly react will actually re-render.</p><div id="ff7a" class="link-block">
<a href="https://github.com/podefr/react-debounce-render">
<div>
<div>
<h2>podefr/react-debounce-render</h2>
<div><h3>react-debounce-render is a Higher Order Component that wraps your react components and debounces their rendering. This…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*JRwTFv_6IO5mfWhC)"></div>
</div>
</div>
</a>
</div><div id="e2ca" class="link-block">
<a href="https://dev.to/botreetechnologies/how-can-we-debounce-render-a-react-component-with-example-33gj">
<div>
<div>
<h2>How can we debounce render a React Component? (with example)</h2>
<div><h3>According to https://www.geeksforgeeks.org/debouncing-in-javascript/ Debouncing in JavaScript is a practice used to…</h3></div>
<div><p>dev.to</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*p5daO6SCctohxsz5)"></div>
</div>
</div>
</a>
</div><div id="3f88"><pre><span class="hljs-function"><span class="hljs-keyword">export</span> <span class="hljs-title">default</span> <span class="hljs-params">(process.browser
? debounceRender(LinkGenerator, <span class="hljs-number">0.1</span>) : LinkGenerator
: LinkGenerator)</span></span>;</pre></div><p id="cdef">This is a fairly gimmicky solution. But I cannot argue with the results of all this combined. With partial-hydration, I anticipate the initial render tick will improve, since I am still calling <code>react.createElement</code></p><figure id="57dd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AQkS2bcKLXDPbh2T7P0kOw.png"><figcaption></figcaption></figure><p id="77f8" type="7">Hacky or not — that's impressive!</p><h2 id="78e9">What the final result will look like.</h2><p id="168f">I'll avoid debouncing. because I'm still paying for that first render.</p><p id="8ffb">The final solution will be with <code>react-lazy-hydration</code> but with additional modifications. I want to have the ability to hydrate on promise resolution.</p><p id="dbc9">This would let me leave markup totally ignored by React, till the worker responds with updates. A promise capability will also let me choose to hydrate react components based on TTI. I can use Gate, which is already monitoring chip performance and blocking vendor tags until there is less stress.</p><p id="62e2">The worker pool needs to be consolidated into a hook or utility function, most importantly — I want these worker pools to use module federation (universally). My messages to a worker would act as a controller for MF within the worker. Since a remote container is only 5kb, the initial parse and startup time of the worker is significantly better. As i need more of my own codebase, the host messages the remote via a worker, tell it which module it should execute, and what arguments to execute with.</p>
<figure id="910a">
<div>
<div>
<img class="ratio" src="http://placehold.it/16x9">
<iframe class="" src="https://cdn.embedly.com/widgets/media.html?type=text%2Fhtml&key=a19fcc184b9711e1b4764040d3dc5c07&schema=twitter&url=https%3A//twitter.com/scriptedalchemy/status/1313315713088589828&image=" allowfullscreen="" frameborder="0" height="281" width="500">
</div>
</div>
</figure></iframe></div></div></figure><h2 id="8078">Utilize the GPU for data processing</h2><p id="2a31">The CPU is able to perform any computational task. But the GPU is faster at specific tasks — moving work to the GPU can result in much faster operations. But the GPU is not as versatile as a CPU, offloading random functions might not yield the expected result. So choose wisely and benchmark what should live in a worker and what should live in a GPU thread</p><div id="92d8" class="link-block">
<a href="https://github.com/gpujs/gpu.js">
<div>
<div>
<h2>gpujs/gpu.js</h2>
<div><h3>GPU.js is a JavaScript Acceleration library for GPGPU (General purpose computing on GPUs) in JavaScript for Web and…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*ltWxEsH1bIfn9evn)"></div>
</div>
</div>
</a>
</div><h2 id="8ec3">DRY out code with better static analysis</h2><p id="93d5">Removing code is still the best performance tactic around. Don't look at the gzip size reduction, look at the uncompressed file size. You can remove 300kb of code — when gzip is applied it can end up being 5kb. But the browser still needs to uncompress and parse the full size. Just because it's small to transport doesn't mean it's just as easy to JIT parse, compile, and execute. Removing code is your best perf tactic :)</p><div id="2fe1" class="link-block">
<a href="https://github.com/rdgd/twly">
<div>
<div>
<h2>rdgd/twly</h2>
<div><h3>twly (pronounced "towel-E") is a static analysis tool which can help you keep your code DRY (Don't Repeat Yourself) by…</h3></div>
<div><p>github.com</p></div>
</div>
<div>
<div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*-dDv2iqMOOpidAjN)"></div>
</div>
</div>
</a>
</div><h2 id="f9ff">That’s all for now!</h2><p id="3019">This article is getting too long. I’ll write another one since there is plenty more to speak about.</p><p id="812d">Part 2 will be tweeted and added to this spot.</p><p id="d6c4">You know where to find me.</p><p id="7a5a">Twitter: <a href="https://twitter.com/ScriptedAlchemy">ScriptedAlchemy</a></p><p id="6d20">Github: ScriptedAlchemy</p></article></body>
How To Boost JavaScript Runtime Performance
Part 1: Advanced Tactics to reduce App startup time
There’s lots of advice, but it seems to taper off when it comes to advanced performance tactics. I’ve read the articles, but it’s either too vague, too broad, or just basic stuff I have already done. Where are the more advanced articles on performance, most importantly — why are we not combining tech and talking about a stacked implementation?
This has been my real-world experience, tools, or tactics I've used. I like web performance and am a little obsessed. These ideas can be a little quirky or abstract, there are probably better ways to handle perf.
With that said…
The Basics
Let's get these out the way, mostly common sense and typical perf suggestions.
Use Brotli
Use http2
Use webp and a CDN that can dynamically resize and serve the most efficient formats
Code split your app
Utilize edge networks
Don’t preload videos, don’t autoplay videos until intersection observer is activated.
Use CSS and JS optimization
Tweak webpack chunking to reduce cache misses when redeploying
Trim the tag manager, move really static code into your own
Lazy-load images with intersection observer
Responsive images, lazy-loading, and intersection observer.
This component can speed up load times. Especially if a page consists of multiple images, even small ones. Image requests can block up the network priority. I try not to lazy load the first image in a carousel depending on where it is in the fold. You want to leave some margin when using intersection observer so there's enough scrolling time left for resources to be loaded just before view
It's important to note that IntersecionObserver v1 cannot determine opacity or height:0 as being hidden still, so make sure to display none collapsed content that technically is still in view, at height 0. The same applies to z-index.
Use resource hints against third party domains
There is a lot of third party tags on most production environments. preconnecting domains and preloading critical tags will cut down on HTTP handshakes and RTT in general. HTTPS and DNS resolution can take up to 200ms.
I'm pretty sure this repo has a bug in it. But something like this is very useful to dynamically create resource hints. It's especially useful when combining with other performance tactics, like Gate
With a quick overview of some basic perf improvements. Let's look at some other perf improvements.
Use requestIdleCallback on anything heavy.
Executing code during idle time is a great way to reduce runtime overhead. I'll often wrap componentDidMount or componentDidUpdate in idleCallback. Especially when mounted code executes anything heavy, like objectFitImages polyfills or event handler callbacks.
Idle callback schedules background execution at some point in the near future. Usually within a few milliseconds after being created. It's a useful way to reduce long-running function times. Some code can run without blocking the event loop.
Idle Callback is very useful when combined with other performance tactics, there's also plenty of idle-callback polyfills to take advantage of.
Use Network Idle callbacks
Running heavy operations when the network is determined idle, similar to TTI callbacks. I've not tried this since TTI does most of what I need.
Pre-heating can be used in a few ways. The core concept is to separate code loading from its execution. Giving the environment an opportunity to “warm-up” before immediately having to go from network, parse, compile to execution.
getInSequence(modulesToHeat,(warm)=>newPromise((resolve)=>{
requestIdleCallback(()=>{
resolve(warm())
})
)).then(()=>{
// you could use the library in the promise. But if App contained the mount and render function as well.
const ReactDOM = require('react-dom')
const App = require('./App')
ReactDOM.hydrate(App,DOMNode)
})
Such a tactic improves initial paint and render time since the main thread is not immediately slammed with requiring and executing code on the same tick. Preheating can get you paint and render times under 50ms.
This tactic can be retrofitted to third party tags. The pre-heat would use dynamic resource hints followed by creating a script tag in idleCallback ticks. This mechanism works best when combined with how Gate works against unblocking third party tags
I use a similar tactic when using Module Federation.
functionpreloadComponent(scope, module) {
returnasync () => {
// Initializes the share scope. This fills it with known provided modules from this build and all remotesawait__webpack_init_sharing__("default");
const container = window[scope]; // or get the container somewhere else// Initialize the container, it may provide shared modulesawait container.init(__webpack_share_scopes__.default);
// the chunk is downloaded constfactory = awaitwindow[scope].get(module);
return factory;
};
}
const preload = preloadComponent(scope,module)
setTimeout(()=>{
preload.then(factory=>{
// the factory is called, which returns module.exports
IdleCallback can be implemented, but since module federation is async under this implementation — you should preload future modules somewhere higher up in the application lifecycle. Combining with intersection observer, you can perform preloading before the module has to be called.
Read about it seperately. Gate had been the largest performance improvement I’ve seen.
Partial and Lazy Hydration
You can drastically improve internal application performance by only hydrating part of the application. Since you usually only need some of a page to be interactive, like above the fold content. Everything else can remain as static markup from SSR. We can then hydrate additional react components with intersection observer, idle callback, or not at all — leaving the markup static.
React hydration can be an extensive operation. The less we need to hydrate upfront, the faster the hydration process will complete.
When combined with Gate lifecycle hooks we can hydrate low priority components after TTI has been reached.
A good combo is whenVisible or on TTI calculations. TTI is calculated client-side by monitoring performance APIs and CPU active cycles. It works in all browsers too. User experience is not compromised since hydration will occur before the components are in view (with intersection observer) — otherwise, if the user is not looking at it, there’s no reason we can hydrate those areas of the application when the CPU is consistently idle.
The advantage of a TTI callback is that lighthouse will not measure code executed after TTI. While TTI itself isn’t heavily weighted anymore, it’s a very useful way to improve lighthouse and RUM metrics. So I use it to reduce the time of long-running functions like react hydration. Concurrent mode will likely improve the function execution time in the future.
Similar to TTI events, you can also get device capacity and network speed. Depending on what network or memory conditions are like, I can aggressively lazy hydrate or offload more vendor code. You can also adjust image quality and resolution.
Memoizing in react should be utilized more than often. Especially on components that have to perform heavy renders or have heavy Intense lifecycle hooks.
Reactive codebases have a bad habit of executing a lot of code during render cycles.
engineers also gravitate to the easiest place to put code, in the render method. We also map Over arrays in render methods quite often. Memoizing some older legacy code with heavy renders is a quick fix. Applying memoization in utility functions like URL parsers can also save time, especially if they are executed multiple times, yielding the same result
Worker pools are not easy to configure in a seamless manner.
Using workerpool and Webpack 5’s Module Federation, we can use advanced architectural patterns with cutting edge tech in webpack 5.
Federated worker threads allow you to use the Host’s own remote as a way to hand off and work to another thread, its very seamless to do so with MF and this approach can work server or client-side (with a little change) Ill be writing about universal worker pools soon as I have the motivation to finish it.
2. Ill create a worker file, just for more efficient handoff (avoiding serialization of functions)
//worker.jsconstfederatedWorkerImport = async (containerPath, shareInit) => {
const path = require("path");
global.__webpack_require__ = require(path.join(
process.cwd(),
".next/server/webpack-runtime.js"
));
const {
initSharing: __webpack_init_sharing__,
shareScopes: __webpack_share_scopes__,
} = shareInit();
// initialize any sharing, unlikely in a workerawait__webpack_init_sharing__("default");
// require containerconst container = require(containerPath).dashboard;
// Initialize the container, it may provide shared modulesawait container.init(__webpack_share_scopes__.default);
return(request) => {
return container.get(request).then((factory) =>factory());
};
};
module.exports = federatedWorkerImport;
3. I need to create a helper function to generate a worker
const createWorker = async (data, request, moduleExport) => {
if (!process.browser) {
const path = __non_webpack_require__("path");
// could also make this an external, then just use "require"const initRemote = __non_webpack_require__(
// needs webpack runtime to get __webpack_require__// externally require the worker code with node.js This could be inline,// but i decided to move the bootstapping code somewhere else. Technically if this were not next.js// we should be able to import('dashboard/utils')// workers/index.js was in this file, but its cleaner to just move the boilerplate
path.join(process.cwd(), "workers/index.js")
);
// essentially do what webpack is supposed to do in a proper environment.// attach the remote container, initialize share scopes.// The webpack parser does something similer when you require(app1/thing), so make a RemoteModuleconst federatedRequire = await initRemote(
path.join(process.cwd(), ".next/server/static/runtime/remoteEntry.js"),
() => ({
initSharing: __webpack_init_sharing__,
shareScopes: __webpack_share_scopes__,
})
);
// the getter, but abstracted. This async gets the module via the low-level api.// The remote requires utils (basically this file lol) and i pull toFixed off its exports.// alternatively i could copy paste, but MF provides me the power to import the current file as an entrypointconst RemoteModule = await federatedRequire(request);
return RemoteModule[moduleExport](data);
}
};
4. Now to create a function that hands-off data processing to a thread in the worker pool
I’m also experimenting on ways to grant access to the dom from inside Web workers, this could potentially reduce vendor impact if some of them are able to work inside a worker with a shimmed DOM API
This method is very useful for finding heavy modules that should be code split or pre-heated. You can then go back and retroactively work to improve the worst offending modules.
While module level and user timings are helpful — it can be more effort to set up a Kibana dashboard to plot all this data. Especially RUM information.
Blue Triangle is one of my favorite vendors when it comes to performance. Some of the core features I love are:
Realtime RUM data
Reports on Core Web Vitals metrics
You can run synthetic samples
They can accurately calculate the missed revenue opportunity caused by poor performance
Similar to Gate, Blue Triangle has the ability to calculate TTI on the client-side in RUM.
Its got a great data science engine, I've used this to diagnose specific issues at specific internet exchange nodes.
It's POWERFUL
The staff are AMAZING to work with and are there to support their clients.
The company takes user input seriously
RUM information helps see what impact your code is having on user devices. Thanks to blue triangle, I'm able to deploy experimental performance enhancements (inside a try-catch) into production. Then can look at the RUM data. Within 5 minutes I usually have my answer, they will either merge to master or re-deploy the master branch and continue working on my experiment till i see the impact I expect.
You are also able to send custom measurement timing back to BTT
There are some things I would like to see Blue Triangle improve on the product.
Expose your RUM measurement functions as callback events.
Since BT already reports all this RUM data back to its servers. It would be AMAZING to have something like window.btt.events.isInteractive(myCallback and window.btt.networkType // returns [3G,WIFI,LTE]not only would BT be able to measure RUM, but actually provide callbacks that help engineers improve. If you know the network speed/quality of a device, it would be amazing to hook into that information. I could build adaptive systems backed by RUM data
Report back the standard performance.mark user timings API. Id like to be able to graph component level performance without using a custom marker.
Sentryis another critical vendor worth investing in.
You need to know if there are race conditions that were not picked up in standard regressions and QA. Error reporting and fast deploy pipelines let you move faster and rollback quickly.
Spending time exploring sentry APIs and available webhook options will be very valuable. I'm planning to use Sentry, Blue Triangle, and the still-in-beta Federation Dashboard to leverage Module Federation and command control systems that will be capable of automatically adapting how and what version of federated code gets attached to the host. I'll publish a separate article on what an architecture designed to be self-healing and self-regulating would look like. The good news is; a system like that is not too hard to make since I own the tooling to make it possible.
Graphana and Kibana
Fantastic tools for charting and consuming large amounts of data.
These have been my go-to at previous companies — having data is priceless. You can sell any initiative if you have data.
This article (a little old compared to module federation these days) goes into a little depth on what data i was plotting and how those graphana dashboards led us to outperform backend fragment caches
Using these dashboarding tools, you get a huge amount of data in high resolution. Especially on the frontend. I use a proxy to emit logs based on POST requests ill send to the endpoint. Graphing any and all frontend metrics is how you remain online and stable.
I good monitoring tactic is to attach events to business-critical flows. Like, add to cart. Graphing clicks and successful calls lets you create a moving average, then any metrics fall below the standard moving average — alerts are triggered and notifications are sent to slack.
I've relied on this to locate bad deploy issues. Graphana has also saved some serious revenue. I was able to react and respond to the famous east coast AWS outage before Amazon had updated their status. By the time the AWS status page showed East Coast outage. We had already moved production to our backup data center in Europe.
Consider lite hydration for quicker initial startup.
This method works by replacing ReactDOM with something lightweight. It can help with initial hydration times to get an app partially or fully interactive. You can also use a smaller dom library to handle only the initial hydration. Then re-hydrate with ReactDOM during idle time
This is a new trick I am experimenting with (right now)
My Link component is slow. Children change, props change. Each time I need to parse the URL and figure out if its an internal router link, or an external hyperlink.
While this isn't the most optimized solution, it was very effective under the conditions I'm trying it out against.
Parsing the URL takes about 1ms, the whole component takes a little around 1–2ms. Overall, this is how much time the component takes (for all links combined)
Around 50ms per render! Ouch!
Since this article pushed me to get universal workers up and running. I decided to see how much link would improve if I moved URL parsing to a workerpool I had been using lazy hydration to improve the time, but I needed to open PR to enable hydration without wrapper components.
I moved the URL parsing into a worker, then created a useEffect hook to update hyperlinks once there is a response from the workers, which let me process all links in parallel, off the main thread. which would save around 200ms.
I don't want flicker to happen since I no longer have the props that were passed to its child markup. So rendering could flash if I return null till the worker is done. This is SSR so maintaining the initial markup is important. Till I move back to lazy hydration, ill just treat all links are <a>
Even when I removed the flicker — those workers had to re-compute the same URLs a few times, with nothing important actually changing that requires an immediate 50ms re-render. This got me thinking about debouncing the component's re-render cycle. If props change many times, let's debounce how quickly react will actually re-render.
This is a fairly gimmicky solution. But I cannot argue with the results of all this combined. With partial-hydration, I anticipate the initial render tick will improve, since I am still calling react.createElement
Hacky or not — that's impressive!
What the final result will look like.
I'll avoid debouncing. because I'm still paying for that first render.
The final solution will be with react-lazy-hydration but with additional modifications. I want to have the ability to hydrate on promise resolution.
This would let me leave markup totally ignored by React, till the worker responds with updates. A promise capability will also let me choose to hydrate react components based on TTI. I can use Gate, which is already monitoring chip performance and blocking vendor tags until there is less stress.
The worker pool needs to be consolidated into a hook or utility function, most importantly — I want these worker pools to use module federation (universally). My messages to a worker would act as a controller for MF within the worker. Since a remote container is only 5kb, the initial parse and startup time of the worker is significantly better. As i need more of my own codebase, the host messages the remote via a worker, tell it which module it should execute, and what arguments to execute with.
Utilize the GPU for data processing
The CPU is able to perform any computational task. But the GPU is faster at specific tasks — moving work to the GPU can result in much faster operations. But the GPU is not as versatile as a CPU, offloading random functions might not yield the expected result. So choose wisely and benchmark what should live in a worker and what should live in a GPU thread
Removing code is still the best performance tactic around. Don't look at the gzip size reduction, look at the uncompressed file size. You can remove 300kb of code — when gzip is applied it can end up being 5kb. But the browser still needs to uncompress and parse the full size. Just because it's small to transport doesn't mean it's just as easy to JIT parse, compile, and execute. Removing code is your best perf tactic :)