Give ?vue3 SFC copies their own hot-reload record id

What does this MR do and why?

Fixes #629099: on the rspack dev server, super sidebar flyout menus do not open on pages with a Vue 3 migration flag enabled (for example /-/automate/agent-sessions with vue3_migrate_duo_agents_platform), and the console shows:

[Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading '_base')"
found in ---> <GlModal> <FeatureLibraryModal> <SidebarMenu> ...
TypeError: Cannot read properties of undefined (reading 'componentInstance')

Root cause

  • vue-loader 15 computes the hot-reload record id as hash(shortFilePath), without the resource query, so modal.vue and modal.vue?vue3 share one id.
  • vue-hot-reload-api is deliberately a single shared module for both realms (SCANNER_BYPASS_PACKAGES in config/rspack/vue3_infection_loader.js), so both copies register into one map.
  • The generated hot-reload code is isRecorded(id) ? api.reload(id, options) : api.createRecord(id, options). On a clean page load, the second copy to execute calls api.reload(), whose updateOptions() copies its options onto the first copy's options object. The Vue 2 GlModal ends up with a @vue/compat BModal constructor in components.
  • A compat constructor has super but no sealedOptions, so Vue 2's resolveModifiedOptions throws on the first options key, _base. The sidebar render aborts and the flyouts never mount.

Only development builds emit the hot-reload code, so production is unaffected. Vite is also unaffected: @vitejs/plugin-vue2 only calls createRecord on load and never reload, verified both on a clean load and on a hot update of a component loaded in both realms.

Fix

The vue-loader patch appends -vue3 to the hot-reload id when the resource query contains vue3, so each realm keeps its own record. The scoped CSS id is not touched.

Verified on a Caproni rig running rspack: before the change window.__VUE_HOT_MAP__ held one GlModal record whose Ctor.super.version was 2.7.16 while options.components.BModal.super.version was 3.5.42 (seven @gitlab/ui components were mixed this way: GlModal, GlTooltip, GlPopover, GlTable, GlDropdown, GlTabs, GlDropdownForm). After the change there are separate 932f7b4a and 932f7b4a-vue3 records with the right Vue version each, the console is clean and the Manage flyout opens.

How to set up and validate locally

  1. Use the rspack dev server (GDK default) and clear its cache once so the patched loader output is used: rm -rf tmp/cache/rspack.
  2. Feature.enable(:vue3_migrate_duo_agents_platform).
  3. Open a project's /-/automate/agent-sessions page and hover a collapsed sidebar section such as Manage.
  4. Without this MR: _base error in the console, no flyout. With this MR: no errors, flyout opens.

MR acceptance checklist

Merge request reports

Loading
Loading