-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ml] Optimize bundles, reduce page load async chunks by 74% #179311
[ml] Optimize bundles, reduce page load async chunks by 74% #179311
Conversation
c172f04
to
f1f06e6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for spotting and improving this!
@elasticmachine merge upstream |
@darnautov I can't merge this, unfortunately. For a very strange reason I haven't been able to identify, this change causes several chunks to bloat to 2MB each. It appears code gets copied for each one. I've only been able to fix it by outright removing the My only guess is that because a number of the files pertaining to that collection of routes are still in JS, there may be a circular or other dependency. But I haven't been able to hunt it down, after a day of trying. Perhaps @mistic or @elastic/kibana-operations can assist. But this is a crazy effect from moving a simple constant. |
Another update-- I've run all the permutations, and all of the changes in this PR are fine with only one exception: If Unfortunately, that appears to to be the change needed to see the performance gains in the browser. |
I believe I've found the cause and the solution to the async module bloat: a utility function was defined in Importing the single utility from that file brought all of the other code with it. By moving it to its own module, we decoupled the utility and prevented the rest of the application code from being bundled with the async module. |
927dfbf
to
5b3c7e8
Compare
6ec6a38
to
022c61c
Compare
db32220
to
ea4267f
Compare
…lpers that are conditionally run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🚀 many thanks @clintandrewhall!
Async chunks are significantly smaller now. Reorganising code by getting rid of some deep imports and introducing async imports for routes are the great enhancements 🙏🏻
@elasticmachine merge upstream |
💚 Build SucceededMetrics [docs]Module Count
Public APIs missing comments
Async chunks
Page load bundle
Unknown metric groupsAPI count
async chunk count
History
To update your PR or re-run it, just comment with: |
Summary
The
AnomalyExplorerChartsService
was importing theSWIM_LANE_LABEL_WIDTH
numerical constant fromswimlane_container.tsx
. As a result, the entirety of that file was being included in the async bundle.AnomalyExplorerChartsService
is loaded asynchronously on page load by the embeddable. By relocating the constant to its own file-- as well as other optimizations (see below)-- we reduce the async page load by 74%, (in dev mode).Before -
351k
After -
93.4k
Unfortunately, this change led to a bloating of async modules, the cause of which is still unclear. The application async chunk weighed in at 2.2 MB compressed! To get this PR to a shippable state, I refactored additional code to bring down duplication and bloat.
The result is an
ml
experience that fetches small bundles on demand as someone interacts with it:More work can be done to continue to optimize the plugin, of course, but this set of changes is an excellent start, (and case study on bundle load).
Other optimizations in this PR
start
services are conditional, and contain their own async calls. I've removed these from the register helper, (which itself is a brute-force offload of code from the plugin, but is still loaded every time), and loaded them async if the conditions apply.ml
use factories to create individual routes. In a lot of cases, the pages these routes displayed were not asynchronously loaded, adding tremendous amounts of React code to the root application.React.lazy
async modules, (usingdynamic
from@kbn/shared-ux-utility
.export * from
directives frompublic/shared.ts
to accurately reflect what is being consumed outside theml
plugin, (and also reduce the size of that bundle.lodash
imports to submodule imports to enable tree-shaking, (if ever enabled in webpack).getMlGlobalServices
off of theapp.tsx
file for import by others, (to avoid depending on the rest of the code there)./common
to avoid importing code, (though, admittedly, types are compiled away). But it felt cleaner to move them out.