From 08b71244c3bf7cf2cbd8183a671d1a589af75798 Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Mon, 31 Jan 2022 14:08:24 +0100 Subject: [PATCH] fix(ssr): extend component correctly if at root (vue2) (#1104) * fix(ssr): extend component correctly if at root (vue2) fixes #1054 Essentially the problem is that $vnode is usually available, but not when the this is a root Vue instance. In that case we are in the "Vue.component" case, which before now always was wrong (it takes two arguments, not one) * not only * Update src/util/__tests__/createServerRootMixin.test.js Co-authored-by: Sarah Dayan <5370675+sarahdayan@users.noreply.github.com> Co-authored-by: Sarah Dayan <5370675+sarahdayan@users.noreply.github.com> --- .../__tests__/createServerRootMixin.test.js | 76 +++++++++++++++++++ src/util/createServerRootMixin.js | 5 +- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/util/__tests__/createServerRootMixin.test.js b/src/util/__tests__/createServerRootMixin.test.js index 56349d33..917c22b3 100644 --- a/src/util/__tests__/createServerRootMixin.test.js +++ b/src/util/__tests__/createServerRootMixin.test.js @@ -719,6 +719,82 @@ Array [ }, }, ] +`); + }); + + it('works when component is at root (and therefore has no $vnode)', async () => { + const searchClient = createFakeClient(); + let mainIndex; + + const app = { + render: renderCompat(h => + /** + * This code triggers this warning in Vue 3: + * > Non-function value encountered for default slot. Prefer function slots for better performance. + * + * To fix it, replace the third argument + * > [h(...), h(...)] + * with + * > { default: () => [h(...), h(...)] } + * + * but it's not important (and not compatible in vue2), we're leaving it as-is. + */ + h(InstantSearchSsr, {}, [ + h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }), + h(SearchBox), + ]) + ), + }; + + const wrapper = createSSRApp({ + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + serverPrefetch() { + return this.instantsearch.findResultsState({ + component: this, + renderToString, + }); + }, + created() { + mainIndex = this.instantsearch.mainIndex; + }, + render: renderCompat(h => h(app)), + }); + + await renderToString(wrapper); + + expect(mainIndex.getWidgetState()).toMatchInlineSnapshot(` +Object { + "hello": Object { + "configure": Object { + "hitsPerPage": 100, + }, + }, +} +`); + + expect(searchClient.search).toHaveBeenCalledTimes(1); + expect(searchClient.search.mock.calls[0][0]).toMatchInlineSnapshot(` +Array [ + Object { + "indexName": "hello", + "params": Object { + "facets": Array [], + "hitsPerPage": 100, + "query": "", + "tagFilters": "", + }, + }, +] `); }); } diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index 970cc2fa..fbb16c91 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -56,7 +56,10 @@ function defaultCloneComponent(componentInstance, { mixins = [] } = {}) { const Extended = componentInstance.$vnode ? componentInstance.$vnode.componentOptions.Ctor.extend(options) - : Vue2.component(Object.assign({}, componentInstance.$options, options)); + : Vue2.component( + options.name, + Object.assign({}, componentInstance.$options, options) + ); app = new Extended({ propsData: componentInstance.$options.propsData,