Vue3 migration organization
@GretaD is already working on this.
Since Sep 2, 2026.
- #13589 by @GVodyanov — closed without merging
- Dominant language
- JavaScript
- Stars
- 1k
- Forks
- 348
- Avg merge
- 12h 28m
- Merged PRs (30d)
- 91
Description
Related to https://github.com/nextcloud/groupware/issues/64
Wave A — preparation, merged to main, shipped on Vue 2.7
Wave A ships as three PRs, one per section below. Each section is a single theme, is
independently releasable, and is independently revertible. The item IDs (A1…A18) are stable and
still index the per-item detail in §3; only the packaging changed.
Merge order is A-1 → A-2 → A-3, because A-3 contains A11, which rewrites the import line of nearly
every component and will conflict with anything still in flight.
A-1 — Template API alignment (@nextcloud/vue prop, event and slot renames) https://github.com/nextcloud/mail/pull/13589
Everything the v8.40 forward-compatible aliases already accept: props renamed, events renamed, slots
renamed, booleans inverted. Mechanical, template-only, no behaviour change on Vue 2.7. Land the items
in the listed order and rebase between them — they touch overlapping component files.
- A4 —
:checked/@update:checked→v-model/@update:model-valueonNcCheckboxRadioSwitch,NcActionCheckbox,NcActionRadio(13 files) - A5 —
:value/@update:value/@input→v-model/@update:model-valueon the 13 other input components (32 files) - A6 —
type="primary|secondary|…"→variant=, andnative-type→typeonNcButton/NcActions/NcDialogButton
A7 #default → #icon slot on NcInputField / NcTextField / NcPasswordField
- A9 — Inverted boolean props: audit
canClose,focusTrap,closeOnClickOutside,enableSwipe,showUserStatus*: https://github.com/nextcloud/mail/pull/13624 - A12 — Drop the
exactprop (Envelope.vue,EnvelopeSkeleton.vue) https://github.com/nextcloud/mail/pull/13625
A-2 — Retire the Vue-2-only dependencies and component APIs https://github.com/nextcloud/mail/pull/13626
Everything that has to stop being a Vue-2-only package or a removed-in-v9 component API. Few files,
but the only hand-written UI in Wave A, so this is the section that needs manual testing. Give each
replacement its own commit and its own QA pass — see §8.
- A2 — Drop the unused
v-tooltipplugin fromsrc/main.js(imported, registered, never used in a template) - A8 —
isMobilemixin →useIsMobile()composable (src/components/MailboxThread.vue, the only user) - A10 —
FilePickerVuecomponent →getFilePickerBuilder()function (4 files) - A13 — Replace
vue-autosize(Vue-2-only, no successor) - A14 — Replace
@riophae/vue-treeselectinMailboxInlinePicker.vue(Vue-2-only, unmaintained) — revives #13412 - A15 — Replace
vue-tabs-componentinAccountForm.vue(Vue-2-only) — revives #13411 - A16 — Replace
vue-dndropinquickActions/Settings.vue(Vue-2-only) — revives #13413 - A17 — Verify
emojiSearch/emojiAddRecentimport path for v9 (TextEditor.vue)
A-3 — Module boundaries and the v9 audit
Everything that changes how modules are imported rather than how components are used, plus the
written-down audit of what Wave B will have to repair. A11 is the whole reason this section is last.
- A1 —
import { translate as t }→import { t }(18 sites); same fortranslatePlural as n: https://github.com/nextcloud/mail/pull/13492
- [ ] A3 — ReplaceMOVED TO WAVE BVue.set/Vue.deletewith a localset/delshim (55 call sites, 3 files): https://github.com/nextcloud/mail/pull/13392 - A11 — Barrel imports
from '@nextcloud/vue'→ per-component subpath imports (~50 files) — last item in the wave - A18 — Deep-selector and internal-class-name audit (105 hits) — write down what will break, fix what can be fixed early
The three are close in size for different reasons: A-1 is the most files but one changed line per
site; A-2 is the fewest files but the only real new code; A-3 is ~50 mechanical files plus a
document. If A-2's replacements turn out larger than estimated, split A14–A16 out rather than
letting the PR grow past a few thousand lines.
Wave B — https://github.com/nextcloud/mail/pull/13666
Nothing here works on Vue 2. Land these onto vue3, then merge vue3 → main once.
- B1 — Dependency bump (#13407, rebase)
- B2 —
patch-package: fix or droppatches/splitpanes+2.4.1.patch(v9 ships splitpanes 4.x) - B3 — Entry points →
createApp(#13405/#13408, pick one, rebase) - B4 — Router →
createRouter/createWebHistory(folded into B3) - B5 —
.sync→v-model:prop(#13410, rebase — 13 sites, 10 files) - B6 — CKEditor →
@ckeditor/ckeditor5-vue(#13414, rebase) - B7 —
vue-shortkey→vue3-shortkey - B8 — Remove
vue-frag(NavigationAccount.vue) — Vue 3 has native fragments - B9 — Remove
.nativemodifiers (4 sites) and add the correspondingemitsdeclarations - B10 —
<template functional>→ plain SFC (src/components/icons/JunkIcon.vue) - B11 —
<transition>class renames:v-enter→v-enter-from,v-leave→v-leave-from(3 components) - B12 — Collapse the
set/delshim from A3 into plain assignment (one-file diff) - B13 — Unit tests:
@vue/test-utilsv1 → v2 (#13415, rebase) - B14 —
vitest.config.js:@vitejs/plugin-vue2→@vitejs/plugin-vue - B15 —
eslint.config.mjs:recommendedVue2→recommended, thennpm run lint:fix - B16 — Pinia 2 → 3,
@pinia/testingbump, dropPiniaVuePlugin - B17 — Add explicit
emits:declarations across components (ESLintvue/require-explicit-emits) - B18 — Drop the
Nextcloud.jsmixin in favour ofapp.config.globalPropertiesor per-file imports - B19 — CSS repair pass:
box-sizing: border-boxon modals/popovers,vs__*(vue-select 4),@vuepic/vue-datepickerreplacingmx-datepicker - B20 —
npm run buildclean,npm run lintclean,npm run stylelintclean,npm run test:unitgreen - B21 — Replace
Vue.set/Vue.deletewith a localset/delshim (55 call sites, 3 files): https://github.com/nextcloud/mail/pull/13392
Wave C — after the flip
- C1 — Full manual QA pass against the §8 matrix
- C2 — Playwright e2e suite green (
npm run test:e2e) - C3 — Design review, then follow-up styling PRs (calendar did exactly this — do not block the merge on pixel polish)
- C4 — File upstream bugs against
@nextcloud/vuefor anything broken in the library itself - C5 — Bump
appinfo/info.xmlif the Nextcloud minimum has to move - C6 — Optional follow-ups: Options API → Composition API,
<script setup>, TypeScript
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.