From 9f59e857eec295ba82023754817ee76e42295b1f Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 16 Dec 2020 17:10:01 +0100 Subject: [PATCH 1/4] fix(ssr): forward slots of the AisInstantSearchSsr component The clone created in findResultsState also manually needs to forward slots, or the data won't be available. --- src/util/createServerRootMixin.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index 883817007..4aff065d3 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -88,6 +88,9 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { propsData: componentInstance.$options.propsData, }); + // https://stackoverflow.com/a/48195006/3185307 + app.$slots = componentInstance.$slots; + app.$options.serverPrefetch = []; app.instantsearch.helper = helper; From 915757be28a2a73da534d64d6837d692a355d9ef Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Wed, 16 Dec 2020 18:04:58 +0100 Subject: [PATCH 2/4] Update src/util/createServerRootMixin.js --- src/util/createServerRootMixin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index 4aff065d3..a7845259e 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -90,6 +90,7 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { // https://stackoverflow.com/a/48195006/3185307 app.$slots = componentInstance.$slots; + app.$scopedSlots = componentInstance.$scopedSlots; app.$options.serverPrefetch = []; From 3de617e0626242c285b8f7c533579cb0e59c252f Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Thu, 17 Dec 2020 14:18:56 +0100 Subject: [PATCH 3/4] chore: also forward root --- src/util/createServerRootMixin.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index a7845259e..b06d2985c 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -91,6 +91,7 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { // https://stackoverflow.com/a/48195006/3185307 app.$slots = componentInstance.$slots; app.$scopedSlots = componentInstance.$scopedSlots; + app.$root = componentInstance.$root; app.$options.serverPrefetch = []; @@ -164,6 +165,12 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { const results = search.__initialSearchResults[parent.getIndexId()]; + // this happens when a different InstantSearch gets rendered initially, + // after the hydrate finished. There's thus no initial results available. + if (!results) { + return; + } + const state = results._state; // helper gets created in init, but that means it doesn't get the injected From 08b756e111142f16fca1f5df30c7f7f201fded9c Mon Sep 17 00:00:00 2001 From: Haroen Viaene Date: Thu, 17 Dec 2020 16:21:12 +0100 Subject: [PATCH 4/4] scoped slots doesn't work, add tests --- .../__tests__/createServerRootMixin.test.js | 157 ++++++++++++++++++ src/util/createServerRootMixin.js | 2 +- 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/src/util/__tests__/createServerRootMixin.test.js b/src/util/__tests__/createServerRootMixin.test.js index 200b5bffc..afec17dc7 100644 --- a/src/util/__tests__/createServerRootMixin.test.js +++ b/src/util/__tests__/createServerRootMixin.test.js @@ -362,6 +362,163 @@ Array [ await renderToString(wrapper); }); + + it('forwards slots', async done => { + const searchClient = createFakeClient(); + + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + return h(InstantSearchSsr, {}, this.$slots.default); + }, + serverPrefetch() { + return ( + this.instantsearch + .findResultsState(this) + .then(res => { + expect( + this.instantsearch.mainIndex.getWidgets().map(w => w.$$type) + ).toEqual(['ais.configure']); + + expect(res.hello._state.hitsPerPage).toBe(100); + }) + // jest throws an error we need to catch, since stuck in the flow + .catch(e => { + done.fail(e); + }) + ); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App, [ + h('template', { slot: 'default' }, [ + h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }), + ]), + ]); + }, + }); + + await renderToString(wrapper); + done(); + }); + + // TODO: forwarding of scoped slots doesn't yet work. + it.skip('forwards scoped slots', async done => { + const searchClient = createFakeClient(); + + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + return h(InstantSearchSsr, {}, [ + this.$scopedSlots.default({ test: true }), + ]); + }, + serverPrefetch() { + return ( + this.instantsearch + .findResultsState(this) + .then(res => { + expect( + this.instantsearch.mainIndex.getWidgets().map(w => w.$$type) + ).toEqual(['ais.configure']); + + expect(res.hello._state.hitsPerPage).toBe(100); + }) + // jest throws an error we need to catch, since stuck in the flow + .catch(e => { + done.fail(e); + }) + ); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App, { + scopedSlots: { + default({ test }) { + if (test) { + return h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }); + } + return null; + }, + }, + }); + }, + }); + + await renderToString(wrapper); + done(); + }); + + it('forwards root', async () => { + const searchClient = createFakeClient(); + + // there are two renders of App, each with an assertion + expect.assertions(2); + + const App = Vue.component('App', { + mixins: [ + forceIsServerMixin, + createServerRootMixin({ + searchClient, + indexName: 'hello', + }), + ], + render(h) { + expect(this.$root).toBe(wrapper); + + return h(InstantSearchSsr, {}, [ + h(Configure, { + attrs: { + hitsPerPage: 100, + }, + }), + h(SearchBox), + ]); + }, + serverPrefetch() { + return this.instantsearch.findResultsState(this); + }, + }); + + const wrapper = new Vue({ + mixins: [forceIsServerMixin], + render(h) { + return h(App); + }, + }); + + await renderToString(wrapper); + }); }); describe('hydrate', () => { diff --git a/src/util/createServerRootMixin.js b/src/util/createServerRootMixin.js index b06d2985c..527048c49 100644 --- a/src/util/createServerRootMixin.js +++ b/src/util/createServerRootMixin.js @@ -90,7 +90,7 @@ function augmentInstantSearch(instantSearchOptions, searchClient, indexName) { // https://stackoverflow.com/a/48195006/3185307 app.$slots = componentInstance.$slots; - app.$scopedSlots = componentInstance.$scopedSlots; + app.$root = componentInstance.$root; app.$options.serverPrefetch = [];