-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
setContext to async import a library to generate the link #11361
Comments
Hey @arahman4710 👋 The problem you're running into is that your
I'm not super familiar with Action Cable since the last time I used rails was the Rails 4 days before Action Cable was introduced, but looking around at the various libraries, here are a couple things that I can point out that should help. Even if
You'll want to make sure you create a single I'm assuming you're using GraphQL Ruby in your example, and taking a look there at the Try the following and see if it works for you: import { ApolloClient, HttpLink, ApolloLink, InMemoryCache } from '@apollo/client';
import { createConsumer } from '@rails/actioncable';
import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink';
const cable = createConsumer(process.env.NEXT_PUBLIC_ACTION_CABLE_API_URL)
const hasSubscriptionOperation = ({ query: { definitions } }) => {
return definitions.some(
({ kind, operation }) => kind === 'OperationDefinition' && operation === 'subscription'
)
}
const link = ApolloLink.split(
hasSubscriptionOperation,
new ActionCableLink({ cable }),
httpLink
);
const client = new ApolloClient({
link: link,
cache: new InMemoryCache()
}); |
Hey @jerelmiller, I tried the example solution initially but got a Do you have any advice for that? Thank you! |
I guess I should have read this first 😅 To be honest, I'm not sure these are compatible. Action Cable works with a Rails backend. Since you're using Next.js, Next.js will not know how to handle this. I'd recommend finding some blog posts that describe how to setup websockets with Next.js and figuring out what client libraries you'll need. The first part of my previous reply still stands though. You'll need a terminating link which will send the websocket request to your server. |
Are you sure this is because of the import, or is this because you're using Action Cable with Next.js? |
I think its because i'm using action cable with next js but i was trying to load it asynchronously to avoid this problem (not 100% sure if that'd work though) |
The trick here is to return an Observable from your link and before you start sending the observer notifications, you need to resolve the promise. Check out the implementation of
I'm not sure this will solve anything to be honest. Unless there is something I'm not aware of where Next.js has compatibility with Action Cable, you're going to run into the same issue, it just will happen "later". |
Out of sheer curiosity, do you have a resource I can look at that recommends or shows Action Cable working with Next.js? I'm curious how you arrived at the conclusion to use these two together. Totally fine if you'd rather not answer this question! Again, just super curious what material is out there so I can better understand 🙂 |
I don't have a specific resource. I have a react/next js app for the FE and a rails app for the BE and wanted to introduce websockets. The rails recommended solution for web sockets is action cable which is why I started to look into that. Does that help? |
I was following this blog post: https://medium.com/@jerridan/implementing-graphql-subscriptions-in-rails-and-react-9e05ca8d6b20 (it doesn't specifically mention next js though) |
Ah ok this is useful context that I was missing. I'm used to seeing Next.js being the "full stack" solution, which includes Next.js being your server, not just the frontend part, so this makes sense! To be honest, I'm not super familiar with Next.js and all its capabilities, so I didn't realize you could just use it as a frontend. In that case, I take back what I said. As long as your frontend app is communicating to the Rails server, Action Cable should work just fine! Back to this error:
Does this happen on the |
I just found this post about that error: https://stackoverflow.com/questions/66096260/why-am-i-getting-referenceerror-self-is-not-defined-when-i-import-a-client-side Does this match what you're seeing? If so, now I finally understand why you're trying to do the dynamic import. Thanks for taking this ride with me 😆. I'll followup with an idea of how you might get this to work. |
Alright, see if something like this works for you (warning, untested). import { setContext } from '@apollo/client/link/context';
// We only want to create the consumer once, so cache it after its created
let consumer;
async function getActionCableConsumer() {
if (consumer) {
return consumer;
}
const { createConsumer } = await import('@rails/actioncable');
consumer = createConsumer(process.env.NEXT_PUBLIC_ACTION_CABLE_API_URL)
return consumer;
}
// We can use `setContext` to create the cable async and pass it to the terminating link
const setCableLink = setContext(async () => ({
cable: await getActionCableConsumer()
}))
// Similarly, we only want to create the action cable link once
let actionCableLink;
const getActionCableLink = ({ cable }) => {
actionCableLink ||= new ActionCableLink({ cable });
return actionCableLink;
}
// Since we can't create the `ActionCableLink` until we have the cable, we wrap it
// with a custom `ApolloLink` and execute it here. This is our terminating link
const actionCableLink = new ApolloLink((operation) => {
// Pull the cable off of context which you set in the `setCableLink`
const { cable } = operation.getContext();
return ApolloLink.execute(getActionCableLink({ cable }), operation)
});
// Ensure your subscription link is a combination of `setCableLink` and `actionCableLink`
const subscriptionLink = setCableLink.concat(actionCableLink);
const link = ApolloLink.split(
hasSubscriptionOperation,
subscriptionLink,
httpLink
); Try this out and let me know if this works for you! |
Gonna try it out in a bit, thanks for the help! |
Hey @jerelmiller, I tried it out but I don't think its working as intended. I would expect a request to Any other ideas for how to debug or try out? Thanks! |
I have verified that all the functions you've written are being called but it doesn't seem like the end result is happening the way I'd expect it to |
Stepped through the code a bit more. It seems like
I'm reading the docs on a terminating link and it seems like we need to "send your composed GraphQL operation to the destination that executes it (usually a GraphQL server) and returning an ExecutionResult" |
Actually, think i got it working with Thanks for the help! |
@arahman4710 ah thank you! I totally forgot that Don't hesitate to reach out if you need any more help! You may also find our discord server and/or community forums helpful as well. |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Hey all,
I'm using action cable + next.js and importing it normally resulted in a
ReferenceError: self is not defined
so i decided to dynamically import it to try to fix it.I saw in the docs that
setContext
is how async processing for links should work so I'm usingsetContext
and then dynamically importing action cable and then returning the action cable link. However, it doesn't seem to be triggering the link properly. Does anyone know what i'm doing wrong? Here is my code for it:Thanks!
The text was updated successfully, but these errors were encountered: