aboutsummaryrefslogtreecommitdiffstats
path: root/resources/src/vue
diff options
context:
space:
mode:
authorRoan Kattouw <roan.kattouw@gmail.com>2021-02-23 16:14:21 -0500
committerVolkerE <volker.e@wikimedia.org>2021-11-02 05:03:36 +0000
commitc52f650809eee8a494d0555b86e4f086b9584f8b (patch)
treeb08338b4b19d81eea5d392178939d1b1357e5823 /resources/src/vue
parent8eced80e24af65a12fce182bcb00a59e7fbd68b2 (diff)
downloadmediawikicore-c52f650809eee8a494d0555b86e4f086b9584f8b.tar.gz
mediawikicore-c52f650809eee8a494d0555b86e4f086b9584f8b.zip
Add Vue.createMwApp(), to help with Vue 2->3 migration
This will allow code that mounts components to be written in a way that will keep working across the Vue 2->3 migration: var RootComponent = require( './RootComponent.vue' ), store = require( './store.js' ); // if using Vuex Vue.createMwApp( RootComponent ) .use( store ) // if using Vuex .mount( '#foo' ); While we're still using Vue 2, createMwApp() will return something that pretends to be an app object, with support for .use() and .mount(). Once we move to Vue 3, createMwApp() will remain, as a wrapper around Vue.createApp() that adds in the i18n plugin and the error logger. Migrating to this API won't be required immediately, since the change upgrading Vue from v2 to v3-compat will include a compatibility wrapper for the old calling style. Bug: T251974 Change-Id: Ib3ef9b88547b43c566abb007cde08a27baf2b7a4
Diffstat (limited to 'resources/src/vue')
-rw-r--r--resources/src/vue/index.js65
1 files changed, 65 insertions, 0 deletions
diff --git a/resources/src/vue/index.js b/resources/src/vue/index.js
index 02f25dbeb70f..a0cae377ddce 100644
--- a/resources/src/vue/index.js
+++ b/resources/src/vue/index.js
@@ -4,5 +4,70 @@
Vue.use( require( './errorLogger.js' ) );
Vue.use( require( './i18n.js' ) );
+ /**
+ * @class Vue
+ */
+ /**
+ * Wrapper that imitates Vue.createApp(), to make the Vue 2 -> Vue 3 migration smoother.
+ *
+ * Vue.createApp() is introduced in Vue 3. This returns an object that provides part of the
+ * same API, so that we can swap out Vue 3 for Vue 2 without needing to change callers.
+ * After the Vue 3 migration, this function will stay as a wrapper around Vue.createApp()
+ * that adds the i18n plugin and the error handler, because those can't be added globally
+ * in Vue 3.
+ *
+ * To create and mount an app that doesn't use Vuex:
+ * var RootComponent = require( './RootComponent.vue' ),
+ * Vue.createMwApp( RootComponent )
+ * .mount( '#foo' ); // CSS selector of mount point, or DOM element
+ *
+ * To create and mount an app with Vuex:
+ * var RootComponent = require( './RootComponent.vue' ),
+ * store = require( './store.js' );
+ * Vue.createMwApp( RootCompoinent )
+ * .use( store )
+ * .mount( '#foo' );
+ *
+ * @param {Object} componentOptions Vue component options object
+ * @return {Object} Object that pretends to be a Vue 3 app object, supports .use() and .mount()
+ */
+ Vue.createMwApp = function ( componentOptions ) {
+ var App = Vue.extend( componentOptions ),
+ finalOptions = {};
+
+ // Wrap .use(), so we can redirect app.use( VuexStore )
+ App.use = function ( plugin ) {
+ if (
+ typeof plugin !== 'function' && typeof plugin.install !== 'function' &&
+ // eslint-disable-next-line no-underscore-dangle
+ plugin._actions && plugin._mutations
+ ) {
+ // This looks like a Vuex store, store it for later use.
+ finalOptions.store = plugin;
+ return this;
+ }
+ Vue.use.apply( Vue, arguments );
+ return App;
+ };
+
+ App.mount = function ( elementOrSelector, hydrating ) {
+ // Mimic the Vue 3 behavior of appending to the element rather than replacing it
+ // Add a div to the element, and pass that to .$mount() so that it gets replaced.
+ var wrapperElement = document.createElement( 'div' ),
+ parentElement = typeof elementOrSelector === 'string' ?
+ document.querySelector( elementOrSelector ) : elementOrSelector;
+ if ( !parentElement || !parentElement.appendChild ) {
+ throw new Error( 'Cannot find element: ' + elementOrSelector );
+ }
+ // Remove any existing children from parentElement.
+ while ( parentElement.firstChild ) {
+ parentElement.removeChild( parentElement.firstChild );
+ }
+ parentElement.appendChild( wrapperElement );
+ new App( finalOptions ).$mount( wrapperElement, hydrating );
+ };
+ return App;
+ };
+
module.exports = Vue;
}() );