Skip to content

Vue3 migration organization #13622

Description

@GVodyanov

Related to nextcloud/groupware#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 (A1A18) 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) #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:checkedv-model / @update:model-value on NcCheckboxRadioSwitch, NcActionCheckbox, NcActionRadio (13 files)
  • A5:value / @update:value / @inputv-model / @update:model-value on the 13 other input components (32 files)
  • A6type="primary|secondary|…"variant=, and native-typetype on NcButton / NcActions / NcDialogButton
  • A7#default#icon slot on NcInputField / NcTextField / NcPasswordField
  • A9 — Inverted boolean props: audit canClose, focusTrap, closeOnClickOutside, enableSwipe, showUserStatus*: feat(vue3): inverted boolean props #13624
  • A12 — Drop the exact prop (Envelope.vue, EnvelopeSkeleton.vue)

A-2 — Retire the Vue-2-only dependencies and component APIs

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-tooltip plugin from src/main.js (imported, registered, never used in a template)
  • A8isMobile mixin → useIsMobile() composable (src/components/MailboxThread.vue, the only user)
  • A10FilePickerVue component → getFilePickerBuilder() function (4 files)
  • A13 — Replace vue-autosize (Vue-2-only, no successor)
  • A14 — Replace @riophae/vue-treeselect in MailboxInlinePicker.vue (Vue-2-only, unmaintained) — revives #13412
  • A15 — Replace vue-tabs-component in AccountForm.vue (Vue-2-only) — revives #13411
  • A16 — Replace vue-dndrop in quickActions/Settings.vue (Vue-2-only) — revives #13413
  • A17 — Verify emojiSearch / emojiAddRecent import 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.

  • A1import { translate as t }import { t } (18 sites); same for translatePlural as n
  • A3 — Replace Vue.set/Vue.delete with a local set/del shim (55 call sites, 3 files)
  • 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 — the flip, stacked onto the vue3 branch

Nothing here works on Vue 2. Land these onto vue3, then merge vue3main once.

  • B1 — Dependency bump (#13407, rebase)
  • B2patch-package: fix or drop patches/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.syncv-model:prop (#13410, rebase — 13 sites, 10 files)
  • B6 — CKEditor → @ckeditor/ckeditor5-vue (#13414, rebase)
  • B7vue-shortkeyvue3-shortkey
  • B8 — Remove vue-frag (NavigationAccount.vue) — Vue 3 has native fragments
  • B9 — Remove .native modifiers (4 sites) and add the corresponding emits declarations
  • B10<template functional> → plain SFC (src/components/icons/JunkIcon.vue)
  • B11<transition> class renames: v-enterv-enter-from, v-leavev-leave-from (3 components)
  • B12 — Collapse the set/del shim from A3 into plain assignment (one-file diff)
  • B13 — Unit tests: @vue/test-utils v1 → v2 (#13415, rebase)
  • B14vitest.config.js: @vitejs/plugin-vue2@vitejs/plugin-vue
  • B15eslint.config.mjs: recommendedVue2recommended, then npm run lint:fix
  • B16 — Pinia 2 → 3, @pinia/testing bump, drop PiniaVuePlugin
  • B17 — Add explicit emits: declarations across components (ESLint vue/require-explicit-emits)
  • B18 — Drop the Nextcloud.js mixin in favour of app.config.globalProperties or per-file imports
  • B19 — CSS repair pass: box-sizing: border-box on modals/popovers, vs__* (vue-select 4), @vuepic/vue-datepicker replacing mx-datepicker
  • B20npm run build clean, npm run lint clean, npm run stylelint clean, npm run test:unit green

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/vue for anything broken in the library itself
  • C5 — Bump appinfo/info.xml if the Nextcloud minimum has to move
  • C6 — Optional follow-ups: Options API → Composition API, <script setup>, TypeScript

Metadata

Metadata

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions