How to pass current url to Vue Instantsearch routing during SSR?

Hi,

The problem I’m experiencing is that my Algolia setup is always rendering without any initial state during SSR because it’s not receiving the ‘current url’ (which I’m pushing into the Vue Router).

On the client-side it does figure out the url though, so in the end the rendering goes fine (just not when server-side rendering).

I’m basically using the SSR setup of the Vue Instantsearch docs and Github (https://github.com/algolia/vue-instantsearch/tree/aeea2630e4a2b01b959645baf6b40a01658d1eab/examples/ssr)

In the createServerRootMixin I’m defining the routing and router object as provided on Github. I’m then expecting that either read() or onUpdate() gets called when I do router.push(context.url);. This doesn’t happen though. Is that right? Do I have to manually trigger an update on the server (whereas this happens automatically client-side)? If so, how can I tell this instantsearch router the url gets updated?

I hope someone can give some clarity on where I’m missing something :slight_smile:

(I’m using Vue Instantsearch 3.3.0 because of: https://github.com/algolia/vue-instantsearch/issues/1054)

Arco

1 Like

Hi @arcomul can you share with us the code you’re using around this router.push() ? What’s the confusing to me is that if you’re doing router.push, you’re most likely on the client and in most SSR implementation there is no server roundtrip after the first page load.

Sharing your code would help here.

Youcef

Hi Youcef, I basically use router.push like it gets used in the SSR example: https://github.com/algolia/vue-instantsearch/blob/master/examples/ssr/src/entry-server.js#L7

On the initial render (during SSR) I have to tell the router/app in which state to render the application, with which url, so I do there a router push to tell vue-router to display the right components.

This url should also in some way end up in vue-instantsearch, but to me it’s not clear how it should arrive there if routing.router.read or onUpdate doesn’t get called.

Here is my specific implementation in my SSR node server:

    const body = req.body;
    const { createApp } = require(body.path);
    const context = JSON.parse(body.serializedProps);

    const { app, router } = await createApp({ context });
    router.push(context.url);

    router.onReady(() => {

      // no matched routes, reject with 404
      const matchedComponents = router.getMatchedComponents();
      if (matchedComponents.length === 0) {
        return res.sendStatus(404);
      }

      renderer.renderToString(app, (err, markup) => {
        context.algoliaState = app.instantsearch.getState();
        ...etc

Hi @arcomul if you look at the example you linked, the state should transit via a global variable __ALGOLIA_STATE__ which Vue InstantSearch should populate automatically.

However, in order for Vue IS to be able to create the right state, you need to pass it the URL the server is responding to: which is done in read

Does that help?

Hi @Youcef

I am populating the __ALGOLIA_STATE__ window variable, the problem I am experiencing happens before that, while the server is rendering the application. I don’t think that the __ALGOLIA_STATE__ variable has an effect on that.

In the read() function I try to retrieve the url like in your example:

            read() {
              const url = context && context.url
                ? context.url
                : typeof window.location === 'object'
                  ? window.location.href
                  : '';
              ...

But here is where the problem appears, it seems that server-side this read() method never gets called by the vue-instantsearch plugin. Cient-side it does get called, and the state is read from the url and the page renders the correct state, but on the server the read() function doesn’t get called and therefore always renders the page with an empty state, even when the url contains a certain filter.

If you try to log the url console.log(url) on line 84 of main.js of the SSR example: vue-instantsearch/main.js at master · algolia/vue-instantsearch · GitHub You’ll see that when refreshing the page the url never gets logged in the server logs.

Hey @arcomul,

I’ve just tested using this sandbox (which is the same code as in the documentation) and it seems that the route is properly parsed on the server and rendered to the right state.

For example, when hitting this route (which contains a refinement on brand Samsung) with JavaScript disabled (meaning no hydration happens), the search state is refined on it and displays only Samsung results.

Capture d’écran 2021-09-27 à 19.54.54

If this isn’t what you mean, please don’t hesitate to send us a reproduction of your issue with the provided sandbox. This will make it easier to understand the situation and debug it.

Hi @sarah.dayan,

Thank you for investigating!

It seems that properly reading the url breaks in a later version of vue-instantsearch.

I forked the sandbox and added a console.log in the read() function, which logs fine. The version used in the sandbox you provided is 3.0.3, after upgrading the vue-instantsearch package to version 3.3.0 (the version I am using) it doesn’t log anymore though.

Changing to the latest version of vue-instantsearch also doesn’t work, but for another reason: SSR is broken · Issue #1054 · algolia/vue-instantsearch · GitHub

The weird thing is that when I revert back to version 3.0.3 after being on 3.3.0, it also doesn’t work any more. I don’t really understand why.

Here you can find the sandbox: loving-stallman-xxe2d - CodeSandbox