Upgrade to v3

As of v3, it's now possible to consume @salesforce/retail-react-app updates by adding it as an npm dependency and enabling template extensibility in your project.

This guide covers how to update a PWA Kit project from v2.7.x to v3.0.0.

We’ve added lots of new features to PWA Kit v3, including:

🔨 Template extensibility: Greatly reduce your project's code footprint and reduce development toil, cost of ownership, and future upgrade headaches. For more details, see the Template Extensibility guide!

🪝 @salesforce/commerce-sdk-react "hooks" integration: Decouples API calls from a project's implementation, allows API calls to be upgraded as an npm library dependency, and brings along many of the great features (including state management, and others) via TanStack Query. See the the Commerce SDK React docs to get started!

⚛️ Major vendor library updates, including support for React 18, Node 16 / 18, and Chakra 2 and more.

One of the first decisions to make when migrating from v2.7.x to v3.x is whether you want to leverage Template Extensibility. In order to benefit from it, you must import at least one file from @salesforcef/retail-react-app (or another extendable app). You can choose how many files you want to inherit from the base template, but you must commit to importing at least one.

From there, consider how many files you have modified in from the original project that you generated via npx pwa-kit-create-app@2.x. Some customers have large numbers (perhaps hundreds) of files, but even then, a significant number can be unmodified. Those unmodified files are a good candidate for importing from @salesforce/retail-react-app, but we recommend doing this process carefully and gradually. Many files in @salesforce/retail-react-app are similar but have been changed from their previous state in v2.x of the PWA Kit Retail React App. In particular, the @salesforce/commerce-sdk-react integration (migration details covered in more detail later) has caused a large number of files to change in terms of their imports as well as their file structure, removing the entire commerce-api directory from the app, as a starting point that is in itself a significant change.

When migrating a project to use template extensibility, please note that version 2.x of the PWA Kit SDKs and projects generated via npx pwa-kit-create-app@2.x do not have a dependency on @salesforce/commerce-sdk-react whereas the newer code @salesforce/retail-react-app@^1.x makes heavy use of this library, which touches and changes many files. To get a sense of the magnitude of the changes, you can compare release-2.7.xrelease-3.0.x in this Github diff https://github.com/SalesforceCommerceCloud/pwa-kit/compare/release-2.7.x...release-3.0.x?diff=unified#files_bucket and search for @salesforce/commerce-sdk-react and take note of all the additions that add this import.

If your app attempts to share code with version 2.x (which includes the app/commerce-api directory), you risk adding unnecessary code to your bundle where that code exists (in two very different forms) in both the commerce-api folder and the @salesforce/commerce-sdk-react npm module.

As of v3.0.0, PWA Kit uses a different fetch strategy withReactQuery. This strategy leverages the react-query library and enables queries in the SSR rendering pass. The @salesforce/retail-react-app uses @salesforce/commerce-sdk-react which is powered by react-query.

In order for hooks to work on server side, you need to wrap your AppConfig component with the new higher-order component withReactQuery.

As part of the migration to ReactQuery as the default fetch strategy, @salesforce/retail-react-app@^1 a change is required to ensure legacy getProps() calls continue to work.

For those projects trying to upgrade to v3 and continuing to use getProps, wrap your AppConfig component with the withLegacyGetProps component.

You can use both withReactQuery and withLegacyGetProps at the same time.

Change dependencies in package.json as follows

Update engines in package.json to support Node ^16.11 and npm ^9. Remove @chakra-ui/system from peerDependencies in package.json since version 2 is the latest major version of Chakra.

There is a bug nswapi, which is a dependency of jest-environment-jsdom that is not compatible with Chakra 2. It throws an error ':disabled):not([disabled]' is not a valid selector on some of the tests that use the Modal component. This bug only affects unit tests, not browser execution. We use npm 8, and add overrides to enforce the 2.2.2 version of nwsapi package, and npm 7 support is dropped.

Add an overrides property into package.json to enforce the package version:

Reinstall dependencies for your project with npm i.

For the react-hook-form migration, read the react-hook-form official doc here. In the PWA project, there are two places that require changes:

  1. Move form errors object into one more layer of destructing for hooks in app/components/forms/* as errors object has been moved into formState object.

  2. Move the render props in Controller into the field prop. Render's callback signature returns an object that contains field and fieldState.

As of React 18, hydration warnings are surfaced as errors instead of warnings as they had been in React 17. Some code updates were required to suppress these potential errors that prevent the application from building when there are hydration errors. It is essential to fix these errors to ensure the app can render isomorphically. This error occurs because there is a mismatch between server or client. If a component or a page happens to render conditionally, you must make sure that the hydration is finished before rendering any client-specific code.

In your project, create a utility function to determine if the hydration has finished. you can use a built-in variable provided by window.__HYDRATING__ in pwa-kit-react-sdk.

Add this function wherever you use conditional rendering. There are a few places to add the function in a PWA Kit project:

See here.

If you have a browser plugin installed that interferes the DOM rendering, you can get a hydration error in the footer. For example, if you are using the LastPass extension, you can see the error on the Subscribe component in the footer because LastPass takes over the browser's rendering to inject an icon to enable the in-field popup. If this takeover happens during the hydration process, the error shows up. One simple trick you can use without having to use isHydrated() is to switch the order of input components like this:

If your project uses components and APIs from the @chakra-ui/react library that are different than the Retail React App template, review the official Chakra 2 migration docs.

To support Chakra 2, there are a few files that require updates for projects based on the Retail React App template:

Remove allowToggle in Accordion component because allowMultiple and allowToggle can't be used at the same time in Chakra 2.

In the Footer component, importing StylesProvider directly from @chakra-ui/react is deprecated. You must create it via createStylesContext('Footer') instead.

Set up userEvent before calling any action, and await the action in unit tests that uses userEvent because in React testing library v14.0.0, all the user actions are async, and it requires calling setup before performing user actions.

For example:

For more details, see the official docs for userEvent from testing-library.

Alternatively, to avoid repetitively calling setup() in many unit tests, you can set up your userEvent in app/utils/test-util.js right before rendering the test component and return it along with render results so that the test can perform the user actions without having to call setup().

In jest-setup, there is a mock dependency that can throw an error about TextDecoder being undefined in jest-setup.js. Add the following to jest-setup.js:

When migrating from version 2.x of the PWA Kit SDKs or projects generated via npx pwa-kit-create-app@2.x the @salesforce/commerce-sdk-react code has been significantly refactored to remove the app/commerce-api/* directory. Instead of those files handling API request and acting as an SDK @salesforce/commerce-sdk-react supersedes that functionality. The v3 release of the SDKs correlates with the first release of @salesforce/retail-react-app@^1.x because the SDKS use this library a lot.

The implementation of @salesforce/commerce-sdk-react alters many files in the Retail React App. To get a sense of the magnitude of the changes, compare release-2.7.xrelease-3.0.x in this GitHub diff and search for @salesforce/commerce-sdk-react. In the diff, take note of all the additions that add this import.