Skip to content

chore: migrate from Vue 2/Webpack to Vue 3/Vite with bootstrap-vue-next - #44

Open
sundancekid73 wants to merge 15 commits into
mainfrom
chore/vue3-vite-migration
Open

chore: migrate from Vue 2/Webpack to Vue 3/Vite with bootstrap-vue-next#44
sundancekid73 wants to merge 15 commits into
mainfrom
chore/vue3-vite-migration

Conversation

@sundancekid73

Copy link
Copy Markdown
Collaborator

Summary

  • Replace Vue CLI/Webpack with Vite, upgrade all core dependencies to Vue 3
  • Migrate bootstrap-vue to bootstrap-vue-next (Bootstrap 5), rewire app infrastructure (Pinia, Vue Router 4, Keycloak-js v26)
  • Rewrite Editor.vue for Tiptap v2 + Vue 3; auto-resolve bootstrap-vue-next components via unplugin-vue-components
  • Fix BTable filter API (removed in bootstrap-vue-next) across all 6 list components using computed filteredX bound to :items
  • Fix blank-page crash on list views, broken logout link, navbar dark-text contrast
  • Fix detail form layout: button list now beside content (col-auto), form labels restored (:value to :model-value), relation row elements spaced evenly
  • Fix keyword tag alignment in TagInput by replacing grid layout with flexbox
  • Fix SearchableDropdown left-alignment and flex-fill inside input-group
  • Bump form-data to 4.0.6 (GHSA-hmw2-7cc7-3qxx CRLF injection patch)

Test plan

  • Login via Keycloak works
  • Comics list loads and search/filter works
  • Keywords, Persons, Predicates, Publishers, Roles lists load and filter works
  • Comic detail form: button list appears left of content, all sections (creator, publisher, keywords, genres, cover, comment) render correctly
  • Keyword detail form: keyword name displays, relations show source/predicate/target evenly spaced
  • Person, Publisher, Role detail forms: header label displays correctly
  • Editor (rich text) works in keyword descriptions
  • Save/delete actions work across all entities

🤖 Generated with Claude Code

sundancekid73 and others added 15 commits May 21, 2026 14:57
Creates proxy network if needed, then starts admin-webapp containers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- vite.config.js replaces vue.config.js (Vite + @vitejs/plugin-vue)
- index.html moved to project root with ESM script tag
- package.json: Vue 3, Vue Router 4, Pinia, Bootstrap 5, bootstrap-vue-next,
  Tiptap v2, FontAwesome vue-fontawesome v3, Vitest; removed Vue CLI, Vuex,
  Bootstrap 4, bootstrap-vue, tiptap v1, vuejs-logger, core-js, regenerator-runtime
- .env.*: VUE_APP_* renamed to VITE_*
- Dockerfile-stage: ARG/ENV renamed to VITE_API_URL
- eslint.config.mjs: switch to Vue 3 flat/essential ruleset, remove babel parser
- pnpm-workspace.yaml: approve esbuild, vue-demi, @parcel/watcher build scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- src/services/logger.js: thin console wrapper replacing vuejs-logger
- src/services/keycloak.js: keycloak singleton module (was Vue.prototype)
- src/stores/comicListStore.js: Pinia store replacing Vue.observable services/store.js
- src/main.js: createApp, Pinia, bootstrap-vue-next, Vue 3 globalProperties
- src/router.js: createRouter/createWebHistory (Vue Router 4), keycloak singleton
- src/services/httpclient.js: remove Vue import, use keycloak/logger modules, VITE_API_URL
- Header.vue, ComicList.vue, SearchableDropdown.vue, TagInput.vue: Pinia store
- src/styles/styles.scss: remove old Bootstrap 4/bootstrap-vue imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace $bvModal.msgBoxConfirm with inline b-modal pattern in all 6 list
  components (ComicList, KeywordList, PersonList, PublisherList, RolesList,
  PredicateList)
- Remove b-form-row → b-row, b-input-group-prepend/append → slot syntax,
  b-jumbotron → plain div, b-navbar sticky → sticky="top"
- Rename Bootstrap 4 utility classes (ml/mr/pl/pr → ms/me/ps/pe, float-left/right
  → float-start/end) across all affected files
- Rename value prop → modelValue and $emit('input') → $emit('update:modelValue')
  in all 14 custom components
- Migrate Relation.vue and KeywordForm.vue from services/store to Pinia
- Fix $set (removed in Vue 3) in PredicateList.vue → direct array assignment
- Fix @input@update:modelValue on <editor> in CommentField.vue

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace tiptap + tiptap-extensions with @tiptap/vue-3, StarterKit,
  Underline, and Link extensions
- Replace EditorMenuBar/EditorMenuBubble with plain div toolbar + BubbleMenu
- Update all commands to editor.chain().focus().toggle*().run() pattern
- Update active checks to editor.isActive('name') pattern
- Rename value prop → modelValue, emit update:modelValue
- Fix beforeDestroy → beforeUnmount
- Fix nested watch bug from original (editable watcher was never invoked)
- Fix SCSS import path: ./src/styles → @/styles (Vite alias)
- Remove library.add() call (icons already registered in main.js)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete dead code: src/store/ (Vuex, unused), src/services/store.js
  (replaced by Pinia), tests/unit/example.spec.js, tests/unit/.eslintrc.js
- Remove postcss/autoprefixer config from package.json (not installed,
  not needed — Vite handles vendor prefixing via esbuild)
- Add .vue to vite.config.js resolve.extensions to match Vue CLI behavior
  (allows extension-less imports of .vue files from router.js and elsewhere)
- Auto-fix .sync → v-model:propName in ComicForm, KeywordForm, PersonForm,
  RoleForm (deprecated v-bind sync modifier removed in Vue 3)
- Fix prettier formatting in Editor.vue, KeywordList.vue, NameField.vue
- Production build passes: 368 modules, no errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add "type": "module" to suppress Vite CJS Node API warning
- Switch Sass to modern-compiler API to silence legacy-js-api warnings
- Replace @import with @use in Editor.vue / menububble.scss; remove no-op styles.scss imports from 8 components
- Set dev server port to 8080 to match Keycloak's configured allowed origin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…option

createBootstrap() only wires up directives/controllers, not global b-*
component registration, so navbar/buttons/etc. silently failed to
resolve and rendered unstyled. Add unplugin-vue-components with
BootstrapVueNextResolver to auto-import them at compile time.

Also fix App.vue's $route watcher: immediate was a sibling key instead
of nested under the handler, which is invalid under Vue 3's stricter
watch validation and never actually applied immediate: true.
bootstrap-vue-next dropped the bootstrap-vue type prop, so
type="dark" was silently ignored, leaving default light-theme
nav-link text on the bg-dark navbar. Use data-bs-theme="dark",
the Bootstrap 5.3+ equivalent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bootstrap-vue-next's BTable calls items.map() with no null-guard,
unlike Vue 2 bootstrap-vue. Initializing list data as null (instead
of []) crashed BTable's setup on mount, blanking comics/persons/
publishers/keywords/roles/predicates pages. Default to [] instead.

Also fix Header.vue logout link: to="logout" (relative) didn't
resolve against the /logout route; needs the leading slash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…3qxx)

axios and jsdom/vitest both resolved form-data to the vulnerable 4.0.5;
bumping closes the Dependabot alert without any range changes needed.
bootstrap-vue-next dropped the v2 filter-function/filterIncludedFields/@filtered
API. Replace it in ComicList, KeywordList, PersonList, PredicateList, PublisherList,
and RolesList with a filteredX computed bound to :items; totalRows is now a computed
and a filter watcher resets pagination. Also fix trailing slash on /search endpoint
and bump tiptap, bootstrap, bootstrap-vue-next, dayjs, keycloak-js, and fontawesome
to latest patch versions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add col-auto to #button-col in all 5 detail form views so Bootstrap's
flexbox row layout puts the content column beside the button list instead
of below it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the b-row/b-col column layout inside the b-form-tags slot with a
single d-flex container so the dropdown button and tag badges are siblings
that flow left-to-right from the start, independent of any inherited
text-align from b-form-tags wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace :value with :model-value on all components using the Vue 2 prop
name (InputField, b-form-input) so disabled label fields display correctly
in Vue 3. In Relation.vue, switch disabled b-form-input to input-group-text
span and add flex-fill so the label, predicate, and target share row space
evenly. Add text-start and flex-fill to SearchableDropdown toggle button
for left-aligned text and proportional sizing inside input-group.

Affected: KeywordForm, PersonForm, PublisherForm (header label), Relation
(source/target label), PublisherField (location display), SearchableDropdown.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant