この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
このガイドでは、PWA Kit アプリケーションをバージョン 2.10.0 にアップグレードし、ハイブリッド認証を実装する方法について説明します。PWA Kit 2.10.0 リリースでは、ハイブリッド認証との互換性や @salesforce/commerce-sdk-react パッケージとの統合など、重要な変更が導入されています。PWA Kit v2.10.0 は、SLAS パブリッククライアントのみをサポートします。詳細については、pwa-kit GitHub diff 全体を確認して、コード変更について理解を深めてください。
ハイブリッド認証の導入をこれから開始する新規のお客様は、PWA Kit v3.10.0 以降を使用して開始する必要があります。PWA Kit v3 でハイブリッド認証を実装する方法については、ハイブリッド実装ガイドを参照してください。
Important
アップグレードを開始する前に、以下を満たしていることを確認してください。
最も重要な更新は、新しい Commerce SDK React 認証システムの導入です。
1{
2 "@salesforce/commerce-sdk-react": "^3.4.0",
3 "@tanstack/react-query": "4.28.0"
4}現在の Node.js と npm のバージョンを確認します。
1node --version
2npm --versionNode.js バージョンが 18.x 未満の場合は、先にアップグレードしてください。npm のバージョンが 9.x 未満の場合も、先にアップグレードしてください。
1{
2 "engines": {
3 "node": "^14.0.0 || ^16.0.0 || ^18.0.0 || ^20.0.0",
4 "npm": "^6.14.4 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
5 }
6}1{
2 "engines": {
3 "node": "^18.0.0 || ^20.0.0",
4 "npm": "^9.0.0 || ^10.0.0"
5 }
6}package.json ファイルを開き、次のセクションを更新します。
"engines" セクションを更新します。
1{
2 "engines": {
3 "node": "^18.0.0 || ^20.0.0",
4 "npm": "^9.0.0 || ^10.0.0"
5 }
6}"devDependencies" セクションを更新して、次の依存関係を追加またはバージョン更新します。
1{
2 "devDependencies": {
3 "@salesforce/commerce-sdk-react": "^3.4.0",
4 "@tanstack/react-query": "4.28.0",
5 "commerce-sdk-isomorphic": "^3.3.0",
6 "jwt-decode": "^4.0.0",
7 "pwa-kit-dev": "2.10.0",
8 "pwa-kit-react-sdk": "2.10.0",
9 "pwa-kit-runtime": "2.10.0",
10 "@testing-library/react": "^12.1.5",
11 "@testing-library/react-hooks": "^8.0.1",
12 "@testing-library/user-event": "^14.4.3",
13 "ajv": "^8.17.1",
14 "ajv-keywords": "^5.1.0"
15 }
16}package.json ファイルを保存します。
新しい依存関係をクリーンインストールします。
1rm -rf node_modules package-lock.json
2npm install@testing-library/* の依存関係は任意です。これらが必要になるのは、react-testing-library を使用して単体テストを実装している場合のみです。
Note
config/default.js ファイルを開きます。
ssrFunctionNodeVersion を含む行を見つけて更新します。
1// Change this line:
2ssrFunctionNodeVersion: '18.x', // Or 20.x if you upgraded to Node 20.config/default.js ファイルを保存します。
新しい Commerce SDK React システムを使用するように、認証実装を更新します。
古い認証ファイルを削除します。
1rm app/commerce-api/auth.js
2rm app/commerce-api/pkce.jsutils.js ファイルを更新します。
1# Open app/commerce-api/utils.js and remove authentication-related functionsファイルの先頭から、次の import を削除します。
1// REMOVE these lines from app/commerce-api/utils.js
2import jwtDecode from "jwt-decode";
3import { refreshTokenGuestStorageKey, refreshTokenRegisteredStorageKey } from "./constants";app/commerce-api/utils.js から、次の関数を削除します。
1// REMOVE these functions from app/commerce-api/utils.js
2export function isTokenExpired(token) { ... }
3export function createGetTokenBody(urlString, slasCallbackEndpoint, codeVerifier) { ... }
4export function hasSFRAAuthStateChanged(storage, storageCopy) { ... }keysToCamel や createOcapiFetch など、その他のユーティリティ関数は引き続き必要なため、そのまま残します。
useCustomer フックを更新します。app/hooks/use-customer.js ファイルを開き、認証メソッドを更新します。
1// Add these new imports at the top of the file:
2import { AuthHelpers } from '@salesforce/commerce-sdk-react'
3import { useAuthHelper } from '@salesforce/commerce-sdk-react'
4
5// Find the login and logout methods in useCustomer hook and update them:
6
7// Old implementation (v2.9.x)
8const login = async (credentials) => {
9 const auth = new Auth();
10 await auth.login(credentials);
11 // ... rest of login logic
12};
13
14const logout = async () => {
15 const auth = new Auth();
16 await auth.logout();
17 // ... rest of logout logic
18};
19
20// New implementation (v2.10.0)
21export default function useCustomer() {
22 const api = useCommerceAPI()
23 const {customer, setCustomer} = useContext(CustomerContext)
24
25 const login = useAuthHelper(AuthHelpers.LoginRegisteredUserB2C)
26 const logout = useAuthHelper(AuthHelpers.Logout)
27
28 const getSkeletonCustomer = () => {
29 return {
30 customerId: api.auth.get('customer_id'),
31 authType: api.auth.get('customer_type')
32 }
33 }
34
35 const self = useMemo(() => {
36 return {
37 ... customer,
38
39 // Other useCustomer hook functions
40 ...
41 // The login method is now handled by the useAuthHelper hook
42 async login(credentials) {
43 await api.auth.ready()
44 let skeletonCustomer = getSkeletonCustomer()
45 if (credentials) {
46 await login.mutateAsync({
47 username: credentials.email,
48 password: credentials.password
49 })
50 skeletonCustomer = getSkeletonCustomer()
51 }
52 // ... rest of login logic
53 },
54
55 async logout() {
56 await logout.mutateAsync()
57 await api.auth.ready()
58 const skeletonCustomer = getSkeletonCustomer()
59 setCustomer(skeletonCustomer)
60 // ... rest of logout logic
61 }
62 }
63 })useCustomer フックは、新しい Commerce SDK React の認証メソッドを使用するようになりました。既存のログインコンポーネントと登録コンポーネントは、これまでと同じ login() 関数と register() 関数を呼び出すため、変更する必要はありません。
Note
Commerce API の実装は、@salesforce/commerce-sdk-react パッケージの新しい transformSDKClient ユーティリティを使用するように大幅に更新されています。詳細については、パッケージの README.md を参照してください。
Note
app/commerce-api/index.js ファイルを開きます。
ファイルの先頭にある import を更新します。
1// Remove these old imports:
2import Auth from "./auth";
3import { isError } from "./utils";
4
5// Add these new imports:
6import Auth from "@salesforce/commerce-sdk-react/auth";
7import { transformSDKClient } from "@salesforce/commerce-sdk-react/utils";
8import { DWSID_HEADER_KEY } from "./constants";auth モジュールのインスタンス化を更新します。
1// Old implementation (v2.9.x)
2
3this._config = { proxy, ...restConfig };
4
5this.auth = new Auth(this); // Update this with new authConfig次の新しいコードに置き換えます。
1// Old implementation (v2.9.x)
2
3this._config = { proxy, ...restConfig };
4
5// Add new authConfig object
6this._authConfig = {
7 redirectURI: `${getAppOrigin()}/callback`,
8 proxy,
9 locale: this._config.locale,
10 currency: this._config.currency,
11 ...this._config.parameters,
12 ...this._config.headers,
13};
14
15this.auth = new Auth(this._authConfig); // pass authConfig as param to Auth class constructor.SDK クライアントがインスタンス化されているセクション (100 行目から 150 行目付近) を見つけて、SDK インスタンス化ロジック全体を置き換えます。 次の古いコードを削除します。
1// Old implementation (v2.9.x) - using Proxy
2const SdkClass = apiConfigs[key].api;
3self._sdkInstances = {
4 ...self._sdkInstances,
5 [key]: new Proxy(new SdkClass(this._config), {
6 get: function (obj, prop) {
7 // ... proxy implementation
8 },
9 }),
10};次の新しいコードに置き換えます。
1// New implementation (v2.10.0) - using transformSDKClient
2const SdkClass = apiConfigs[key].api;
3const sdkClient = new SdkClass(this._config);
4self._sdkInstances = {
5 ...self._sdkInstances,
6 [key]: transformSDKClient(sdkClient, {
7 props: this._config,
8 transformer: async (_, methodName, options) => {
9 const { fetchOptions = {} } = options;
10 if (fetchOptions.ignoreHooks) {
11 return options;
12 }
13
14 const { locale, currency } = this._config;
15
16 // Inject the locale and currency to the API call via its parameters.
17 const { sendLocale = true, sendCurrency = false } = apiConfigs[key];
18
19 const includeGlobalLocale = Array.isArray(sendLocale)
20 ? sendLocale.includes(methodName)
21 : !!sendLocale;
22
23 const includeGlobalCurrency = Array.isArray(sendCurrency)
24 ? sendCurrency.includes(methodName)
25 : !!sendCurrency;
26
27 fetchOptions["parameters"] = {
28 ...(includeGlobalLocale ? { locale } : {}),
29 ...(includeGlobalCurrency ? { currency } : {}),
30 ...fetchOptions?.parameters,
31 };
32
33 // Handle auth logic (replacing willSendRequest functionality)
34 let dwsidHeader = {};
35 const dwsid = self.auth.get("dwsid");
36 if (dwsid) {
37 dwsidHeader = {
38 [DWSID_HEADER_KEY]: dwsid,
39 };
40 }
41
42 // Special handling for auth methods
43 if (
44 methodName === "authenticateCustomer" ||
45 methodName === "authorizeCustomer" ||
46 methodName === "getAccessToken"
47 ) {
48 return {
49 ...options.parameters,
50 headers: {
51 ...options.headers,
52 ...fetchOptions.headers,
53 },
54 credentials: "same-origin", // Required for SLAS calls to set dwsid cookie
55 ...fetchOptions,
56 };
57 }
58
59 const { access_token: token } = await self.auth.ready();
60 return {
61 ...options,
62 headers: {
63 ...options.headers,
64 ...dwsidHeader,
65 Authorization: `Bearer ${token}`,
66 },
67 // Add cache breaker for Storefront Preview
68 parameters: {
69 ...options.parameters,
70 ...(this.isStorefrontPreview ? { c_cache_breaker: Date.now() } : {}),
71 },
72 };
73 },
74 }),
75};CommerceAPI クラスから、次のメソッドを見つけて削除します。
1// Remove these methods completely:
2async willSendRequest(methodName, ...params) {
3 // ... entire method
4}
5
6didReceiveResponse(response, args) {
7 // ... entire method
8}定数ファイルを更新します。
app/commerce-api/constants.js に新しい定数を追加します。
1export const DWSID_HEADER_KEY = "sfdc_dwsid";Commerce API コンテキストは、Commerce SDK React および React Query と統合するように更新されています。
Note
app/commerce-api/contexts.js ファイルを開きます。
ファイルの先頭に、次の import を追加します。
1import { CommerceApiProvider as CommerceSDKReactProvider } from "@salesforce/commerce-sdk-react";
2import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3import { getAppOrigin } from "pwa-kit-react-sdk/utils/url";
4import { isServer } from "../../pwa-kit-managed-runtime/utils/utils";import の後に、QueryClient の構成を追加します。
1const queryClientOptions = {
2 queryClientConfig: {
3 defaultOptions: {
4 queries: {
5 retry: false,
6 refetchOnWindowFocus: false,
7 staleTime: 10 * 1000,
8 ...(isServer ? { retryOnMount: false } : {}),
9 },
10 mutations: {
11 retry: false,
12 },
13 },
14 },
15 beforeHydrate: (data) => {
16 const now = Date.now();
17 const updateQueryTimeStamp = ({ state }) => {
18 state.dataUpdatedAt = now;
19 };
20 data?.mutations?.forEach(updateQueryTimeStamp);
21 data?.queries?.forEach(updateQueryTimeStamp);
22 return data;
23 },
24};
25
26const queryClient = new QueryClient(queryClientOptions);既存の CommerceAPIProvider を、次の新しい実装に置き換えます。
1export const CommerceAPIProvider = ({ value, children }) => {
2 const { api, site, locale } = value;
3 const apiClients = api._sdkInstances;
4
5 const { shortCode, clientId, organizationId } = api.getConfig().parameters;
6 const { proxy } = api.getConfig();
7
8 return (
9 <CommerceAPIContext.Provider value={api}>
10 <QueryClientProvider client={queryClient}>
11 <CommerceSDKReactProvider
12 shortCode={shortCode}
13 clientId={clientId}
14 organizationId={organizationId}
15 siteId={site?.id}
16 locale={locale?.id}
17 currency={locale?.preferredCurrency}
18 redirectURI={`${getAppOrigin()}/callback`}
19 proxy={proxy}
20 apiClients={apiClients}
21 disableAuthInit={true}
22 >
23 {children}
24 </CommerceSDKReactProvider>
25 </QueryClientProvider>
26 </CommerceAPIContext.Provider>
27 );
28};app/commerce-api/contexts.js ファイルを保存します。
**重要な変更: ** CommerceAPIProvider で必要な props 構造が変更されました。
Important
app/components/_app-config/index.jsx ファイルを開きます。
CommerceAPIProvider コンポーネントを見つけて更新します。
次のコードを:
1// Old implementation (v2.9.x)
2<CommerceAPIProvider value={locals.api}>次のコードに置き換えます。
1// New implementation (v2.10.0)
2<CommerceAPIProvider value={locals}>app/components/_app-config/index.jsx ファイルを保存します。
app/components/_app/index.jsx ファイルを開きます。
login 呼び出しを削除します。
1// Auth initialization is now handled by calling await self.auth.ready() in commerce-api/index.js
2// Remove this line.
3await api.auth.login();開発サーバーを起動します。
1npm startビルドを実行して、エラーがないことを確認します。
1npm run buildPWA Kit v2.10.0 では、@salesforce/commerce-sdk-react の強力なクエリフックを使用できるようになりました。これらのフックは、ハイブリッドおよび非ハイブリッドの両方の PWA Kit v2.x ストアフロントで、自動キャッシュ、読み込み状態、エラー処理を提供します。ページでの使用方法は次のとおりです。
新しいクエリフックを使用して、最小限の注文リストコンポーネントを作成します。
1import React from "react";
2import { useCustomerOrders } from "@salesforce/commerce-sdk-react";
3import useCustomer from "../../commerce-api/hooks/useCustomer";
4
5const SimpleOrderList = () => {
6 const customer = useCustomer();
7
8 const { data: { data: orders } = {}, isLoading } = useCustomerOrders(
9 { parameters: { customerId: customer?.customerId } },
10 { enabled: !!customer?.customerId },
11 );
12
13 if (isLoading) return <div>Loading orders...</div>;
14
15 return (
16 <div>
17 <h2>My Orders</h2>
18 {orders?.map((order) => (
19 <div key={order.orderNo}>
20 <p>
21 Order #{order.orderNo} - {order.status}
22 </p>
23 <p>Total: ${order.orderTotal}</p>
24 </div>
25 ))}
26 </div>
27 );
28};
29
30export default SimpleOrderList;新しいクエリフックの主なメリットは次のとおりです。