Closed kreejzak closed 1 year ago
Hey,
Thanks for rising this question. Vue Instantsearch does not work with SSR by default. In order to make it a mixin (or something similar for Vue 3) would be needed.
The official docs are using Nuxt 2 as the module is maintained by me and help of contributors, not by Algolia itself. Thats is why the examples there are not up to date but I already contacted Algolia team to add my docs there.
For now, I would recommend you to use useFacetedSearch or regular useAsyncAlgoliaSearch to get the data in SSR while we can think about supporting SSR with Vue Instantsearch in future releases :)
For that, you can use https://algolia.nuxtjs.org/getting-started/usage#useasyncalgoliasearch and pass as a third property of the param object the requestOptions filters https://www.algolia.com/doc/api-reference/api-methods/search/#method-param-requestoptions
Thank you for pointing me in the right direction! 🙏
Glad that I could help!
I will reopen the issue so that I could make some research about implementing the mixin to make Vue Instantsearch work with SSR :)
After all, it should work for SSR too so it is a valid feature request.
Hey @haroenv
Long time no see 😃
Have you maybe found a way to implement instantsearch for Vue 3 with SSR? 🙂
I tried this recently, but didn't manage to get reference to the component's render as you can do in non-setup style scripts. My attempt is here: https://github.com/algolia/doc-code-samples/pull/430
Thanks @Haroenv I will take a look at it in a few days
Havent managed to make it work either unfortunately. I think this can be an opportunity for some community contribution to this module as it is not very requested feature for all users but rather a nice to have
Hello there 👋
First, thanks a lot for your module and for sharing code samples. It was useful to look at the code, even though I'm not using Algolia. For the context, I'm using Meilisearch, which is an open source alternative. Meilisearch also uses InstantSearch components to implement the front-end.
I haven't yet come to a solution, but I've got a partially working sample. It might or might not be useful but I figured I would share it as your contributions helped me a lot in my work, so I hope I can return the favor.
Basically, my implementation works for server-side rendering the results, but not the other components that depends on the state (ie. filters, etc.) At least, that's my understanding of the behavior. Feel free to let me know if I'm wrong.
I made a local Nuxt module in one of the projects I'm working on, you can take a look here: https://github.com/meilisearch/ecommerce-demo/blob/main/components/organisms/MeiliSearchProvider.vue
EDIT: The link is now public as intended
Have a good day,
Hey @Strift
Thank you for this message! I am glad that you liked the module :)
Also thanks for the research on how to implement this using SSR.
I am affraid that I do not have access to this project.
Would you be interested in contributing to Algolia module and adding such provider for it to make VueInstantsearch work with SSR? :)
I tried this recently, but didn't manage to get reference to the component's render as you can do in non-setup style scripts. My attempt is here: algolia/doc-code-samples#430
Have you tried the getCurrentInstance function ?
EDIT: Made it kinda work doing this:
Using the code from your pull request, I removed the search.vue component and put everything in the page. Then I did this modification:
app.ssrContext.payload.algolia = await instantsearch.findResultsState({
// todo: what is the component? i don't see how to access the instance we currently are in
component: getCurrentInstance(),
// this relies on a patch in createServerRootMixin, as the component would be a child likely
renderToString,
});
The issue next was that the finderResultsState function (https://github.com/algolia/instantsearch/blob/master/packages/vue-instantsearch/src/util/createServerRootMixin.js) tries to access the instantsearch instance by doing this.instantsearch which doesn't work. If I modify the file by doing this
created() {
instance = component.provides.$_ais_ssrInstantSearchInstance;
instance.start();
Then it works (I still get some hydration mismatch on the widgets, but the search results is good). I just don't know how to make the finderResultsState function work properly.
Hey there,
Sorry for the link to private repository earlier. 😓 It's now public.
I'm using a solution similar to Bcavez's. The search results are SSR'd, but not the rest of the UI (facets, etc.)
I'm guessing this is related to me not using instantsearch.findResultsState()
.
@Baroshem Unfortunately, I currently do not have the time to contribute. But I will make sure to share what I learn here!
Hey @Strift
Sorry for no contact from my side. I was off due to sick leave.
Thanks for that! I am currently working on other modules as this one is quite stable now and does not require that many new features. So, I am looking at this feature as an opportunity for an open source activity for contributors to implement.
After a long debugging session I managed to make finderResultsState
work. I hope this helps anyone struggling with this.
onBeforeMount(() => {
// Use data loaded on the server
if (data.value) {
instantsearch.hydrate(data.value.algoliaState)
}
})
const { data } = await useAsyncData('algolia-state', async () => {
const algoliaState = await instantsearch.findResultsState({
// IMPORTANT: a component with access to `this.instantsearch` to be used by the createServerRootMixin code
component: {
$options: {
data() {
return { instantsearch }
},
render() {
h('div')
},
},
},
renderToString,
})
return { algoliaState }
})
Hey @Laruxo
Thanks for this piece of code. Would you be interested in contributing to the module by writing a docs section with this code sample? I am sure that several people could benefit from that :)
Hey @Baroshem, honestly, I am not using this module right now 😅 I think we should contribute to vue-instantsearch
instead, it really needs to move away from that mixin. I will try to find some time for any of this a bit later. First, I really need to finish my migration to Nuxt 3 🙂
@Laruxo
I see but you just provided a way how users can have instantsearch in Nuxt 3 with SSR.
If you don't want to, I can add this code snippet to the docs so the future users could more easily find the answer for that :)
Fixing this in instantsearch is a good idea as well!
@Baroshem got inspired this morning, so I created a PR for the docs 🙂
Awesome!
I will review it in a few hours :)
@Laruxo, the component won't have access to the child widgets though, which is needed to have routing and state synced 🤔
@Haroenv you are right, I've just encountered that. Now, I am having some errors when I use initialUiState
. Do you have any ideas how I could work around it?
The component you're mounting needs to be the component with all widgets mounted too.
So I managed to make it work for my project. For that, I needed to render AisRefinementList
and AisSortBy
components. I don't persist the state to the route for now, so I did not add the router.
@Haroenv do you know other cases for which we would need to add additional components?
const { data: algoliaState, error } = await useAsyncData('algolia-state', async () => {
return instantsearch.findResultsState({
// IMPORTANT: fake component used by the createServerRootMixin code
component: {
$options: {
components: { AisInstantSearchSsr, AisRefinementList, AisSortBy },
data() {
return { instantsearch }
},
provide: { $_ais_ssrInstantSearchInstance: instantsearch },
render() {
return h(AisInstantSearchSsr, null, () => [
h(AisRefinementList, { attribute: 'metadata.languages.value' }),
h(AisSortBy, { items: [{ value: indexName, label: '' }] }),
])
},
},
},
renderToString,
})
})
This would make sense, but if you're going that far, you can take the component, put it in a separate file, and use that to both render the html, as well as the server side rendering
I tried that, but my components use Nuxt composables (e.g. useNuxtApp
) which causes the SSR to fail (specifically instantsearch.findResultsState
). Maybe someone with a better understanding of Vue/Nuxt internals could work around that.
Sorry for posting in a closed issue but I cannot seem to make your solution work. Is there something missing in the snippet you provided @Laruxo ?
I'm getting this error:
[nitro] [dev] [unhandledRejection] <ref *1> ReferenceError: XMLHttpRequest is not defined
at eval (file:///home/projects/github-vukisz-jvkzve/algoliasearch/dist/algoliasearch-lite.esm.browser:818:39)
at new Promise (<anonymous>)
at Object.send (file:///home/projects/github-vukisz-jvkzve/algoliasearch/dist/algoliasearch-lite.esm.browser:817:20)
at retry (file:///home/projects/github-vukisz-jvkzve/algoliasearch/dist/algoliasearch-lite.esm.browser:419:38)
at eval (file:///home/projects/github-vukisz-jvkzve/algoliasearch/dist/algoliasearch-lite.esm.browser:432:16) {
error: [Circular *1]
}
Here is a minimal repro: https://stackblitz.com/edit/github-vukisz-jvkzve?file=pages/search.vue
Sorry for the late reply @Bcavez. Your implementation seems correct, so I don't know why it does not work. The only strange thing that I can see from the error is the use of a browser build (algoliasearch-lite.esm.browser
). In my case, we use a different build.
@Bcavez have you found any solution to this problem?
Hello, I just wanted to ask if it is possible to use this module for Nuxt 3 Instantsearch with SSR? I tried using
<ais-instant-search-ssr>
component, but it throws:Also the Algolia's official Instantsearch example for Nuxt with SSR is only for Nuxt 2. So not much to learn there.
Is there any way to use Instantsearch with SSR, or should I use
useAlgoliaFacetedSearch
inside ofuseAsyncData
for obtaining results and handle filtering manually with factes?Thanks for your time!