Skip to content

Make API clients injectable in commerce-sdk-react (CommerceApiProvider)#2519

Merged
shethj merged 26 commits intodevelopfrom
feature/commerce-sdk-react-refactor-2
Jun 12, 2025
Merged

Make API clients injectable in commerce-sdk-react (CommerceApiProvider)#2519
shethj merged 26 commits intodevelopfrom
feature/commerce-sdk-react-refactor-2

Conversation

@shethj
Copy link
Contributor

@shethj shethj commented Jun 5, 2025

Description

As a part of the Plugin SLAS to Hybrid Auth transition, we’d like to enable customers using PWA Kit v2.x to take advantage of Hybrid auth capabilities. This requires some changes to CommerceApiProvider in @salesforce/commerce-sdk-react and more changes to integrate commerce-sdk-react in PWA Kit v2.x

This PR implements a refactor to @salesforce/commerce-sdk-react to allow injecting API Clients from the parent project (V2 template in this case) that uses the @salesforce/commerce-sdk-react package as a dependency.
This allows us to continue using the SDK client setup in PWA Kit v2 and also allow customers to take advantage of the new react query hooks and auth improvements we've made in commerce-sdk-react.

Most important, this change paves a simple path for customers to be able to upgrade to future versions of PWA Kit where they can combine use of V2 CommerceAPI and V3's commerce-sdk-react to migrate their storefront components over gradually.

As a side-effect of this change, we also laid foundation and have a working POC for fully decoupling the SDK Client instantiation from commerce-sdk-react which allows us to move commerce-sdk-isomorphic as a dev-dependency of the react SDK and eventually boost performance by reducing bundle sizes via tree-shaking.

NOTE: Tree shaking improvements requires implementing ESM support for commerce-sdk-isomorphic.

Overall Goals for this work

To summarize the description above we want to achieve the following:

  • Enable Hybrid Auth on PWA Kit v2.x [✅]
  • Seamless integration of commerce-sdk-react with PWA Kit v2.x
  • Give customers a clean upgrade path to v3+ [✅]
  • Allows easier distribution of new features going forward [✅]
  • Allows a mix of sdk and react-query usage in PWA Kit v2.x [✅]
  • Decouple SDK initialization from commerce-sdk-react, making SDK clients injectable into CommerceApiProvider (commerce-sdk-react)
  • Update commerce-sdk-react to accept SDK client instances as in input via props [✅]
  • SDK Optimization: Only initialize the clients your template actually uses [⚠️ Breaking Change to V3 template]
  • Enable tree shaking to reduce bundle size [⚠️Breaking change to V3 template]
    • Requires ESM support in commerce-sdk-isomorphic

The items marked ✅ are the ones we want to merge for now while the items marked ⚠️ involve breaking changes to the V3 retail template and also require work in the isomorphic-sdk.

This PR includes changes required to merge in items marked as ✅.
This gives us significant improvements while avoiding any breaking changes.
The items marked ⚠️ have already been implemented as a POC in a different PR but will be held off until PWA Kit v4 where we have capacity to include breaking changes. See this PR

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Breaking change (could cause existing functionality to not work as expected)
  • Other changes (non-breaking changes that does not fit any of the above)

Breaking changes include:

  • Removing a public function or component or prop
  • Adding a required argument to a function
  • Changing the data type of a function parameter or return value
  • Adding a new peer dependency to package.json

Changes

  • Introduced an optional prop apiClients to CommerceApiProvider
  • Use apiClients from the props if passed in else fallback to manually instantiating all SDKs like we already do [This fallback piece will be removed when we optimize for tree-shaking via the ⚠️ marked changes in the description above in v4.]
  • Added a transform proxy to allow internal control over headers, params and other config objects passed to the SDK.
  • Added tests for the transform proxy

Note: Since we made apiClients injectable and optional and customers can choose to instantiate only the SDK classes that they actually use, we need to handle cases where the template might call a query or a mutation hook for SDKs that have not been passed in. This change is in a follow-up PR. See #2539

How to Test-Drive This PR

  • Checkout this branch
  • Run npm start from monorepo root
  • Smoke test the retail app.

Checklists

General

  • Changes are covered by test cases
  • CHANGELOG.md updated with a short description of changes (not required for documentation updates)

Accessibility Compliance

You must check off all items in one of the follow two lists:

  • There are no changes to UI

or...

Localization

  • Changes include a UI text update in the Retail React App (which requires translation)

@cc-prodsec
Copy link
Collaborator

cc-prodsec commented Jun 5, 2025

🎉 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)

@shethj shethj marked this pull request as ready for review June 5, 2025 21:39
@shethj shethj requested a review from a team as a code owner June 5, 2025 21:39
@shethj shethj changed the title Make API clients injectable (no tree-shaking) Make API clients injectable Jun 9, 2025
@shethj shethj changed the title Make API clients injectable Make API clients injectable in commerce-sdk-react (CommerceApiProvider) Jun 9, 2025
Copy link
Contributor

@kevinxh kevinxh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM, can we add some documentation for this feature in the README?

@vmarta
Copy link
Contributor

vmarta commented Jun 11, 2025

First of all, just wanted to say: thank you and great job on this detailed PR description.

For me who isn't following the progress closely, I feel like I now have a better idea of what's going on.

Copy link
Contributor

@vmarta vmarta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments. Other than that, this PR looks good to me 👍

Btw, I did not test with an older pwa kit v2 template. I'm guessing there will be another PR?

},
throwOnBadResponse: true,
fetchOptions
const _defaultTransformer: SDKClientTransformer<Record<string, any>> = (_, _$, options) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 I see the first 2 arguments to this function are not being used. So do we really need them?

Besides, it doesn't look like there's a way for the end user to pass in their own transformer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah v2 integration is in a separate PR.

I see the first 2 arguments to this function are not being used. So do we really need them?

We're not using those arguments now: those 2 are props and methodName but we might need them for some future change. I could convert the props to transformer to be an object with optional properties to make it clear.

Also, we're not accepting a transformer from the end user for now is because they already have props in CommerceApiProvider where they can pass in all the different headers and options and our default transformer and SDK initialization already accepts all that when creating an instance.

However, the transformSDKClient function is open to accept any transformer function so in the future if we come across a use-case to allow the customer to pass in a transformer we can easily do that by simply creating another options prop for commerceApi.

I haven't added that today because I don't see a direct use-case for that right now.

Comment on lines +231 to +235
export type SDKClientTransformer<T> = (
params: T,
methodName: string,
options: any
) => any | Promise<any>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see in the default transformer, it looks like the return object is like options but with some overrides/additions. If that's the case, can we make the type clearer?

Suggested change
export type SDKClientTransformer<T> = (
params: T,
methodName: string,
options: any
) => any | Promise<any>
export type SDKClientTransformer<T> = (
params: T,
methodName: string,
options: SomeOptions
) => SomeOptions | Promise<SomeOptions>

@shethj shethj merged commit 0ae61e0 into develop Jun 12, 2025
35 checks passed
@shethj shethj deleted the feature/commerce-sdk-react-refactor-2 branch July 16, 2025 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants