Skip to content
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

AblyProvider and Next - Ably connects from server even with use client #1742

Open
bookercodes opened this issue Apr 17, 2024 · 3 comments
Open
Assignees
Labels
documentation Improvements or additions to public interface documentation (API reference or readme). enhancement New feature or improved functionality.

Comments

@bookercodes
Copy link

bookercodes commented Apr 17, 2024

Consider the following client component in Next 14.1 with the app router:

'use client'

import * as Ably from 'ably';
import { AblyProvider } from 'ably/react'
import Link from 'next/link'
import { UserButton } from "@clerk/nextjs";

export default function ChatLayout = function ({ children })  {
    const client = new Ably.Realtime({ authUrl: '/api/ably' })
    return <>
        <nav>
            <h1>Comet</h1>
            <UserButton showName={true} />
        </nav>

        <aside>
            <ul>
                <li>
                    <Link href="/chat/announcements">#Announcements</Link>
                </li>
                <li>
                    <Link href="/chat/general">#General</Link>
                </li>
                <li>
                    <Link href="/chat/random">#Random</Link>
                </li>
                <li>
                    <Link href="/chat/mods-only">#Mods-only</Link>
                </li>
            </ul>
        </aside>
        <AblyProvider client={client}>
            {children}
        </AblyProvider>

    </>
}

Even though it's a client component, Next still runs it on the server as part of a pre-fetch, causing AblyProvider to connect form the server.

In my case, that causes an error explained here ably-labs/react-hooks#8

10:30:09.593 Ably: Auth.requestToken(): token request signing call returned error; err = Error: `input` must not start with a slash when using `prefixUrl`

So, my server never actually connects (I just get a noisy error), but it's totally plausible the sever connects if you use an absolute URL or another auth implementation, causing a surprising duplicate connection.

What is the implication of this? Well, the error in the console is a bit verbose and it can look messy in the Ably developer console when the client appears to connect twice, but the implication is probably quite little, isn't that right? I thought it could result in duplicate connections (for example, in an avatar stack), but usePressence, etc. is run as an effect (client-side only).

┆Issue is synchronized with this Jira Task by Unito

@bookercodes
Copy link
Author

bookercodes commented Apr 17, 2024

For the benefit of anyone else with this issue, I am including my solution below, which is to turn ssr off for the component.

Team Ably, I'm not a React or Next expert or anything, so is this the right way to go about it?

Is there a way to make the AuthProvider work more friendly with Next SSR? Maybe if it's running in a server context, it shouldn't try and connect? I'm not sure, as there may be implications for testing etc.

Any advice on best practices appreciated!

'use client'

import * as Ably from 'ably';
import { AblyProvider } from 'ably/react'
import Link from 'next/link'
import { UserButton } from "@clerk/nextjs";


export default dynamic(() => Promise.resolve(ChatLayout), {
    ssr: false
})

const ChatLayout = ({ children }) => {
    const client = new Ably.Realtime({ authUrl: '/api/ably' })
    return <>
        <nav>
            <h1>Comet</h1>
            <UserButton showName={true} />
        </nav>

        <aside>
            <ul>
                <li>
                    <Link href="/chat/announcements">#Announcements</Link>
                </li>
                <li>
                    <Link href="/chat/general">#General</Link>
                </li>
                <li>
                    <Link href="/chat/random">#Random</Link>
                </li>
                <li>
                    <Link href="/chat/mods-only">#Mods-only</Link>
                </li>
            </ul>
        </aside>
        <AblyProvider client={client}>
            {children}
        </AblyProvider>

    </>
}

@ttypic ttypic added enhancement New feature or improved functionality. documentation Improvements or additions to public interface documentation (API reference or readme). labels Apr 17, 2024
@VeskeR
Copy link
Contributor

VeskeR commented Apr 17, 2024

Hi @bookercodes ! Thank you for bringing this up and finding other existing solutions.

Yes, the approach described here: ably-labs/react-hooks#8 (comment), is currently the suggested one: use next/dynamic with the ssr: false option in order to force components to load on the client side.
So your solution looks right:

export default dynamic(() => Promise.resolve(ChatLayout), {
    ssr: false
})

This has also prompted us to discuss how we can improve the usage of ably-js in Next.js with SSR to avoid issues like this, and we will investigate this further. There might be a better solution (instead of disabling SSR altogether). For example, if you detect that you are running on the server during SSR, then you can set the autoConnect: false option when creating the Ably.Realtime instance to prevent it from trying to connect to Ably servers. This should be the desired behavior during SSR; we don't want to perform any real operations there.
We will investigate this further and update this issue with more information.

@bookercodes
Copy link
Author

Ah, interesting!

You're right, something like this works well:

const client = new Ably.Realtime({ authUrl: '/api/ably', autoConnect: typeof window !== 'undefined' })

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to public interface documentation (API reference or readme). enhancement New feature or improved functionality.
Development

No branches or pull requests

3 participants