[Refactor/Chore] Separate lightweight AppIcon rendering from eager emoji data initialization
Self Checks
- I have read the Contributing Guide and Language Policy.
- This is only for refactors or chores; questions belong in Discussions.
- I have searched for existing issues, including closed ones.
- I confirm that I am using English to submit this report.
- 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
- I have filled in the required template fields.
Description
web/app/components/base/app-icon/index.tsx imports @emoji-mart/data and emoji-mart at module scope and calls init({ data }). Any static consumer of AppIcon therefore includes the full emoji implementation/data even when it only needs a simple icon.
In the inspected client build, the shared AppIcon chunk is 507,576 bytes (approximately 109,186 bytes gzip). Its modules include Emoji Mart and its data. The Knowledge list's static import closure includes this chunk, as do numerous sidebar, app-list and dialog consumers.
Separate the common display path from functionality that needs the complete emoji registry. Preserve stored legacy emoji IDs, Unicode emoji, image icons, fallback icons, hydration behavior, sizing and accessibility. Loading the picker must continue to work. The exact implementation should follow the supported icon contract rather than blindly replacing every ID with a text character.
Motivation
This dependency affects common list and navigation surfaces. Reducing eager icon dependencies can improve frequently visited routes instead of optimizing only an infrequently loaded large feature.
Acceptance criteria:
- Show before/after manifest or bundle evidence for Knowledge list and app-list consumers.
- The common icon display path should avoid eagerly initializing the complete emoji dataset where it is unnecessary.
- Cover Unicode, legacy IDs, image/fallback icons and SSR/hydration behavior with focused verification.
- Do not claim the entire current chunk size as guaranteed savings; shared dependencies and compatibility paths may remain.
Additional Context
Measurements come from a local Dify 1.17.1 development checkout (base commit 06e473015a9a1abb71da88ac0a0e92d96a992008, with local DevTools integration patches), using Vinext 1.0.0-beta.10 / Vite+ core 0.3.2 / Node 24.21.0. They are a diagnostic baseline, not a benchmark of an unmodified main checkout or a production network measurement. Related background: #30931 (closed).
Static dependency totals below follow manifest imports recursively, deduplicate files, and exclude dynamic imports, CSS, images and fonts. Gzip values are summed per-file estimates. Shared closures overlap and must not be added together.
Source: langgenius/dify