Skip to content

[Epic] Refactor EuiIcon for performance and enhanced bundler support #8860

@tkajtoch

Description

@tkajtoch

✨ Summary

EuiIcon currently causes substantial, user-perceivable rendering issues in Kibana and creates friction in any non-webpack environment. We can solve this, amongst other problems, by refactoring EuiIcon to use modern browser and JS features, and greatly improve how icons are imported at scale.

❗ Problem or Opportunity

1. EuiIcon currently causes substantial, user-perceivable rendering issues in Kibana

EuiIcon applies a fade-in loading animation to each icon loaded for the first time during the application's runtime. This animation makes every instance of EuiIcon to be rendered on a separate document layer, which dramatically slows down page re-renders (the graphics operation, not React component re-renders) due to the layerizing job having to deal with many unnecessary* layers.

This slowdown is particularly noticeable in scrollable sections that display icons, especially EuiDataGrid (e.g., on the Alerts page). During my testing, the rendering took so long that the cell hover effects felt slow and choppy. I suspect it may be even worse on slower machines.

2. EuiIcon is currently not tree-shakeable, which can bloat bundle sizes for consumers

Note

Tree-shaking, also known as dead code elimination, is a process of removing unused code from distribution files. Its primary goal is to reduce the number of bytes needed to be shipped via network, parsed, compiled, and executed on users' devices, resulting in a better user experience.

EuiIcon uses dynamic import expressions to resolve string icon names such as editorRedo and import the corresponding icon SVG from the application bundle. It's an interesting technique that has benefits and, when supported, is easy to use, but almost never scales well.

The primary reason for subpar scalability is that the runtime applications need to store a mapping of all existing icons to SVG bundle files at all times. In the current implementation this results in:

  • 532 icon name mappings loaded at all times (~16KB; unminifiable)
  • 532 * 2 icon name to SVG bundle file mappings loaded at all times (* 2 because the current implementation doesn't limit the expression's scope to just .js files, so there's one record for when extension is included and one for when it's omitted) (~50KB minified)

66KB of mappings is needed just to let the runtime know which SVG file to fetch and display. This is included globally and cannot be tree-shaken due to the current implementation of EuiIcon.

3. EuiIcon causes friction when using EUI in any environment other than webpack

Some of the reported issues caused by trying to import EUI in projects using a bundler different than webpack:

🎯 Value

There's perceivable UX impact to EuiDataGrid, which means that it affects the core Kibana experience.

Between that, and the constant friction people deal with when trying to create POCs with EUI or integrate into new Elastic products make it a worthwhile endeavour.

Urgency

There's no particular urgency, people are working around this for now. The UX degradation is not ideal but it's also been that way for a long time.

🧠 Feasibility & Direction

❓ Open Questions to answer


📐 Definition

As the issue evolves, use this section to add concrete details.
This section can grow over time as the direction becomes more clear.
Remove sections if they're not needed or captured in an external document.

Design

Proposed Solution

Acceptance criteria

Definition of done

Documentation needs

Impact scope

Rollout plan


@tkajtoch Integrate the content below into the content above please.

Summary

EuiIcon has a few issues internally that we should address. The most noticeable one is definitely bundler support - EUI can only be used in apps bundled using webpack due to the usage of webpack magic strings to load icons on demand. This and other behaviors make the component slower than it should be at runtime.

Goals

  1. Refactor EuiIcon to not rely on webpack magic strings
  2. Deprecate referencing icon types by string and switch to using actual imports for tree shakeability and optimal bundle sizes
  3. Continue allowing asynchronous icon imports, but recommend regular imports for snappy user interfaces
  4. Avoid unnecessary animations and transitions to avoid icons being rendered in a separate layer - this drastically reduces performance during rerenders

Sub-issues

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions