This issue has been created
 
 
XWiki Platform / cid:jira-generated-image-avatar-6aa41b4c-27be-4eb2-86a9-bd3b0b066069 XWIKI-24848 Open

The navigation drawer is fully rendered on every page view although it is only shown on click

 
View issue   ·   Add comment
 

Issue created

 
cid:jira-generated-image-avatar-51c24fb2-4457-4aee-ad5e-7d241a794f57 Manuel Leduc created this issue on 09/Sep/26 15:35
 
Summary: The navigation drawer is fully rendered on every page view although it is only shown on click
Issue Type: cid:jira-generated-image-avatar-6aa41b4c-27be-4eb2-86a9-bd3b0b066069 Improvement
Affects Versions: 17.10.0-rc-1
Assignee: Unassigned
Components: Flamingo Skin
Created: 09/Sep/26 15:35
Labels: performance
Priority: cid:jira-generated-image-static-major-d186de74-08f8-4722-aef4-3c599e4ccf7b Major
Reporter: Manuel Leduc
Description:

Context

Measured on a plain page view (Sandbox.WebHome, no images, no comments, no macros, 18.8.0-SNAPSHOT), the server sends a 93,113-byte HTML document of which about 63% is not useful at first paint: 33.5 KB of markup for dialogs and menus nobody opened, and 24.9 KB of inline <script>. The overhead is a near-constant 51-57 KB per page view whatever the page contains, and the document is not compressed, so those are real bytes on the wire every time.

Reproduction steps

  1. Visit http://localhost:8080/xwiki/bin/view/Sandbox/
  2. Look at the HTML source of the page, or inspect #tmDrawer in the browser debugger
  3. Do not open the drawer

Expected

The drawer contents are not in the document until the user opens it.

Actual

The complete <dialog class="drawer-nav" id="tmDrawer"> is rendered server-side on every page view: 3,540 bytes, 3.8% of the document, holding the user menu and the wiki-level links (Administrator, Log-out, Administer Wiki, Page Index, User Index, Application Index, What's New, Wiki Index).

Opening the drawer fires zero network requests, confirming the content is entirely pre-rendered. The drawer is opened even less often than the "More Actions" menu.

It is also server-side work

Per page view, in flamingo/drawer.vm:

  • :32 — #largeUserAvatar($xcontext.user), resolving the avatar URL
  • :44 — $services.csrf.getToken() for the logout link, plus $xwiki.relativeRequestURL
  • :47 — $xwiki.getUserName($xcontext.user, false), a user document load
  • :63 — $services.uix.getExtensions('org.xwiki.plaftorm.drawer', ...)
  • :129 and :140 — per UIX, one hasAccess('admin', ...) and a full $services.uix.render($uix, 'html/5.0'), for each of Page Index, User Index, Application Index, What's New, Wiki Index and Administer Wiki

Also five $services.logging.getLogger('drawer.vm').debug(...) calls per UIX per page view (:65 and :131-134). Individually cheap, but Velocity evaluates the argument expressions — which string-format $uix, $!uix.documentReference and $!uix.authorReference — regardless of the log level. Those are worth guarding or dropping whatever is decided about the lazy loading.

Where it comes from

  • flamingo/drawer.vm:24-106 — the whole drawer
  • flamingo/menus_view.vm:52 — includes it, inside #macro(displayDrawerActivator) (:47-53)
  • flamingo/drawer_macros.vm#drawerItem, #drawerSeparator, #drawerCategoryHeader, #largeUserAvatar
  • flamingo/menus_language.vm — inlined by drawer.vm:95

Suggested fix

Fetch the drawer contents when it is opened, with the xpage= + #sendRequiredSkinExtensions() pattern described in the companion issue about the "More Actions" menu.

There is already a working call site that fetches the drawer exactly this way and cherry-picks a fragment out of it — XWiki/InplaceEditing.xml:1293-1300:

$('<div/>').load(xwikiDocument.getURL('get', $.param({
  'xpage': 'xpart',
  'vm': 'drawer.vm',
  'useLayoutVars': true
})) + '&' + location.search.substring(1) + ' #tmLanguages_menu', function() { … });

Trade-off: 3.54 KB off every page view, one request the first time the drawer is opened.

Caveat: drawer.vm:101 calls $globalPart.toString(), forcing the whole global section (including menus_language.vm) to render before deciding whether to emit its header — the same "content must be non-blank" problem as the actions menu, and it needs the same decision.