react-on-rails-pro 16.2.0-rc.0 → 16.2.0-rc.1

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.
@@ -200,7 +200,30 @@ async function forAllElementsAsync(selector, callback) {
200
200
  const els = document.querySelectorAll(selector);
201
201
  await Promise.all(Array.from(els).map(callback));
202
202
  }
203
- export const renderOrHydrateImmediateHydratedComponents = () => forAllElementsAsync('.js-react-on-rails-component[data-immediate-hydration="true"]', renderOrHydrateComponent);
203
+ /**
204
+ * Filters elements to only include those with a nextSibling.
205
+ *
206
+ * This is used to prevent a race condition during HTML streaming where
207
+ * the props script element exists in the DOM but its content is incomplete.
208
+ *
209
+ * Why checking for ANY nextSibling works:
210
+ * - During HTML streaming, the browser parses incrementally
211
+ * - A script element's content is everything between <script> and </script>
212
+ * - The browser cannot parse ANY content after a script until </script> is found
213
+ * - Therefore, if nextSibling exists (even whitespace or comments), the closing
214
+ * tag was parsed and the content is guaranteed to be complete
215
+ *
216
+ * Elements without a nextSibling will be hydrated later when their
217
+ * immediate hydration script executes and calls reactOnRailsComponentLoaded().
218
+ *
219
+ * See: https://github.com/shakacode/react_on_rails/issues/2283
220
+ */
221
+ async function forAllCompleteElementsAsync(selector, callback) {
222
+ const els = document.querySelectorAll(selector);
223
+ const completeEls = Array.from(els).filter((el) => el.nextSibling !== null);
224
+ await Promise.all(completeEls.map(callback));
225
+ }
226
+ export const renderOrHydrateImmediateHydratedComponents = () => forAllCompleteElementsAsync('.js-react-on-rails-component[data-immediate-hydration="true"]', renderOrHydrateComponent);
204
227
  export const renderOrHydrateAllComponents = () => forAllElementsAsync('.js-react-on-rails-component', renderOrHydrateComponent);
205
228
  function unmountAllComponents() {
206
229
  renderedRoots.forEach((root) => root.unmount());
@@ -225,7 +248,7 @@ export async function hydrateStore(storeNameOrElement) {
225
248
  }
226
249
  await storeRenderer.waitUntilHydrated();
227
250
  }
228
- export const hydrateImmediateHydratedStores = () => forAllElementsAsync(`[${REACT_ON_RAILS_STORE_ATTRIBUTE}][data-immediate-hydration="true"]`, hydrateStore);
251
+ export const hydrateImmediateHydratedStores = () => forAllCompleteElementsAsync(`[${REACT_ON_RAILS_STORE_ATTRIBUTE}][data-immediate-hydration="true"]`, hydrateStore);
229
252
  export const hydrateAllStores = () => forAllElementsAsync(`[${REACT_ON_RAILS_STORE_ATTRIBUTE}]`, hydrateStore);
230
253
  function unmountAllStores() {
231
254
  storeRenderers.forEach((storeRenderer) => storeRenderer.unmount());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-on-rails-pro",
3
- "version": "16.2.0-rc.0",
3
+ "version": "16.2.0-rc.1",
4
4
  "description": "React on Rails Pro package with React Server Components support",
5
5
  "main": "lib/ReactOnRails.full.js",
6
6
  "type": "module",
@@ -43,7 +43,7 @@
43
43
  "./ServerComponentFetchError": "./lib/ServerComponentFetchError.js"
44
44
  },
45
45
  "dependencies": {
46
- "react-on-rails": "16.2.0-rc.0"
46
+ "react-on-rails": "16.2.0-rc.1"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": ">= 16",