Use one vendored copy of vue-virtual-scroller
What this does
We vendor two copies of vue-virtual-scroller. CONTEXT_ALIASES redirects Vue 3 pages to the second one. That copy crashes under @vue/compat.
vendor/assets/javascripts/vue-virtual-scroller-vue3/src/components/DynamicScrollerItem.vue:245 calls this.$slots.default(). That is a function only under a real Vue 3 runtime. Under @vue/compat it is an array, so the webpack build threw as soon as a page opted into Vue 3 with Option 1:
TypeError: this.$slots.default is not a functionThis MR drops the vendor/vue-virtual-scroller redirect and deletes that copy. Every page now uses vendor/assets/javascripts/vue-virtual-scroller, which the rest of the application already uses on Vue 2 pages.
Why remove rather than patch
- Every prop the call sites pass exists on the remaining copy:
items,keyField,itemSize,minItemSize,buffer,pageMode,useTransform, and onDynamicScrollerItemitem,active,watchData,sizeDependencies,emitResize,tag. - It revives a dead binding.
app/assets/javascripts/diffs/components/app.vue:893passes:use-transform="false". Only the remaining copy implements that prop; the deleted one renamed it todisableTransform, so the binding did nothing whenever the diffs page ran under Vue 3. - The deleted copy was not the release it claimed. Its
package.jsonsaid2.0.0-beta.8, but the published2.0.0-beta.8contains neitherdisableTransformnoruseTransform. It was a snapshot of the 2.x master branch taken in e90f862b, carrying a local change to a prop default. - Nothing else referenced it once the redirect was gone.
Why not upgrade instead
Moving to a current upstream release is separate, larger work, and the vendoring model is most of the reason.
We cannot vendor the current source easily, because it is TypeScript. Upstream converted the library after our snapshot was taken. At 2.0.0-beta.9, 21 of the 29 source files are .ts and the five SFCs are <script setup lang="ts">. Our infection matcher is:
const INFECTABLE_RE = /\.(js|mjs|vue)$/;.ts does not match, so the infection would never propagate into the composables, which is where all the logic lives after the v2 rewrite. That is the same class of failure that produced this bug. Widening the regex is possible, but it is a change to shared Vue 3 migration infrastructure affecting every page, not a dependency bump.
Taking the built output instead does not work either. From 2.0.0-beta.9 onwards npm ships dist only, with no src. That is a single pre-compiled ESM bundle importing vue directly, which bypasses the ?vue3 model entirely.
So an upgrade means either vendoring TypeScript from a git tag and teaching the infection tooling about it, or stopping vendoring altogether. Both are worth doing deliberately rather than as part of a crash fix.
On top of that, every candidate version carries the same two migrations: the IdState mixin is gone from 2.0.x onwards, and disableTransform reverts to the upstream default against our patched one. #619357 (closed) has the full comparison.
Verification
- In GDK with
vue3_migrate_artifactson, the artifacts page servespages.projects.artifacts.vue3.js, mountsCiArtifactsRoot, and expanding a job row renders the scroller (vue-recycle-scroller ready direction-vertical) with no$slotserror. Before this change the same interaction threw on every expand.- Verification passes in the child MR !250423 (merged)
MR stack
| Goal | MR |
|---|---|
| Harden tests / guarantee fixes work | Add feature spec coverage for the artifacts page (!251287 - merged) |
| Clean up faulty dependency | Use one vendored copy of vue-virtual-scroller (!251351 - merged) |
| Fix Vite Vue 3 infection | Align Vite and webpack Vue 3 alias resolution (!251350 - merged) |
| Migration of artifacts entrypoints | Add Vue 3 rollout flag for the artifacts pages (!250423 - merged) |
References
- Part of #619357 (closed)
- Unblocks !250423 (merged)
- Followed by !251350 (merged), which fixes the bundler divergence that hid this