Page MenuHomePhabricator

Make Wikibase work with the Vue 3 migration build
Closed, ResolvedPublic

Description

One of the first steps in our migration to Vue 3 will be to upgrade the version of Vue in MediaWiki from Vue 2.6 to the migration build of Vue 3. This migration build is mostly compatible with Vue 2, but it doesn't provide compatibility for certain edge cases or for features that are undocumented or not officially supported. The Vue code in Wikibase (including its submodules, like termbox, and the WikibaseLexeme extension which doesn't appear to have its own Phabricator project) needs to be tested against the Vue 3 migration build and updated to fix any errors.

See the "test plan" section on T289019: Test Vue 3 migration build with extensions/skins using Vue for more detail. The outcome of this task should be that Wikibase runs without errors both under Vue 2.6 and under the migration build of Vue 3. These changes should ideally be minor; actually migrating to Vue 3 should be done later, since it's more work and will lead to incompatibility with Vue 2.

Event Timeline

I’m aware of four Wikibase codebases that use Vue:

  • termbox
  • data bridge
  • lexemes
  • tainted references

I’m aware of four Wikibase codebases that use Vue:

  • termbox
  • data bridge
  • lexemes
  • tainted references

Yes, those are the only four that I'm aware of as well. The other vuejs projects that we have do not integrated directly with MediaWiki/ResourceLoader (e.g. QueryBuilder, MismatchFinder, ...)

Change 737747 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/WikibaseLexeme@master] Use createMwApp() instead of new Vue()

https://gerrit.wikimedia.org/r/737747

I started working on this in WikibaseLexeme, but someone else could probably start with one of the other components in parallel, if you want.

For WikibaseLexeme, as far as I can tell the old code works with Vue 2 (obviously), the old code works with the Vue 3 migration build (i.e. git review -d 666434 in MW core), the new code (see change above) works with Vue 2 (though it requires a small MediaWiki core change), and the new code works with Vue 3 too.

@Michael and I looked at Tainted References, and it’s not really clear how to migrate it. Tainted References (and Data Bridge) uses vue-class-component, which doesn’t seem to have a version compatible with Vue 3 yet, and we don’t know if a Vue 3 version of vue-class-component will use createApp() (which would make a migration to createMwApp() relatively straightforward) or not.

More worryingly, the current Tainted References code isn’t compatible with Vue 3 migration build (i.e. git review -d 666434 in MW core) either. I uploaded a change to fix one of the resulting errors, but then there are further errors when (apparently) Tainted References’ custom plugins (Message, presumably also Track) aren’t getting registered properly. This might block the migration to Vue 3 :/

Change 739273 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Migrate from vue-class-component to options API

https://gerrit.wikimedia.org/r/739273

Change 737747 merged by jenkins-bot:

[mediawiki/extensions/WikibaseLexeme@master] Use createMwApp() instead of new Vue()

https://gerrit.wikimedia.org/r/737747

Change 739327 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Change App id from data to prop

https://gerrit.wikimedia.org/r/739327

Change 739328 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Use Vue.createMwApp()

https://gerrit.wikimedia.org/r/739328

Change 739536 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Include Vue in build and move plugin registration

https://gerrit.wikimedia.org/r/739536

Change 739587 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: WIP: Migrate to Vue 3 and Vuex 4

https://gerrit.wikimedia.org/r/739587

To summarize all the Gerrit stuff up there, our current general plan for Tainted Refs is:

  • Migrate from vue-class-component to the options API. Can be merged at any time.
  • Temporarily include Vue 2 in the build, making it independent of the version shipped with MediaWiki core. I don’t think there’s a way around this – since we compile templates in our build step, we can’t produce a bundle that’s compatible with Vue 2 and 3 at runtime. Should only be merged right before the next step.
  • MediaWiki core migrates to Vue 3. (This might need a Depends-On for the previous change, to make CI pass.)
  • Migrate to Vue 3 (in Tainted Refs).
  • Use the MediaWiki-provided Vue again.

The Vue 2/3 switch in Tainted Refs should happen as close as possible to the switch in MediaWiki core, so that we can hopefully avoid including the extra-large Tainted Refs bundle (with its own copy of Vue) in any train version.

Data Bridge and Termbox will probably require the same procedure. (WikibaseLexeme is easier, since it’s written in a simpler style: no vue-class-component, no build step, not even SFCs.)

since we compile templates in our build step, we can’t produce a bundle that’s compatible with Vue 2 and 3 at runtime

I thought this would be a problem with WVUI, but from my testing, the Vue 2-compiled WVUI bundle works just fine under the Vue 3 migration build. The compatibility that the migration build provides for the render function API is good enough that compiled templates work. I wouldn't trust this blindly without testing, but it has worked for us for the (relatively simple) Vue 2 code in WVUI.

If you're using the composition API plugin for Vue 2 and bundling it with your code, then you will run into strange bugs. I had that problem with WVUI, and I plan to fix it by externalizing the composition API plugin instead of bundling it, see T284707 and T295106#7497606.

I thought this would be a problem with WVUI, but from my testing, the Vue 2-compiled WVUI bundle works just fine under the Vue 3 migration build. The compatibility that the migration build provides for the render function API is good enough that compiled templates work. I wouldn't trust this blindly without testing, but it has worked for us for the (relatively simple) Vue 2 code in WVUI.

Hm, then I’ll go into a bit more detail. My first attempt had been to use Vue 3 at build time, but that didn’t work with a Vue 2 runtime (incompatible templates). I assumed that Vue 2 compiled templates wouldn’t work against a Vue 3 runtime either, but I didn’t actually reach the point where I got an error for that.

The latest problem I had was that we export components as export default Vue.extend( { /* options */ } ) to make TypeScript type inference work properly. (This fulfills a similar function to Vue.defineComponent() in Vue 3.) However, createMwApp() already calls Vue.extend() on the options it receives, and Vue.extend() isn’t idempotent (unlike Vue.defineComponent()), so we need to pass the original options into createMwApp(), not the extended Vue constructor. In Vue 2, this worked by passing in App.extendOptions (the original options, which Vue.extend() attaches to the returned constructor), but in the compatibility build’s version of Vue.extend(), that doesn’t happen, and when I tried to add it (wrap the compatibility build’s Vue.extend() with a function that attaches the argument as extendOptions to the original return value), the template was missing (I don’t know exactly how the SFC build attaches <template> and <style> to the options, but they weren’t there).

It’s possible that this problem is solvable – this is just the point where I realized that running Vue 2 compiled templates against Vue 3 would probably work no better than the earlier attempt of Vue 3 compiled templates crashing on Vue 2, so I abandoned that line of work and instead tried including Vue 2 in the build, which works fairly well. Maybe we can come back to the Vue.extend() problems, but the solution with bundled Vue at least seems like a viable way forward.

That confuses me, because WVUI uses export default Vue.extend( { ... } ) too (example), and using the Vue 2 build of WVUI with the Vue 3 compat runtime works fine. Maybe the difference is that we never pass a WVUI component directly to Vue.createMwApp(), we happen to always wrap them in another component (because WVUI only contains basic components that don't make much sense on their own). It sounds like you are importing fully functional components that are mounted directly. A workaround might be as simple as:

var TaintedRefs = require( './TaintedRefs.js' ); // returns a Vue 2-compiled component
var wrappedTaintedRefs = {
    render: function ( h ) {
        return h( TaintedRefs, { props: { /* whatever you need to pass in */ } } );
    }
};
Vue.createMwApp( wrappedTaintedRefs ).mount( 'selector' );

That said, bundling Vue 2 temporarily is a good workaround too, we can always fall back on that if we can't find a good solution to the Vue.extend() problem.

Hm, the render workaround seems to work well in Vue 2 (and it’s nicer than extendOptions, so thanks!), but I haven’t managed to get it working in Vue 3 yet. Rendering App produces an error about $store being undefined; rendering $.extend( { store }, App ) avoids that error, but then apparently nothing happens, the component doesn’t seem to get rendered at all (a console.log in a required computed prop is never called). I’ve pushed that change here if you want to take a look (though you’d need a local Wikibase install to test it at runtime).

Got it, the store needs to be on the outer app (obviously, in hindsight ^^):

Vue.createMwApp( {
	store,
	render( h ) {
		return h( App, { props: { id } } );
	},
} )
	.mount( appElement );

I think this solves all the remaining Wikibase Tainted Refs issues and we don’t need to bundle Vue after all \o/ I’ll try it out a bit more and upload changes to Gerrit etc.

Change 739273 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Migrate from vue-class-component to options API

https://gerrit.wikimedia.org/r/739273

Change 739327 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Change App id from data to prop

https://gerrit.wikimedia.org/r/739327

Change 739328 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Use Vue.createMwApp()

https://gerrit.wikimedia.org/r/739328

Change 740201 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Move plugin registration to app

https://gerrit.wikimedia.org/r/740201

Change 740230 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Remove vuex-class

https://gerrit.wikimedia.org/r/740230

Change 740231 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] TR: Migrate to Vue 3 and Vuex 4

https://gerrit.wikimedia.org/r/740231

Change 740230 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Remove vuex-class

https://gerrit.wikimedia.org/r/740230

Change 740201 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Move plugin registration to app

https://gerrit.wikimedia.org/r/740201

Change 739536 abandoned by Lucas Werkmeister (WMDE):

[mediawiki/extensions/Wikibase@master] TR: Include Vue in build and move plugin registration

Reason:

we made it work with MediaWiki’s Vue 3 after all, see If818f32ae0

https://gerrit.wikimedia.org/r/739536

Change 739587 abandoned by Lucas Werkmeister (WMDE):

[mediawiki/extensions/Wikibase@master] TR: WIP: Migrate to Vue 3 and Vuex 4

Reason:

replaced by I229f5b5c0b (which also has the proper commit message)

https://gerrit.wikimedia.org/r/739587

Change 740654 had a related patch set uploaded (by Michael Große; author: Michael Große):

[mediawiki/extensions/Wikibase@master] bridge: Use MwCreateApp

https://gerrit.wikimedia.org/r/740654

Change 742165 had a related patch set uploaded (by Michael Große; author: Michael Große):

[mediawiki/extensions/Wikibase@master] bridge: Use emitter as prop instead of using repeater

https://gerrit.wikimedia.org/r/742165

Change 742165 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] bridge: Use emitter as prop instead of using repeater

https://gerrit.wikimedia.org/r/742165

Change 740654 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] bridge: Use MwCreateApp

https://gerrit.wikimedia.org/r/740654

Note that there is still one new Vue() call remaining in Wikibase, in ErrorPermission.vue in data bridge. That's not an immediate blocker for the Vue 3 migration (we have compatibility code that should keep it working), but I wanted to point it out as something that will eventually need to be migrated.

Note that there is still one new Vue() call remaining in Wikibase, in ErrorPermission.vue in data bridge. That's not an immediate blocker for the Vue 3 migration (we have compatibility code that should keep it working), but I wanted to point it out as something that will eventually need to be migrated.

Yeah, that is part of the patch that switches bridge itself to the Vue3 compat build: https://gerrit.wikimedia.org/r/c/mediawiki/extensions/Wikibase/+/742783/12/client/data-bridge/src/presentation/components/ErrorPermission.vue\

But maybe it is something that could be extracted into its own change πŸ€”

Change 740231 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] TR: Migrate to Vue 3 and Vuex 4

https://gerrit.wikimedia.org/r/740231

I think we can close this task; MediaWiki core has been shipping the migration build for a while now, clearly it’s working well enough in practice. I’ve created T304534: [EPIC] Make Wikibase work with Vue 3 (non-migration build) for the remaining migration to pure Vue 3 (which was partially done here already).