Migrate OrchardCore.Media module from Vue 2 to Vue 3
Description
Migrates OrchardCore.Media from Vue 2.6.14 to Vue 3.5.13 to align with OrchardCore.Resources and eliminate deprecated Vue 2 dependencies.
Core Migration Changes
-
Event bus: Replaced Vue 2 instance-based event bus with custom
EventBusclass implementing$on,$emit,$offmethods -
App initialization: Converted
new Vue({ el, data })→Vue.createApp({ data() }).mount(el)pattern across 3 app instances -
Component registration: Changed global
Vue.component()to app-scopedapp.component()for 10 components -
Data function: Updated
data: {}object syntax todata() { return {}; }function syntax -
Resource dependencies: Updated ResourceManifestOptionsConfiguration to use
vuejs:3instead ofvuejs:2and removedvue-draggable:2dependency (Media module uses Sortable.js directly)
Before/After
// Vue 2
var bus = new Vue();
mediaApp = new Vue({
el: '#mediaApp',
data: { items: [] }
});
Vue.component('folder', { ... });
// Vue 3
class EventBus { ... }
var bus = new EventBus();
const app = Vue.createApp({
data() { return { items: [] }; }
});
app.component('folder', folderComponent);
mediaApp = app.mount('#mediaApp');
Files Modified
-
package.json: Vue 2.6.14 → 3.5.13 -
ResourceManifestOptionsConfiguration.cs: Updated script dependencies to vuejs:3 - 13 JavaScript component files in
Assets/js/app/ - Built assets:
media.js,media.min.js -
yarn.lock: Dependency graph update
No Razor view changes required - Vue initialization handled entirely in JavaScript.
Original prompt
Overview
Migrate the OrchardCore.Media module's VueJs components from Vue 2 to Vue 3. The module is located at
src/OrchardCore.Modules/OrchardCore.Media/.Current State
- Assets folder:
src/OrchardCore.Modules/OrchardCore.Media/Assets/
Assets/js/app/- Contains Vue componentsAssets/package.json- Currently specifies"vue": "2.6.14"- Views folder:
src/OrchardCore.Modules/OrchardCore.Media/Views/
- Contains Razor views that initialize Vue applications
Migration Requirements
1. Update Dependencies
Update
src/OrchardCore.Modules/OrchardCore.Media/Assets/package.json:
- Change Vue from version
2.6.14to Vue 3 (use the same Vue 3 version already available in other parts of this repository)2. Migrate Vue Components
Update all Vue components in
Assets/js/app/following Vue 3 migration patterns:
Vue 2 Pattern Vue 3 Pattern new Vue({...})Vue.createApp({...}).mount('#el')Vue.component()(global)app.component()(per-app)this.$set()/this.$delete()Direct assignment (Proxy-based reactivity) filtersComputed properties or methods $on,$off,$once(event bus)External library or provide/inject v-modelwith.syncv-modelwith argumentsdataas objectdatamust be a function$listenersMerged into $attrs$scopedSlotsUnified into $slotsbeforeDestroylifecyclebeforeUnmountdestroyedlifecycleunmounted3. Update Razor Views
Update the following views in
src/OrchardCore.Modules/OrchardCore.Media/Views/that initialize Vue applications:
MediaField.Edit.cshtmlMediaField-Attached.Edit.cshtmlMediaField-Gallery.Edit.cshtmlMediaFieldSettings.Edit.cshtml- Any views in
Views/Admin/andViews/Shared/that use VueVue initialization pattern change:
Before (Vue 2):
new Vue({ el: '#media-app', data: { ... }, methods: { ... } });After (Vue 3):
const app = Vue.createApp({ data() { return { ... }; }, methods: { ... } }); app.mount('#media-app');4. Build Assets
After making changes, build the assets using the Orchard Core Assets Manager:
- Documentation: https://docs.orchardcore.net/en/latest/guides/assets-manager/
- Run
yarn build -grat the repository root to build all changed assets- The generated/compiled assets should be included in the PR
5. Testing (Optional)
If possible, test using AutoSetup feature:
- Documentation: https://docs.orchardcore.net/en/latest/reference/modules/AutoSetup/
- Navigate to the admin area to find and test the media editor
- If testing is not possible, the PR will be tested manually by reviewers
Files to Modify
src/OrchardCore.Modules/OrchardCore.Media/Assets/package.json- All
.jsfiles insrc/OrchardCore.Modules/OrchardCore.Media/Assets/js/app/- All
.cshtmlfiles insrc/OrchardCore.Modules/OrchardCore.Media/Views/that contain Vue initialization code- Generated/compiled asset files (after running the build)
Acceptance Criteria
- [ ] Vue dependency updated to Vue 3 in package.json
- [ ] All Vue components migrated to Vue 3 syntax
- [ ] All Razor views updated to use Vue.createApp() pattern
- [ ] Assets built successfully with no errors
- [ ] No Vue 2 specific patterns remain in the codebase
This pull request was created as a result of the following prompt from Copilot chat.
Overview
Migrate the OrchardCore.Media module's VueJs components from Vue 2 to Vue 3. The module is located at
src/OrchardCore.Modules/OrchardCore.Media/.Current State
- Assets folder:
src/OrchardCore.Modules/OrchardCore.Media/Assets/
Assets/js/app/- Contains Vue componentsAssets/package.json- Currently specifies"vue": "2.6.14"- Views folder:
src/OrchardCore.Modules/OrchardCore.Media/Views/
- Contains Razor views that initialize Vue applications
Migration Requirements
1. Update Dependencies
Update
src/OrchardCore.Modules/OrchardCore.Media/Assets/package.json:
- Change Vue from version
2.6.14to Vue 3 (use the same Vue 3 version already available in other parts of this repository)2. Migrate Vue Components
Update all Vue components in
Assets/js/app/following Vue 3 migration patterns:
Vue 2 Pattern Vue 3 Pattern new Vue({...})Vue.createApp({...}).mount('#el')Vue.component()(global)app.component()(per-app)this.$set()/this.$delete()Direct assignment (Proxy-based reactivity) filtersComputed properties or methods $on,$off,$once(event bus)External library or provide/inject v-modelwith.syncv-modelwith argumentsdataas objectdatamust be a function$listenersMerged into $attrs$scopedSlotsUnified into $slotsbeforeDestroylifecyclebeforeUnmountdestroyedlifecycleunmounted3. Update Razor Views
Update the following views in
src/OrchardCore.Modules/OrchardCore.Media/Views/that initialize Vue applications:
MediaField.Edit.cshtmlMediaField-Attached.Edit.cshtmlMediaField-Gallery.Edit.cshtmlMediaFieldSettings.Edit.cshtml- Any views in
Views/Admin/andViews/Shared/that use VueVue initialization pattern change:
Before (Vue 2):
new Vue({ el: '#media-app', data: { ... }, methods: { ... } });After (Vue 3):
const app = Vue.createApp({ data() { return { ... }; }, methods: { ... } }); app.mount('#media-app');4. Build Assets
After making changes, build the assets using the Orchard Core Assets Manager:
- Documentation: https://docs.orchardcore.net/en/latest/guides/assets-manager/
- Run
yarn build -grat the repository root to build all changed assets- The generated/compiled assets should be included in the PR
5. Testing (Optional)
If possible, test using AutoSetup feature:
- Documentation: https://docs.orchardcore.net/en/latest/reference/modules/AutoSetup/
- Navigate to the admin area to find and test the media editor
- If testing is not possible, the PR will be tested manually by reviewers
Files to Modify
src/OrchardCore.Modules/OrchardCore.Media/Assets/package.json- All
.jsfiles insrc/OrchardCore.Modules/OrchardCore.Media/Assets/js/app/- All
.cshtmlfiles insrc/OrchardCore.Modules/OrchardCore.Media/Views/that contain Vue initialization code- Generated/compiled asset files (after running the build)
Acceptance Criteria
- [ ] Vue dependency updated to Vue 3 in package.json
- [ ] All Vue components migrated to Vue 3 syntax
- [ ] All Razor views updated to use Vue.createApp() pattern
- [ ] Assets built successfully with no errors
- [ ] No Vue 2 specific patterns remain in the codebase
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.
@copilot In ResourceManagementOptionsConfiguration the vuejs dependency needs to be updated to vuejs:3 or the correct asset won't be loaded in the views.
Then can you also replace vue-draggable:2 that depends on vuejs 2 and is breaking the view? Find a similar component and update the components and views accordingly.
@copilot In ResourceManagementOptionsConfiguration the vuejs dependency needs to be updated to vuejs:3 or the correct asset won't be loaded in the views.
Then can you also replace vue-draggable:2 tha...
Updated in commit 7230c35:
- Changed vuejs:2 to vuejs:3 in ResourceManifestOptionsConfiguration
- Removed vue-draggable:2 dependency (the Media module uses Sortable.js directly, not vuedraggable)
This is a good idea. Just for the sake of moving to Vue 3. Thanks Sebastien on Copilot! 🐰
It's almost working. PAging issues and maybe other things, but it's rendering
All working and verified now.
Next step, and not on this PR would be to build it with Vite.
If we use ESLint to analyse this code it will highlight bad usage of var and this.
var = let or const this = use =>
And then this leads into making this easier to refactor everything to Typescript at the same time.
@Skrypt done
It cleaned half of them. I wouldn't try to push it too far either. If this works at least with Vue 3 it is a good start. I would iterate other PR's to clean this and make it proper ES6 code. This is why I said maybe not for this PR.
Or we can always still revert to a specific commit if you prefer trying to iterate more. All of the "this" needs to be removed meaning that when you see "function ()" it should normally be replaced with "() =>". Though, maybe it won't work everywhere since this is not using Vue 3 composition API.
Example of Composition API:
<script setup>
import { ref, onMounted } from 'vue';
const myMessage = ref('A random message')
const showMessage = () => {
alert(myMessage.value);
};
// Method 1:
onMounted(showMessage);
// Method 2:
onMounted(() => showMessage());
// Method 3:
onMounted(() => {
showMessage()
}
</script>
Now, what you did is a direct migration to Vue 3 but it is not using the new Vue 3 way of doing things. So, it may be harder to get everything using proper ES6 syntax.
I can see that it also created an EventBus but normally in Vue 3 they recommend using Mitt for that matter. Again, probably not for this PR. I think we should migrate everything to Typescript before that. It is easier to Unit Test it afterward. But, again, back then, it took me a while to refactor since everything is not strongly typed in this app. There's a lot of loose ends and duplication of data here and there instead of having it centralized as proper strongly typed types.
It is really hard to follow where the data is going and in which format. In some place it is adding fields to arrays just for adding extra functionality. Also, the JQuery Upload dependency is a pain to work with. This is why I migrated that part to use Uppy since you can simply (at)import it and it is all written in Typescript already.
For the current PR if everything works I would simply merge it as is. The goal is to move it to Vue 3. But at the same time it is kinda not. 😅 Always depends on the time you want to invest on this @sebastienros
I was able to convert everything to .vue and ts like you did in your branch, but it requires other build pipeline changes which I want to do based on the other PR that migrates to the new pipeline. So I will revert the last commit, merge these PRs, and then create new ones to finish the Vue3 migration to the best practice.
It will become a good start to iterate on. Let's hope changing the build pipeline will work. I'm guessing that it may be difficult with JQuery Upload. But if that's an issue we can look at the Uppy component I did in my PR.