search: Prepare for Vue 3 migration

Port the initialization code for the Vue search to use Vue.createMwApp()
instead of new Vue( ... ). The former mimicks Vue 3's API for mounting
components.

Without this change, this code breaks in Vue 3 (even in compatibility
mode) because the compat support for new Vue(...) is imperfect. By the
time renderFn is called, the searchForm container has already been
emptied by Vue's internal mounting code.

Instead, inspect searchForm and generate the prop list before mounting,
then pass the props to createMwApp() and mount the component.

Bug: T294476
Depends-On: I1fcdcf7bf87f5af2deb9763a231f2c360ea45b23
Change-Id: I5b6e66051d97e75f8f03b8258894daba22525797
This commit is contained in:
Roan Kattouw 2021-11-05 15:53:34 -07:00
parent 04ff34bd0c
commit 5dee570cb2
1 changed files with 12 additions and 28 deletions

View File

@ -1,17 +1,15 @@
/** @module search */
var
Vue = require( 'vue' ).default || require( 'vue' ),
App = require( './App.vue' ),
config = require( './config.json' );
/**
* @param {Function} createElement
* @param {Element} searchForm
* @return {Vue.VNode}
* @throws {Error} if the searchForm does not
* contain input[name=title] and input[name="search"] elements.
* @return {void}
*/
function renderFn( createElement, searchForm ) {
function initApp( searchForm ) {
var
titleInput = /** @type {HTMLInputElement|null} */ (
searchForm.querySelector( 'input[name=title]' )
@ -23,8 +21,9 @@ function renderFn( createElement, searchForm ) {
throw new Error( 'Attempted to create Vue search element from an incompatible element.' );
}
return createElement( App, {
props: $.extend( {
// @ts-ignore
Vue.createMwApp(
App, $.extend( {
id: searchForm.id,
autofocusInput: search === document.activeElement,
action: searchForm.getAttribute( 'action' ),
@ -33,27 +32,10 @@ function renderFn( createElement, searchForm ) {
searchTitle: search.getAttribute( 'title' ),
searchPlaceholder: search.getAttribute( 'placeholder' ),
searchQuery: search.value
},
// Pass additional config from server.
config
)
} );
}
/**
* @param {NodeList} searchForms
* @return {void}
*/
function initApp( searchForms ) {
searchForms.forEach( function ( searchForm ) {
// eslint-disable-next-line no-new
new Vue( {
el: /** @type {Element} */ ( searchForm ),
render: function ( createElement ) {
return renderFn( createElement, /** @type {Element} */ ( searchForm ) );
}
} );
} );
}, config )
)
.mount( searchForm );
}
/**
* @param {Document} document
@ -63,6 +45,8 @@ function main( document ) {
var
searchForms = document.querySelectorAll( '.vector-search-box-form' );
initApp( searchForms );
searchForms.forEach( function ( searchForm ) {
initApp( searchForm );
} );
}
main( document );