-
-
Notifications
You must be signed in to change notification settings - Fork 519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setup Apollo for a Vue+SSR app #1516
Comments
My main problem was, that I have not created a fresh vue app instance at every request. |
@jarkt, could you tell us in more detail how you managed to solve this issue? |
To be honest, I can't say much more. It was just irritating because my code wasn't creating a new Vue app instance on every request and I didn't question it. Now I create the vue app and also the apollo client on every request and this had solved also the state issue. |
@jarkt, isn't the Vue app and Apollo client automatically created on every request? How did you change this behavior? Perhaps you can demonstrate the code? I just had a similar problem but never found a solution |
Don't sure what you mean with "automatically". Maybe in Nuxt, yes. But I have a custom setup with Vite+Vue and so I have to care about that for myself. What does your setup look like? |
@jarkt, i have something similar. On every request, Express calls the render function: server.js export async function createServer() {
const app = express();
const router = express.Router();
app.use(express.static("dist/client", { index: false }));
router.get("/*", async (req, res, next) => {
try {
const template = await fs.promises.readFile(
resolve("./dist/client/index.html"),
"utf-8"
);
const render = await (
await import("./dist/server/entry-server.js")
).render;
const { appHtml, apolloState } = await render(req);
const html = template
.replace("<!--apollo-state-->", apolloState)
.replace("<!--app-html-->", appHtml);
res.status(200).set({ "Content-Type": "text/html" }).end(html);
} catch (e) {
next(e);
}
});
app.use("/", router);
return { app };
}
export const run = (app) => {
app.listen(3000, () => {
console.log("http://localhost:3000");
});
};
createServer().then(({ app }) => run(app)) src/entry-server.js import { renderToString } from "vue/server-renderer";
import { createSSRApp, provide, h } from "vue";
import App from "@/App.vue";
import router from "@/router";
import { ApolloClients } from "@vue/apollo-composable";
import { defaultApolloClient } from "@/apollo";
import { exportStates } from "@vue/apollo-ssr";
export async function render(req = null) {
const app = createSSRApp({
setup() {
provide(ApolloClients, {
default: defaultApolloClient
});
},
render: () => h(App),
});
app.use(router);
await router.push(req.url);
await router.isReady();
const ctx = {};
const appHtml = await renderToString(app, ctx);
const apolloState = exportStates(
{ defaultApolloClient }
);
return {
appHtml,
apolloState,
};
} As far as I understand, a Vue and Vue Apollo will be created on every request. Is not it so? However, apolloState is not reset after page reload |
Please try:
(Further up you used a different key.) |
@jarkt, thanks for the hint, but it didn't give any results Simple example:
That is, it turns out that a common state is used for all users |
Ah yes, of course. JavaScript modules are evaluated only once. apollo.js exports the client, but it's always the same. You have to use a function to create one. |
@jarkt, something like that? const app = createSSRApp({
setup() {
provide(ApolloClients, {
default: () => defaultApolloClient
});
},
render: () => h(App),
}); This does not work, the page containing GraphQL queries does not open, and there are errors in the log
P.S. By the way, this option doesn’t work either, when you try to open a page, a request to the server always occurs, since Apollo cannot detect state const apolloState = exportStates(
{ default: defaultApolloClient }
); And if you do it the way it was before, it works, but a common state is used const apolloState = exportStates(
{ defaultApolloClient }
); |
No. You're importing the apollo client in this line: import { getDefaultApolloClient } from "@/apollo";
...
const app = createSSRApp({
setup() {
provide(ApolloClients, {
default: getDefaultApolloClient()
});
},
render: () => h(App),
}); And the other one, I'm very sure, that const apolloState = exportStates(
{ default: defaultApolloClient }
); is what you want, because you naming is not consistently otherwise. Don't know what the consequences are... I would not expect that it works. |
@jarkt, I tried exporting as a function: export function defaultApolloClient() {
return new ApolloClient({
link: defaultLink,
cache: defaultApolloClientCache,
ssrMode: import.meta.env.SSR
});
} const app = createSSRApp({
setup() {
provide(ApolloClients, {
default: defaultApolloClient()
});
},
render: () => h(App),
}); This did not give any results, the test fails (see #1516 (comment)) Are you sure that everything is working correctly for you? P.S. The key named default is not important in this case, since it is used to restore the cache from the APOLLO_STATE variable, something like this: const defaultApolloClientCache = new InMemoryCache();
if (!import.meta.env.SSR) {
if (typeof window !== "undefined") {
if (typeof window.__APOLLO_STATE__ !== "undefined") {
defaultApolloClientCache.restore(
window.__APOLLO_STATE__.defaultApolloClient
);
}
}
} As you can see, I'm using the defaultApolloClient key, not default |
My code is working fine. |
It doesn't matter in this case, as I wrote above, this name is used to restore the cache
Nothing weird, I'm using a key named defaultApolloClient, not default (see #1516 (comment))
I'm not using the apolloProvider that is part of the @vue/apollo-option package because I'm using the Composition API (@vue/apollo-composable) |
I really struggle with the Apollo Setup in a Vue SSR app.
The documentation, also the inofficial, is incompleted or outdated.
I wonder about the fact, that I need to pass the client in two ways. This is my code to create the app (shortened):
The
provide
seems to be needed to find the client in the componentssetup
functions.And without the app.use, SSR would not work (I believe the data are loading, but nobody waits for it). But both in combination seems not to be documented.
Okay, it runs so far. But there is a very strange thing:
In the doc (https://v4.apollo.vuejs.org/guide-advanced/ssr.html) it seems that I should create an apollo client while application startup time. But the apollo doc (https://www.apollographql.com/docs/react/performance/server-side-rendering/#example) says:
Why the Vue-Apollo doc doesn't reflect it?
Another issue is the SSR. Maybe coupled with the previous question. If I set the fetchPolicy to "no-cache" for test and dev reasons, there appears a hydration mismatch problem. Although I give the "state" to the client. The initial HTML is is generated correct, and the client is also able to generate the same result, but while the hydration time, the data are not available and so is the result another. (That means the page is rendered correctly, than content disappears and reappears immediately after client has loaded the content.)
The "state" seems to be the "cache". The documentation uses
renderState
in the template. (https://v4.apollo.vuejs.org/guide-advanced/ssr.html) But I have not found that function.The text was updated successfully, but these errors were encountered: