Open adamstankiewicz opened 1 year ago
Hi @adamstankiewicz, We did some RnD (on Account and Discussions MFE) on our end and the following are our findings:
Account MFE
npm run build
)51 seconds
35 seconds
2.8 seconds
2.9~2.8 seconds
Discussions MFE
npm run build
)1 minute 20 seconds
45 seconds
5 seconds
4.5 seconds
It seems like the bundle splitting didn't affect load time but the total build time got improved.
NOTE: We used the above given webpack configuration
@Syed-Ali-Abbas-Zaidi Thanks for the update!
Interesting about the improvement to build time. Regarding load time, I wouldn't expect too much of a change just with the above given Webpack configuration since the browser is still downloading all the same code; just a higher quantity of small files versus 1 larger file. That said, if/when MFEs start code splitting through dynamic imports and/or React.lazy
and Suspense
, these smaller, independent chunks could be dynamically loaded as the user interacts with the application.
A few follow-up questions/comments:
npm run serve
, see docs)? I've noticed some discrepancies when doing performance benchmarks locally utilizing Webpack Dev Server vs. the production build directly.node_modules
today and the consuming MFE opted to code split an import of one of these node_modules
through a dynamic import and/or React.lazy
and Suspense
, will Webpack already support extracting that package out as its own chunk? Or do we need to introduce Webpack configuration changes as shown above to split out chunks before consumers can implement code splitting?bundlewatch
, bundlesize
) CI check in GitHub to have better observability into ongoing changes to bundle size at the PR level. Example:[suggestion] We might consider experimenting with a CI check for bundle size in our frontend repos (e.g., bundlewatch, bundlesize) CI check in GitHub to have better observability into ongoing changes to bundle size at the PR level.
[inform] Filed this GitHub issue related to bundlewatch
/bundlesize
: https://github.com/openedx/axim-engineering/issues/837
npm run serve
to benchmark the performance locally. (It works like a charm :) )Suspense
and React.lazy
. (Here is one of the example)
Description
Context: Defining the performance KPI "Largest Contentful Paint"
An important KPI from frontend performance is the Core Web Vital called Largest Contentful Paint (LCP), which measures loading performance:
The "best practice" for LCP is as follows:
Generally, I believe the majority of our edx.org MFEs fall in the "Poor" category for LCP.
About Webpack Production Builds
Webpack Bundle Analyzer
When running
npm run build
, a Webpack Bundle Analyzer report is generated:dist/report.html
:(Using standard Webpack configuration from
@edx/frontend-build
)Finding performance bottlenecks for Open edX MFEs
Based on Chrome's DevTools' performance debugging tools, I've identified that one (large) bottleneck in terms of loading performance for at least a handful of Open edX MFEs is loading the JavaScript assets, and specifically large JS chunks for as vendor
node_modules
, from the network after the initial download of theindex.html
file.The below screenshot utilizes Chrome's "Performance Insights", throttled to "Fast 3G" to simulate slower network speeds on poor network connections.
As shown above, the
542.[hash].js
file takes over 12+ seconds to download on the simulated poor network speeds. In this time, users are shown a blank white screen with no indication of progress and is still before any network API calls have been made to any Django services.An incremental step towards mitigate performance bottlenecks such as shown above is be to modify the
webpack.prod.config.js
configuration file in@edx/frontend-build
to ensure Webpack is configured to appropriately split up vendor and application chunks according to more explicit rules that may improve performance and set the foundation for consuming MFEs to implement code splitting withReact.lazy
andSuspense
.For example, the following Webpack configuration will update the previous Webpack bundle report to contain significantly many more generated files:
The resulting Webpack bundle report:
Note that instead of all
node_modules
(vendor) getting consolidated into a single JS file, Webpack now splits out many more chunks when appropriate to ensure they are able to get loaded performantly by the browser.Take for example,
plotly.js
. Gzipped, it's size is 1.03 MB. Currently, the MFE forces the user to download all 1.03 MB ofplotly.js
even if their user session never renders any component that usesplotly.js
. That additional bandwidth is expensive for the user in terms of performance.Instead, we could enable
plotly.js
to get split out (as seen in above screenshot) into it's own distinct bundle that may be code split by the consuming MFE utilizingReact.lazy
andSuspense
, e.g.:See this demo from React.