Git Product home page Git Product logo

Comments (14)

tcastelly avatar tcastelly commented on May 24, 2024 1

Thank you for your help.

I have issue with getDataFromTree during the "hydration", this article helped me:
https://lihautan.com/hydrating-text-content/

So instead I use renderToStringWithData.

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

Hi @tcastelly ! Tell me if something like this works in your project:

// This is the server renderer we just built
const main = import('../dist/server/main.js');

server.get('*', async (req, res) => {
  const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
  const renderPage = (await main).default.default;

  const apolloCache = new InMemoryCache();

  const { html } = await renderPage(url, {
    manifest,
-   apolloCache,
+   initialState: { apolloCache },
    preload: true,
  });

  res.setHeader('Cache-Control', 'max-age=0');
  res.end(html);
});
const App = ({
  isClient,
- apolloCache = new InMemoryCache(),
+ initialState,
}) => {
  const client = new ApolloClient({
    link: createHttpLink({
      uri: 'http://localhost:8080/graph',
      credentials: 'same-origin',
    }),
    ssrMode: !isClient,
-   cache: apolloCache,
+   cache: initialState.apolloCache,
    credentials: 'same-origin',
  });
export default viteSSR(App, {
  routes,
  transformState(state) {
    if (import.meta.env.SSR) {
      // Serialize
      state.apolloCache = state.apolloCache.extract()
      return JSON.stringify(JSON.stringify(state))
    } else {
      // Deserialize
      state = JSON.parse(state)
      state.apolloCache = new InMemoryCache().restore(JSON.parse(state.apolloCache))
      return state
    }
  }
}, (ctx) => {
  // Custom initialization hook
})

If this works, I will add a second parameter defaultTransformer to the transformState hook so you don't need to care about stringify/parse and escaping dangerous characters for XSS.

from vite-ssr.

tcastelly avatar tcastelly commented on May 24, 2024

Thank you for your help.

In the main.jsx, the state is always null.
I created a project it can be easier to test:

https://github.com/shenron/vite-ssr-plugin-react-demo

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly Ah right, I forgot about the development server. This fixes it and is a bit simpler:

export default viteSSR(App, {
  routes,
  transformState(state) {
    if (import.meta.env.SSR) {
      // Serialize
      state.apolloCache = state.apolloCache.extract();
      return JSON.stringify(JSON.stringify(state));
    }

    // Deserialize
    return JSON.parse(state);
  },
}, ({ initialState }) => {
  // Custom initialization hook
  if (import.meta.env.SSR) {
    initialState.apolloCache = new InMemoryCache();
  } else {
    initialState.apolloCache = new InMemoryCache().restore(initialState.apolloCache);
  }
});

You can stop passing initialState: { apolloCache } from your production server since it's already done in the main hook.

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly I've added defaultTransformer in 0.8.1. You can simplify the transformState like this (keep the code in the main hook as in the previous comment):

transformState(state, defaultTransformer) {
  if (import.meta.env.SSR) {
    state.apolloCache = state.apolloCache.extract();
  }

  return defaultTransformer(state);
}

from vite-ssr.

tcastelly avatar tcastelly commented on May 24, 2024

Thank you for your help. I updated the plugin and files like this:

./back/index.mjs

const { html } = await renderPage(url, {
  manifest,
  initialState: { },
  preload: true,
});

./client/main.jsx

export default viteSSR(App, {
  routes,
  transformState(state, defaultTransformer) {
    if (import.meta.env.SSR) {
      state.apolloCache = state.apolloCache.extract();
    }

    return defaultTransformer(state);
  },
}, ({ initialState }) => {
  // Custom initialization hook
  if (import.meta.env.SSR) {
    initialState.apolloCache = new InMemoryCache();
  } else {
    initialState.apolloCache = new InMemoryCache().restore(initialState.apolloCache);
  }
});

Maybe I missed something, but The behavior is the same. The SSR does not wait the end of the Graphql query.
I have "Loading ..." in my DOM and the cache is empty:

...
<script>window.__INITIAL_STATE__="{\"apolloCache\":{}}"</script>
...

I created an other project without the ssr plugin:
https://github.com/shenron/vite-ssr-react-demo/

The only way that I found to fix my issue is to use:

import { getDataFromTree } from '@apollo/client/react/ssr';

https://github.com/shenron/vite-ssr-react-demo/blob/es6/src/entry-server.jsx#L22

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

Ah I see, so the state now works but it cannot await for queries. vite-ssr relies on Suspense viareact-ssr-prepass. Looks like some updates in Apollo 3 have removed Suspense support so it's tricky to make it work:

I wasn't aware that Apollo is not compatible with Suspense. I'll have a deeper look at it later this week and see if there's anything that we can do here.

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly I've been playing with Apollo internals for a while and I think I got it working. The simplest solution is probably using getDataFromTree instead of React's renderToString until Apollo supports Suspense. I'll try to figure out a way to provide it in vite-ssr API soon πŸ‘

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly Can you check v0.9.0? It should use renderToStringWithData automatically if it detects you have @apollo/client and @vitejs/plugin-react-refresh installed.

I tried it in your repo and it does await for the loading variable to become false so it doesn't render Loading... anymore. However, the GraphQL query returns undefined for some reason but that might be related to the API πŸ€”

from vite-ssr.

tcastelly avatar tcastelly commented on May 24, 2024

It works better thank you :)
But I have a strange behavior.

In this demo project, each page resolve props once and the home page resolve a QraphQL query.

In the ./client/api.jsx I print the state. In ssr mode I see only the apolloCache. Else I see the result of the default query.

// from ssr: { apolloCache: InMemoryCache2 }
// else {body: {…}}
console.log(route.meta.state);
return <Page {...route.meta.state} />;

To reproduce:

npm run dev

Go the the About page from Home. And try to load directly this About page.

Thank you very much for your help.

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly I think that's expected πŸ€” . Only the first route gets the initialState in its route.meta.state after rehydration. Further navigation (SPA mode) to other routes don't get anything in their respective route.meta.state.

I'm not sure what you are trying to accomplish. If you need the whole initialState in every page, you can pass it from your App.jsx as props I guess.

Also, are you going to mix Apollo queries and page-props?

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

I've added a simple example for manual testing based on your repo here: https://github.com/frandiox/vite-ssr/tree/master/examples/react-apollo

from vite-ssr.

tcastelly avatar tcastelly commented on May 24, 2024

I'm agree, only the first route gets the initialState.

I created this project from your react example and I added an Apollo Query to try. So I mixed Apollo queries and page props. Maybe not a good idea because there is no more props in pages during the first launch.

Anyway, vite-ssr plugin with Apollo works now!
Thank you very much for your time.

Edit: Thank you for the new example with only react apollo

from vite-ssr.

frandiox avatar frandiox commented on May 24, 2024

@tcastelly Thanks for all the reproduction and information you provided here, glad it's now working!

from vite-ssr.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.