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

"Connection closed" error when using redirect from a server action to a page with client components #110

Closed
6 tasks done
nickw1 opened this issue Jan 18, 2025 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@nickw1
Copy link

nickw1 commented Jan 18, 2025

Describe the bug

Hi,

I'm encountering problems when I use redirect() inside a server action, to a server component which itself contains a client component.

I have prepared a minimal working example at: https://github.com/nickw1/rs-minimal-1

As you can see, there is an app component which, depending on the session state, renders either a Logout component or a Login component plus a NewUser component.

All are server components except the NewUser component.

Login and Logout contain forms connected to server actions which either set, or unset, a session (using iron-session) though the session handling appears to be unrelated to the problem. Each server action redirects to the root when the session handling is completed.

What should happen is, on first visit the user sees a "Login" button and the message "A client component". The latter is the output from the NewUser component.

When they click "login", the "logout" button should appear (only). When the user then clicks "logout", it reverts to the "Login" button and the message "A client component" being rendered.

This works as expected if NewUser is not rendered, you can login and logout and all works as expected.

However if NewUser (the only client component) is rendered, when I click "Login", I get a "Connection closed" error. When I then reload the page, it does display "Logout" as expected.

Apologies if this is not a bug but to my understanding, this example should work as expected.

Thanks!

Reproduction

No response

Steps to reproduce

Standard steps:
git clone https://github.com/nickw1/rs-minimal-1
pnpm i
pnpm exec react-server
Navigate to http://localhost:3000
Click "login"
Connection closed error occurs.

System Info

System:
    OS: Linux 6.8 Ubuntu 22.04.5 LTS 22.04.5 LTS (Jammy Jellyfish)
    CPU: (16) x64 13th Gen Intel(R) Core(TM) i5-1340P
    Memory: 27.48 GB / 31.05 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 20.10.0 - /usr/local/node/bin/node
    npm: 10.2.3 - /usr/local/node/bin/npm
    pnpm: 9.12.3 - /usr/local/node/bin/pnpm
  Browsers:
    Chrome: 131.0.6778.69
  npmPackages:
    @lazarv/react-server: 0.0.0-experimental-d09c5f5-20250114-70d4f6d7 => 0.0.0-experimental-d09c5f5-20250114-70d4f6d7

(In fact I am testing on Firefox despite the output above)

Used Package Manager

pnpm

Logs

No log text appears.

Validations

@nickw1 nickw1 added the pending triage Pending triage label Jan 18, 2025
@lazarv lazarv self-assigned this Jan 18, 2025
@lazarv lazarv added bug Something isn't working and removed pending triage Pending triage labels Jan 18, 2025
@lazarv
Copy link
Owner

lazarv commented Jan 18, 2025

Hi @nickw1,

sadly there are some issues regarding using redirect in server functions. redirect works right now only when using no client components and so only SSR is used without client-side hydration.

Your reproduction example was really helpful in identifying issues, so thanks for preparing this for investigation!

I would like to point out some parts that need to be addressed in user-land instead of on the framework side.

Adding iron-session to resolve.external:

{
  "resolve": {
    "external": ["iron-session"]
  }
}

I might need some further investigation why this package was included as part of the production bundles, but without the configuration change, a production build was not working as expected because Rollup included iron-session in the server bundles, and the cookie package was not found during server start.

Also, the cookies were not included in an RSC update, but this was an easy fix on the framework side.

Update cookieObject in the Cookies class:

set(name, value, options) {
  this.cookieObject[name] = value;
  setCookie(name, value, options);
}

This change is needed, to properly use the updated session value during rendering. When processing a server function call, first the server function is executed, and then the React Server Component is rendered. setCookie only adds the cookie to a list to update the cookies with the response, but you will not see the changes without updating the cookieObject when you executing logic in the RSC to use either the Login or Logout component. You need to take care of updating your own cookie state in this implementation.

Different rendering strategies are being applied to the login and logout components. This happens because if react-server detects no client component usage, it will omit client-side hydration as it will not be needed as the page is fully static. Logout works with the server function redirect because it does not use RSC rendering, only executing the server function and responding with an HTTP 302 response.

A huge pack of bugfixes, new features, and enhanced error handling is on the way and it will include necessary changes addressing the issues found with redirect and cookies.

lazarv added a commit that referenced this issue Jan 19, 2025
…w example app (#111)

This update brings significant improvements, including a brand-new
__Pokémon example app__ designed to demonstrate the framework's enhanced
error handling and caching capabilities and to showcase superb
performance. In addition to the example app, this PR introduces a series
of crucial bug fixes, navigation improvements, and optimizations to both
client-side and server-side behavior.

A new `Form` navigation component has been introduced to simplify
navigation based on form interactions. This component allows developers
to trigger navigation based on form submissions or specific input
values, without requiring additional event handlers or imperative
navigation logic. This enables form-driven navigation patterns where a
user’s input can dictate the next page, improving declarative control
over navigation behavior.

A new mechanism for controlling when client-side navigation triggers
revalidation has been added. Previously, navigation could result in
unnecessary revalidation of server-side rendering, even in cases where
it was not required. This led to excessive network requests and
performance overhead. Now, developers can explicitly define revalidation
strategies, ensuring that only the relevant components are refreshed
based on user interactions or navigation. This fine-grained control
allows for more efficient client-side navigation while maintaining
consistency.

A global error component has been introduced to standardize error
handling across applications. Instead of handling errors in multiple
locations with redundant logic, applications can now define a
centralized error component that gracefully captures and displays
errors. This ensures a consistent error experience for users while also
simplifying maintenance by reducing duplicated error handling logic.
This feature also enables styling unexpected error caught during
server-side rendering.

Several issues related to module resolution when using `npx` have been
addressed. Previously, certain dependencies would not resolve correctly
when executed the react-server CLI via `npx`, causing unexpected
failures when running commands that relied on specific
`@lazarv/react-server` modules. These resolution issues have now been
fixed, ensuring that executing commands via `npx` correctly locates and
loads the necessary modules without manual intervention.

A fix has been applied to server function calls to ensure that
`redirect` responses behave correctly. Previously, certain redirect
scenarios did not properly propagate the response to the client,
resulting in broken navigation flows. This has now been corrected,
allowing server functions to issue redirects that are correctly handled
by the client. #110

Default CORS configuration has been adjusted to address inconsistencies
in handling requests across different origins. The previous
implementation had cases where preflight requests were either
incorrectly blocked or missing required headers. The fixed configuration
usage ensures that cross-origin requests function correctly,
particularly for applications interacting with APIs and remote
components from different domains.

React Server Component network requests have been updated to support
credential transmission. This change ensures that cookies are correctly
included in all relevant RSC network requests. This improvement allows
for more seamless authentication handling without requiring manual
workarounds.

Support for the `"use cache"` directive has been extended to additional
use cases. Previously, this directive was limited in scope and did not
fully cover all expected scenarios, particularly when used in certain
asynchronous server function calls. These fixes ensure that `"use
cache"` now applies more broadly and reliably across different execution
contexts, allowing more efficient caching behavior and reducing
redundant server computations.

Several issues affecting `RemoteComponent` and remote rendering have
been addressed. These fixes ensure that remotely loaded components
behave consistently, resolving previous issues where rendering states
were not properly handled. Remote rendering now correctly handles
component hydration using both sync and async React Server Components,
preventing unexpected behaviour.

File-system based routing has been improved to correctly apply error
boundaries at the appropriate levels, particularly for route outlets.
Previously, some errors were not caught at the intended boundary,
causing them to propagate unintentionally. With this update, errors
encountered within a specific route segment are correctly handled by the
nearest applicable error boundary, ensuring better application stability
and predictable error recovery.

The documentation has been updated to include details on the new APIs
introduced in this release. This includes explanations of the enhanced
error handling system, details on how to use the new `Form` navigation
component, and guidelines for configuring client-side navigation
revalidation. Additionally, examples have been added to clarify best
practices for handling errors at different levels of an application.
@nickw1
Copy link
Author

nickw1 commented Jan 19, 2025

Hi @lazarv, many thanks for addressing and fixing the bug and also giving recommendations for the code my side.

@nickw1
Copy link
Author

nickw1 commented Jan 19, 2025

To follow up: I can now confim that the minimal example is working fully, with no errors.
Closing the issue now.

@nickw1 nickw1 closed this as completed Jan 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants