Uploaded image for project: 'XWiki Platform'
  1. XWiki Platform
  2. XWIKI-24847

The "More Actions" menu is fully rendered on every page view although it is only shown on click

    XMLWordPrintable

Details

    • Improvement
    • Resolution: Unresolved
    • Major
    • None
    • 17.10.0-rc-1
    • Flamingo Skin
    • Unknown

    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 #tmMoreActions in the browser debugger
      3. Do not click on "More Actions"

      Expected

      The contents of the menu are not in the document until the user opens the menu.

      Actual

      The whole dropdown is rendered server-side on every page view and merely hidden with CSS: 6,453 bytes, 6.9% of the document, for the 14 entries Administer Page, Copy, Move / Rename, Delete, Export, Annotate, Print Preview, Share by Email, Source, Children, Comments, Attachments (1), History, Information.

      Opening the menu currently fires zero network requests, which confirms the content is entirely pre-rendered.

      It is also server-side work, not only markup

      Per page view, whether or not the menu is ever opened:

      • three counts are computed even though only non-zero ones are displayed — $doc.getObjects('XWiki.XWikiComments').size() (shortcuts.vm:42), $services.annotations.getAnnotations($doc).size() (:49) and $doc.getAttachmentList().size() (:54), the last being the "Attachments (1)" above;
      • the right checks in menus_content.vm:23-45, including getObjectNumbers for users and groups — plus a redundant second $xwiki.hasAccessLevel('view') at :457 when $canView from :23 already holds it;
      • roughly 14 $services.localization.render(...) and 14 $services.icon.renderHTML(...) calls;
      • three UI extension points resolved through #displaySecureUIX (:198-241), each doing a per-UIX hasAccess('admin', $uix.authorReference, ...) (:211-212) and a full $services.uix.render($uix, 'html/5.0') (:219).

      Where it comes from

      All under xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/:

      • menus_content.vm:426-484 — #macro(displayOptionsMenu), invoked at :483
      • menus_content.vm:349-377 — #macro(displayAdminActions) (Copy, Move/Rename, Delete)
      • menus_content.vm:382-421 — #macro(displayMoreActions) (Export, Print Preview, Share by Email)
      • shortcuts.vm:25-98 — the "Viewers" entries
      • menus_macros.vm:137-150 — #macro(submenuitem)
      • menus_content.vm:159-185 — #macro(displayMenu), which wraps it in the <dl class="dropdown-menu">

      Suggested fix

      Fetch the menu body when the menu is opened (show.bs.dropdown), using the established pattern: an xpage= partial that declares its own skin extensions with #initRequiredSkinExtensions() / #sendRequiredSkinExtensions() (templates/display_macros.vm:205-213), which sets the X-XWIKI-HTML-HEAD header that xwiki.js:1692-1755 already consumes on every XHR. A complete 12-line example of such a partial is templates/security/requiredrights/getRequiredRightsInformation.vm, fetched by requiredRightsInformationUpdater.js:26-51. Any lazily inserted markup must fire xwiki:dom:updated afterwards.

      Trade-off to accept knowingly: this removes 6.45 KB from every page view but adds one request the first time a user opens the menu, so the menu gains a short latency on first open. For a menu opened on a small fraction of page views that is a good trade, but it is a real one.

      Three things the implementation has to handle:

      1. menus_content.vm:413-414 pulls $xwiki.jsx.use('XWiki.SharePage') / ssx.use from inside the menu build — those calls have to move into the partial.
      2. The keyboard shortcut handlers at menus_content.vm:490-521 hard-reference DOM ids that only exist because the menu was rendered ($('tmViewSource').href, $('tmActionDelete').href, $('tmEditWiki').href, ...) and must be guarded or moved.
      3. #displayMenu (:173) only emits the <dl> wrapper if the rendered content is non-blank, i.e. the server currently renders the whole menu just to decide whether to show it. A lazy design has to either always emit the wrapper and hide it when the fetched body comes back empty, or introduce a cheap "would this menu have content?" predicate. This is the one part that needs actual design work.

      Note that setting async_enabled = 1 on the UIX instead would not work today: async.js:103 activates on ".xwiki-async:visible" and its MutationObserver only watches addedNodes, so a placeholder inside a hidden dropdown is never fetched. That is worth a separate issue.

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              mleduc Manuel Leduc
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated: