react-on-rails-pro 16.5.1 → 16.6.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,7 @@ railsContext: _railsContext, RouterProvider, RouterClient, createBrowserHistory,
36
36
  // A full remount creates a fresh router and may legitimately issue another load.
37
37
  const didTriggerPostHydrationLoadRef = useRef(false);
38
38
  const didInitializeSsrGlobalRef = useRef(false);
39
+ const didSetLegacySsrFlagRef = useRef(false);
39
40
  if (routerRef.current === null) {
40
41
  const router = options.createRouter();
41
42
  // Set browser history for client-side navigation
@@ -53,10 +54,15 @@ railsContext: _railsContext, RouterProvider, RouterClient, createBrowserHistory,
53
54
  'router.hydrate() is required but not available on your TanStack Router version. ' +
54
55
  'Ensure @tanstack/react-router >=1.139.0 <2.0.0 is installed and provides router.hydrate().');
55
56
  }
56
- // Keep SSR mode enabled on hydration paths so Transitioner does not run
57
- // a client-only initial load before hydration settles.
58
- if (!hasSsrRouter && hasSsrPayload && router.ssr !== true) {
59
- router.ssr = true;
57
+ // Legacy hydration path only: signal SSR mode so the Transitioner skips its
58
+ // initial router.load() call, preventing a hydration mismatch. The object
59
+ // shape matches TanStack Router's internal $_TSR hydration contract (the
60
+ // Transitioner only checks truthiness). The new ssrRouter/RouterClient path
61
+ // does not need this — RouterClient sets router.ssr internally via its own
62
+ // hydrate() function.
63
+ if (!hasSsrRouter && hasSsrPayload && !router.ssr) {
64
+ router.ssr = { manifest: undefined };
65
+ didSetLegacySsrFlagRef.current = true;
60
66
  }
61
67
  routerRef.current = router;
62
68
  }
@@ -86,10 +92,22 @@ railsContext: _railsContext, RouterProvider, RouterClient, createBrowserHistory,
86
92
  let cancelled = false;
87
93
  // `cancelled` only suppresses logging for a discarded mount. The in-flight load still
88
94
  // completes unless the router exposes a best-effort cancelLoad() hook.
89
- router.load().catch((err) => {
95
+ router
96
+ .load()
97
+ .catch((err) => {
90
98
  if (!cancelled) {
91
99
  console.error('react-on-rails-pro/tanstack-router: Error loading routes after hydration:', err);
92
100
  }
101
+ })
102
+ .finally(() => {
103
+ // Legacy hydration only: clear the temporary SSR hint after the first
104
+ // client load has completed so it cannot influence later navigations.
105
+ // Only clear when this module set it, so pre-existing router.ssr state
106
+ // from user code or upstream router internals is preserved.
107
+ if (didSetLegacySsrFlagRef.current) {
108
+ router.ssr = undefined;
109
+ didSetLegacySsrFlagRef.current = false;
110
+ }
93
111
  });
94
112
  return () => {
95
113
  cancelled = true;
@@ -1,16 +1,5 @@
1
1
  import { createElement } from 'react';
2
2
  import { normalizeSearch } from "./utils.js";
3
- /**
4
- * Enables TanStack Router's internal SSR mode and verifies the flag is writable.
5
- */
6
- function enableRouterSsrMode(router) {
7
- const routerWithSsrFlag = router;
8
- routerWithSsrFlag.ssr = true;
9
- if (!routerWithSsrFlag.ssr) {
10
- throw new Error('react-on-rails-pro/tanstack-router: Expected router.ssr to accept a boolean flag. ' +
11
- 'Please check that your @tanstack/react-router version is compatible.');
12
- }
13
- }
14
3
  /**
15
4
  * Builds a React element tree with RouterProvider and optional AppWrapper.
16
5
  */
@@ -80,9 +69,10 @@ export async function serverRenderTanStackAppAsync(options, props, railsContext,
80
69
  const memoryHistory = createMemoryHistory({ initialEntries: [url] });
81
70
  router.update({ history: memoryHistory });
82
71
  // Async path uses router.load() public API, so no private store access is needed.
72
+ // No router.ssr flag is set here: React effects (including Transitioner's auto-load)
73
+ // do not execute during server-side renderToString, and router.dehydrate() does not
74
+ // depend on router.ssr.
83
75
  await router.load();
84
- // Ensure SSR output avoids client-only Suspense wrappers that can cause hydration mismatch.
85
- enableRouterSsrMode(router);
86
76
  const dehydratedState = {
87
77
  url,
88
78
  dehydratedRouter: typeof router.dehydrate === 'function' ? router.dehydrate() : null,
@@ -23,8 +23,8 @@ export interface TanStackRouter {
23
23
  };
24
24
  dehydrate?: () => unknown;
25
25
  hydrate?: (data: unknown) => void;
26
- ssr?: boolean | {
27
- manifest: unknown;
26
+ ssr?: {
27
+ manifest?: unknown;
28
28
  };
29
29
  }
30
30
  export interface TanStackHistory {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-on-rails-pro",
3
- "version": "16.5.1",
3
+ "version": "16.6.0-rc.0",
4
4
  "description": "React on Rails Pro package with React Server Components support",
5
5
  "main": "lib/ReactOnRails.full.js",
6
6
  "type": "module",
@@ -47,7 +47,7 @@
47
47
  "./ServerComponentFetchError": "./lib/ServerComponentFetchError.js"
48
48
  },
49
49
  "dependencies": {
50
- "react-on-rails": "16.5.1"
50
+ "react-on-rails": "16.6.0-rc.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": ">= 16",