[Chakra v3] Fix data fetching regression with the SSR rendering (@W-18822712@)#2785
Conversation
🎉 Snyk checks have passed. No issues have been found so far.✅ security/snyk check is complete. No issues have been found. (View Details) ✅ license/snyk check is complete. No issues have been found. (View Details) |
| // (see https://github.com/FormidableLabs/react-ssr-prepass/issues/84) | ||
| // - Why useInsertionEffect? Chakra v3 hooks (like useDisclosure, useBreakpointValue, useMediaQuery, useCallbackRef) rely on it for rendering optimization. | ||
| // - Why no-op? useInsertionEffect is meant for client side only. So on the server, we wanted prepass to ignore it. | ||
| React.useInsertionEffect = () => {} // no-op |
There was a problem hiding this comment.
Interesting fix! I'd imagine it's hard to find this out, good job!
I'm wondering if you want to move this line to near the ssr-prepass related code, for example in packages/pwa-kit-react-sdk/src/ssr/universal/components/with-react-query/index.js
There was a problem hiding this comment.
I was thinking that we needed to set it to no-op very early on, at the start of entry point. But I can try moving it to with-react-query file and see whether the time matters or not.
There was a problem hiding this comment.
Again, just trying to understand the behavior due to this change. So all the components that use useInsertionEffect will now have a slight delay (may be not noticable) for the css application?
There was a problem hiding this comment.
I've just tried moving the line to the with-react-query file, but the app errors out. So I'm leaving the code change as it is now, but I've added some comment near the prepass call.
There was a problem hiding this comment.
@unandyala there shouldn't be any delay nor any change in behaviour. The workaround we implemented here is only for the server side. So when useInsertionEffect is called on the client side, it should behave the same as before.
🤔 Is there something else I need to consider? Let me know please, thanks.
packages/extension-chakra-storefront/src/components/product-view/index.jsx
Outdated
Show resolved
Hide resolved
| - Send PWA Kit events to Data Cloud [#318] (https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2229) | ||
| - Fix dependencies vulnerabilities [#2338](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2338) | ||
| - Fix accessibility issues [#2375](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2375) | ||
| - Fix data-fetching regression with SSR rendering [#2785](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2785) |
There was a problem hiding this comment.
I'm wondering if we want to be a little be more clear on this for discoverability purposes.
We can either say what you have but mention + "due to chakra v3 upgrade".
So we can say something like "Ensure client-side only API's are called on the server"
I'm also ok with leaving it as is.
| if (typeof window === 'undefined') { | ||
| // Render nothing on the server side. Otherwise, the Portal component would break SSR and its data fetching. | ||
| // Portal would call Ark UI's useEnvironmentContext hook, which tries to access `document` that doesn't exist on the server. | ||
| return | ||
| } | ||
|
|
There was a problem hiding this comment.
Instead of having this one off logic, should we create a component..
Also there is this new that might fit the bill to wrap the render portion of this render. Not that I really want to solidify the Island component, but it's there.
There was a problem hiding this comment.
Just trying to understand the behavior here - since the portal components are closed by default there shouldn't be any performance impact, correct?
There was a problem hiding this comment.
@unandyala Yeah I think there shouldn't be any performance impact. But what performance-specific scenario or metric were you thinking of?
There was a problem hiding this comment.
@vmarta There are a few components that is using Portal in its render. Would this happen whenever Portal is used?
There was a problem hiding this comment.
@alexvuong yeah, I'm going to replace all usage of Portal with our own version, which will render only on the client side.
| @@ -1,4 +1,6 @@ | |||
| ## v4.0.0-extensibility-preview.5 (May 06, 2025) | |||
| - Fix data-fetching regression with SSR rendering [#2785](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2785) | |||
There was a problem hiding this comment.
Similar comment as above, but it would be nice to angle this in a positive light since "regression" almost implies we unintentionally broke something and released it and fixed it. Since we didn't release it we might be able to say "Account for rending components that use reacts useInsertionEffect hook on the server"
The setting of useInsertionEffect to a no-op had to be done in another file.
I didn't want to add test to react-rendering.test.js because my code change isn't much for testing. So I decided to add tests for another file instead.
| expect(parseFloat(timer.metrics[0].duration)).toBeGreaterThan(0) | ||
| }) | ||
|
|
||
| test('warns when mark name is undefined', () => { |
There was a problem hiding this comment.
To meet the test coverage, I decided to add tests for this performance util. Yes, it's not related to the PR. But there isn't much changes in the react-rendering.js file that's worthy for testing.
…822712@) (#2785) * Remove call to withLegacyGetProps * Debugging * Revert change to AppConfig * Add todos * Try commenting out the problematic Chakra hooks Including those components that also call `useDisclosure`. * Revert "Try commenting out the problematic Chakra hooks" This reverts commit 970b97e. * Create a safe version of useDisclosure * Fix react-ssr-prepass lack of no-op for useInsertionEffect * Don't render Portal on server side * Show header again * Revert "Create a safe version of useDisclosure" This reverts commit 669f2eb. * This Portal is already rendered only on client side * Render nothing on server side * Clean up code * Remove unnecessary category check * Add comment * Update changelog files * Existing tests are now passing again * Revert change to the skeleton * Add a comment closer to the prepass call The setting of useInsertionEffect to a no-op had to be done in another file. * Create a safe version of Portal * Update changelog files * Add comments to clarify * Check first whether useInsertionEffect is defined or not * Add more tests to pass test coverage I didn't want to add test to react-rendering.test.js because my code change isn't much for testing. So I decided to add tests for another file instead. * Add comment
Brought back the useInsertionEffect no-op from PR #2785.
* update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/components/product-view-modal/bundle.jsx * refactor translations in src/components/product-view-modal/index.jsx * refactor translations in src/components/promo-code/index.jsx * refactor translations in src/components/promo-popover/index.jsx * update refactoring-checklist.md * refactor translations in src/components/recommended-products/index.jsx * refactor translations in src/components/register/index.jsx * refactor translations in src/components/reset-password/index.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/components/search/index.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/components/search/partials/recent-searches.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/components/social-login/index.jsx * update refactoring-checklist.md * refactor translations in src/components/store-locator-modal/store-locator-content.jsx * refactor translations in src/components/store-locator-modal/store-locator-input.jsx * refactor translations in src/components/store-locator-modal/stores-list.jsx * refactor translations in src/components/swatch-group/index.jsx * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/components/toggle-card/index.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/components/with-registration/index.jsx * update refactoring-checklist.md * refactor translations in src/pages/account/addresses.jsx * update refactoring-checklist.md * refactor translations in src/pages/account/index.jsx * refactor translations in src/pages/account/order-detail.jsx * refactor translations in src/pages/account/order-history.jsx * update refactoring-checklist.md * refactor translations in src/pages/account/profile.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/account/wishlist/index.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * update refactoring-checklist.md * refactor translations in src/pages/account/wishlist/partials/wishlist-primary-action.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/cart/hooks/use-cart-operations.js * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/cart/partials/cart-cta.jsx * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/cart/partials/cart-recommendations.jsx * refactor translations in src/pages/cart/partials/cart-secondary-button-group.jsx * refactor translations in src/pages/cart/partials/cart-skeleton.jsx * update refactoring-checklist.md * refactor translations in src/pages/cart/partials/cart-title.jsx * refactor translations in src/pages/cart/partials/empty-cart.jsx * refactor translations in src/pages/checkout/confirmation.jsx * update refactoring-checklist.md * refactor translations in src/pages/checkout/index.jsx * refactor translations in src/pages/checkout/partials/cc-radio-group.jsx * refactor translations in src/pages/checkout/partials/checkout-footer.jsx * refactor translations in src/pages/checkout/partials/checkout-header.jsx * update refactoring-checklist.md * refactor translations in src/pages/checkout/partials/contact-info.jsx * refactor translations in src/pages/checkout/partials/login-state.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/checkout/partials/payment-form.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/checkout/partials/payment.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/checkout/partials/shipping-address-selection.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/checkout/partials/shipping-address.jsx 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor translations in src/pages/checkout/partials/shipping-options.jsx * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/home/index.jsx * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/login/index.jsx * refactor translations in src/pages/page-not-found/index.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/product-detail/partials/information-accordion.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/product-detail/partials/recommended-products-section.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/empty-results.jsx * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/category-links.jsx * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/color-refinements.jsx * refactor translations in src/pages/product-list/partials/page-header.jsx * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/product-list-header.jsx * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/product-list-title.jsx * refactor translations in src/pages/product-list/partials/radio-refinements.jsx * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/pages/product-list/partials/selected-refinements.jsx * refactor translations in src/pages/product-list/partials/size-refinements.jsx * refactor translations in src/pages/product-list/partials/sort.jsx * refactor translations in src/pages/registration/index.jsx * refactor translations in src/pages/reset-password/index.jsx * refactor translations in src/pages/reset-password/reset-password-landing.jsx * refactor translations in src/pages/social-login-redirect/index.jsx * update refactoring-checklist.md * lint * remove scripts * fix test * W-19151166 fix product view modal cart (#2924) * fix product view modal on cart page * [V4] Make sure that the server side rendering works again (@W-19159606@) (#2938) * Fix server side rendering Brought back the useInsertionEffect no-op from PR #2785. * Bring back this comment * Update CHANGELOG.md * build translations * Revert "remove scripts" This reverts commit 39705be. * refactor translations in src/hooks/use-dnt-notification.js * refactor translations in src/hooks/use-add-to-cart-modal.js * refactor translations in src/components/register/index.jsx * refactor translations in src/components/item-variant/item-image.jsx * refactor translations in src/components/item-variant/item-attributes.jsx * refactor translations in src/components/email-confirmation/index.jsx * refactor translations in src/components/action-card/index.jsx * refactor translations in src/pages/product-list/partials/product-list-header.jsx * minor fixes * update translations readme * refactor translations in src/components/display-price/current-price.jsx * refactor translations in src/components/display-price/list-price.jsx * refactor translations in src/components/forms/address-fields.jsx * refactor translations in src/components/forms/profile-fields.jsx * update refactoring-checklist.md * refactor translations in src/components/list-menu/list-menu.jsx * refactor translations in src/components/locale-text/index.jsx * refactor translations in src/components/offline-banner/index.jsx * refactor translations in src/components/order-summary/index.jsx * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * update refactoring-checklist.md * refactor translations in src/hooks/use-add-to-cart-modal.js * refactor translations in src/hooks/use-derived-product.js * refactor translations in src/hooks/use-product-view-modal.js * refactor translations in src/page-designer/layouts/carousel/index.jsx * refactor translations in src/pages/checkout/partials/checkout-footer.jsx * refactor translations in src/pages/checkout/partials/checkout-header.jsx * refactor translations in src/pages/home/index.jsx * refactor translations in src/pages/page-not-found/index.jsx * refactor translations in src/pages/product-list/partials/color-refinements.jsx * refactor translations in src/pages/product-list/partials/empty-results.jsx * refactor translations in src/pages/product-list/partials/sort.jsx * refactor translations in src/components/action-card/index.jsx * refactor translations in src/components/action-card/index.jsx * refactor translations in src/components/action-card/index.jsx * refactor translations in src/components/display-price/current-price.jsx useMemo * refactor translations in src/components/display-price/list-price.jsx useMemo * refactor translations in src/components/drawer-menu/drawer-menu.jsx useMemo * refactor translations useMemo in src/components/email-confirmation/index.jsx * refactor translations useMemo in src/components/field/index.jsx * refactor translations useMemo in src/components/footer/index.jsx * refactor translations useMemo in src/components/forms/address-fields.jsx * refactor translations useMemo in src/components/forms/credit-card-fields.jsx * refactor translations with useMemo in src/components/forms/form-action-buttons.jsx * refactor translations in src/components/forms/login-fields.jsx with useMemo * refactor translations in src/components/forms/password-requirements.jsx with useMemo * refactor translations in src/components/forms/profile-fields.jsx with useMemo * refactor translations in src/components/forms/promo-code-fields.jsx with useMemo * refactor translations in src/components/forms/update-password-fields.jsx with useMemo * refactor translations in src/components/forms/useLoginFields.jsx with useMemo * refactor translations with useMemo in src/components/forms/useProfileFields.jsx * refactor translations with useMemo in src/components/forms/usePromoCodeFields.jsx * refactor translations with useMemo in src/components/forms/useRegistrationFields.jsx * refactor translations in src/components/forms/useResetPasswordFields.jsx with useMemo * refactor translations in src/components/forms/useUpdatePasswordFields.jsx with useMemo * refactor translations in src/components/header/index.jsx with useMemo * refactor translations in src/components/item-variant/item-attributes.jsx with useMemo * refactor translations in src/components/item-variant/item-image.jsx useMemo * refactor translations in src/components/item-variant/item-price.jsx useMemo * refactor translations in src/components/list-menu/list-menu.jsx useMemo * refactor translations in src/components/offline-banner/index.jsx useMemo * refactor translations in src/components/order-summary/index.jsx useMemo * refactor translations in src/components/pagination/index.jsx useMemo * refactor translations in src/components/passwordless-login/index.jsx with useMemo * refactor translations in src/components/product-scroller/index.jsx useMemo * refactor translations in src/components/product-tile/index.jsx useMemo * refactor translations in src/components/product-view-modal/bundle.jsx - useMemo * refactor translations in src/components/product-view-modal/index.jsx - useMemo * refactor translations in src/components/promo-code/index.jsx - useMemo * refactor translations in src/components/promo-popover/index.jsx - useMemo * refactor translations useMemo in src/components/quantity-picker/index.jsx * refactor translations useMemo in src/components/recommended-products/index.jsx * refactor translations useMemo in src/components/register/index.jsx * refactor translations useMemo in src/components/reset-password/index.jsx * refactor translations in src/components/search/index.jsx with useMemo * refactor translations in src/components/search/partials/recent-searches.jsx with useMemo * refactor translations in src/components/social-login/index.jsx with useMemo * refactor translations useMemo in src/components/store-locator-modal/store-locator-content.jsx * refactor translations useMemo in src/components/store-locator-modal/store-locator-input.jsx * refactor translations useMemo in src/components/store-locator-modal/stores-list.jsx * refactor translations useMemo in src/components/swatch-group/index.jsx * refactor translations useMemo in src/components/toggle-card/index.jsx * refactor translations useMemo in src/components/with-registration/index.jsx * refactor translations useMemo in src/hooks/use-add-to-cart-modal.js * refactor translations useMemo in src/hooks/use-dnt-notification.js * refactor translations useMemo in src/hooks/use-product-view-modal.js * refactor translations useMemo in src/page-designer/layouts/carousel/index.jsx * refactor translations useMemo in src/pages/account/addresses.jsx * refactor translations useMemo in src/pages/account/order-detail.jsx * refactor translations useMemo in src/pages/account/order-history.jsx * refactor translations useMemo in src/pages/account/profile.jsx * refactor translations useMemo in src/pages/account/wishlist/index.jsx * refactor translations with useMemo in src/pages/account/wishlist/partials/wishlist-primary-action.jsx * refactor translations with useMemo in src/pages/account/wishlist/partials/wishlist-secondary-button-group.jsx * refactor translations with useMemo in src/pages/cart/hooks/use-cart-operations.js * refactor translations with useMemo in src/pages/cart/partials/cart-cta.jsx * refactor translations with useMemo in src/pages/cart/partials/cart-recommendations.jsx * refactor translations with useMemo in src/pages/cart/partials/cart-secondary-button-group.jsx * refactor translations with useMemo in src/pages/cart/partials/cart-skeleton.jsx * refactor translations with useMemo in src/pages/cart/partials/cart-title.jsx * refactor translations with useMemo in src/pages/cart/partials/empty-cart.jsx * refactor translations with useMemo in src/pages/checkout/confirmation.jsx * refactor translations with useMemo in src/pages/checkout/index.jsx * lint * lint * fix tests * fix tests * revert some changes * revert * remove automation scripts * commit new translations * pr feedback * fix missing descriptions * [V4] Update config parsing such that private slas client works again (@W-19144103@) (#2925) * Attempt at fixing private slas client It works now. It requires tweaking the existing config parsing code. * Clean up code * Further work on migrating to default.js * Revert to public slas client * Empty commit * Fix linting errors * Fix the config in the test file * Move these config properties according to alphabetical order * W-19137621 Fix use-auth-modal Unit Tests (#2952) * fix unit for use-auth-modal * remove jest timeout * lint fix --------- Co-authored-by: Kevin He <kevin.he@salesforce.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Alex Vuong <alex.vuong@salesforce.com> Co-authored-by: Vincent Marta <vmarta@salesforce.com> Co-authored-by: sf-jie-dai <jie.dai@salesforce.com>
In the chakra v3 branch, we've observed a data-fetching regression with the server rendering, where most of the queries were not being run. Only the queries in the very top level components (like App, AppConfig) would get run.
It turns out that
react-ssr-prepassand Chakra's use of React 18'suseInsertionEffectare not compatible. When prepass is walking through the component tree, it needs to ignore the useInsertionEffect.. similar to how it's already ignoring useEffect and useLayoutEffect.As a workaround, we've set useInsertionEffect to a no-op from within our SDK.
There's also another similar issue where Chakra's Portal component tries to access
documentwhich does not exist on the server side. Now we've created our own safe version of Portal that runs only on the client side.Remaining todos:
How to test-drive the PR
If you want to go further, you can also verify that there is no more error caught during prepass.
npm run start:inspectand make sure that you see the correct server logs through your Chrome browser.