升級至 v3

從 v3 開始,現在可以將 @salesforce/retail-react-app 新增為 npm 相依項目,並在專案中啟用範本擴充性,來使用 @salesforce/retail-react-app 更新。

這份指南說明如何將 PWA Kit 專案從 v2.7.x 更新至 v3.0.0。

新功能 

我們為 PWA Kit v3 增加了許多新功能,包括:

⚛️ 必要

  • getProps 重大改變
  • 主要資產庫更新,包括 React 18Node 18Chakra 2 等的支援

🔨 選擇性:範本擴充性 — 大幅減少您專案的程式碼足跡,並降低開發辛勞、擁有成本和未來升級煩惱。如需更多詳細資料,請參閱 Template Extensibility (範本擴充性) 指南!

🪝 選擇性: @salesforce/commerce-sdk-react「Hook」整合 — 讓 API 呼叫與專案實作脫鉤,允許 API 呼叫升級為 npm 資產庫相依項目,並可經由 TanStack Query 引進許多優秀功能 (包括狀態管理和其他功能)。請參閱 Commerce SDK React 文件,立即開始使用!

必要的變更 

新的 SDK 套件 

PWA Kit SDK 已移至 @salesforce NPM 組織。若要升級至 v3,請安裝新的套件,並替換以下套件的所有匯入陳述式:

  • pwa-kit-react-sdk -> @salesforce/pwa-kit-react-sdk@^3
  • pwa-kit-runtime -> @salesforce/pwa-kit-runtime@^3
  • pwa-kit-dev -> @salesforce/pwa-kit-dev@^3
  • pwa-kit-create-app -> @salesforce/pwa-kit-create-app@^3
  • retail-react-app -> @salesforce/retail-react-app@^3

getProps 的重大變更 

從 v3.0.0 開始,PWA Kit 引進了新的資料擷取策略 withReactQuery。此策略使用 react-query 庫,可讓您編寫 React Hook,以同構方式擷取資料。與 getProps 不同,您不再需要為用戶端和伺服器端重複資料擷取邏輯。在此版本中,@salesforce/retail-react-app 預設使用由 react-query 支援的 @salesforce/commerce-sdk-react

1// app/components/_app-config/index.jsx
2
3import { withLegacyGetProps } from "@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-legacy-get-props";
4
5const AppConfig = ({ children }) => {
6  return <div>My AppConfig</div>;
7};
8
9export default withLegacyGetProps(AppConfig);
  • 您可以同時使用 withReactQuerywithLegacyGetProps
  • getPropsshouldGetProps 已從 Retail React App 頁面的預設範本中移除,但未棄用。對這些方法的長期支援仍然存在。

Note

套件相依性升級 

請變更 package.json 中的相依項目,如下所示。從 peerDependencies 中刪除 @chakra-ui/system,並將其包含在 dependenciesdevDependencies 下。

1"@chakra-ui/icons": "^2.0.19",
2"@chakra-ui/react": "^2.6.0",
3"@chakra-ui/skip-nav": "^2.0.15",
4"@chakra-ui/system": "^2.5.6",
5"framer-motion": "^10.12.9",
6"react": "^18.2.0",
7"react-dom": "^18.2.0",
8"react-hook-form": "^7.43.9"

更新 package.json 中的引擎,以支援 Node 18 和 npm 9。

1"engines": {`
2    "node": "^18.0.0",`
3    "npm": "^8.0.0 || ^9.0.0"`
4}

使用 npm i 重新安裝專案的相依項目。

選擇性:使用範本擴充性 

從 v2.7.x 遷移到 v3.x 時,可以選擇是否使用範本擴充性。要從中受益,您必須從 @salesforce/retail-react-app (或將來的其他可擴充範本) 匯入至少一個檔案。

之後,請考量您從透過 npx pwa-kit-create-app@2.x 產生的原始專案中,已經修改了多少檔案。有些客戶擁有大量 (可能數百個) 檔案,但即便如此,其中大部分都是未經修改的。這些未修改過的檔案是從 @salesforce/retail-react-app 匯入的良好候選項目,但我們建議您小心地逐步執行這個程序。@salesforce/retail-react-app 中的許多檔案都很相似,但自 PWA Kit Retail React App v2.x 以來,其原先狀態已經發生改變。特別是,@salesforce/commerce-sdk-react 整合 (稍後將詳細介紹遷移細節) 導致大量檔案在匯入和檔案結構方面發生了變化,應用程式中移除了整個 commerce-api 目錄。

當您遷移專案以使用範本擴充性時,請注意,PWA Kit SDK 2.x 版本和透過 npx pwa-kit-create-app@2.x 產生的專案不依賴 @salesforce/commerce-sdk-react,但較新的程式碼 @salesforce/retail-react-app@^1.x 則大量使用此資產庫,會觸及並變更許多檔案。若要感受一下改變的幅度,您可以到此 Github diff https://github.com/SalesforceCommerceCloud/pwa-kit/compare/release-2.7.x…release-3.0.x?diff=unified#files_bucket 比較 release-2.7.xrelease-3.0.x,搜尋 @salesforce/commerce-sdk-react,並記下所有加入此匯入的新增項目。

Note

如果您的應用程式嘗試與 2.x 版本 (包含 app/commerce-api 目錄) 共用程式碼,則可能會在套件中新增不必要的程式碼,因為該程式碼 (以兩種截然不同的形式) 同時存在於 commerce-api 資料夾和 @salesforce/commerce-sdk-react npm 模組中。

Warning

選擇性:使用 commerce-sdk-react Hook 庫 

從 v3.0.0 開始,PWA Kit 使用不同的擷取策略 withReactQuery。此策略使用 react-query 資產庫,並在 SSR 轉譯通道中啟用查詢。@salesforce/retail-react-app 使用 @salesforce/commerce-sdk-react,由 react-query 支援。

為了讓 Hook 在伺服器端運作,您需要使用新的高階元件 withReactQuery 包住您的 AppConfig 元件。

作為遷移到 ReactQuery 當作預設擷取策略的一部分,@salesforce/retail-react-app@^1 需要進行變更,以確保舊版 getProps() 呼叫可以繼續運作。

Warning

1// app/components/_app-config/index.jsx
2
3import { CommerceApiProvider } from "@salesforce/commerce-sdk-react";
4import { withReactQuery } from "@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query";
5
6const AppConfig = ({ children }) => {
7  return (
8    <CommerceApiProvider
9      clientId="12345678-1234-1234-1234-123412341234"
10      organizationId="f_ecom_aaaa_001"
11      proxy="localhost:3000/mobify/proxy/api"
12      redirectURI="localhost:3000/callback"
13      siteId="RefArch"
14      shortCode="12345678"
15      locale="en-US"
16      currency="USD"
17    >
18      {children}
19    </CommerceApiProvider>
20  );
21};
22
23export default withReactQuery(AppConfig);

疑難排解和最佳化 

完成上述相依性升級後,您可能會在專案中遇到與下列程式庫相關的問題。在以下各節中,我們提出了化解這些問題的解決方案。您的專案細節會有所不同,建議的解決方案應被視為指導方針,而不是絕對的規則。

升級 react-hook-form 

針對 react-hook-form 遷移,請閱讀此處的 react-hook-form 官方文件。在 PWA 專案中,有兩個地方需要變更:

  1. 由於 errors 物件已移至 formState 物件,因此請將表單 errors 物件移至 app/components/forms/ 中 Hook 的另一層解構層。
1// app/components/forms/useAddressFields.jsx
2
3    //before
4    export default function useAddressFields({form: {watch, control, errors}, prefix = ''}) {
5
6    //after
7    export default function useAddressFields({
8        form: {
9            watch,
10            control,
11            formState: {errors}
12        },
13        prefix = ''
14    })
  1. Controller 中的轉譯 Prop 移入 field Prop 中。Render 的回呼簽章會傳回一個包含 field fieldState 的物件。
1// app/components/field/index.jsx
2
3    // before
4    <Controller
5        name={name}
6        control={control}
7        rules={rules}
8        defaultValue={defaultValue}
9        render={({onChange, value, ref}) => {
10          // other code
11        }}
12    />
13
14    // after
15    <Controller
16        name={name}
17        control={control}
18        rules={rules}
19        defaultValue={defaultValue}
20        render={({field: {onChange, value, ref}}) => {
21          // other code
22        }}
23    />

React 18 Hydration 錯誤 

從 React 18 開始,Hydration 警告會顯示為錯誤,而不是像 React 17 那樣顯示為警告。您需要更新一些程式碼來抑制這些潛在錯誤,防止應用程式因為 Hydration 錯誤而無法建置。修正這些錯誤非常重要,可確保應用程式能夠同構轉譯。發生此錯誤的原因是,伺服器或用戶端之間出現不相符。如果某個元件或頁面是在符合條件時才進行轉譯,則您必須確保在轉譯任何用戶端專屬程式碼之前,已先完成 Hydration。

在您的專案中,建立一個公用程式函式來判斷是否已完成 Hydration。您可以使用 pwa-kit-react-sdkwindow.__HYDRATING__ 提供的內建變數。

1/**
2 * This utility function determines if the app has finished hydration
3 * @return {boolean}
4 */
5export const isHydrated = () =>
6  typeof window !== "undefined" && !window.HYDRATING;

Chakra 2 

如果您的專案使用與 Retail React App 範本不同的 @chakra-ui/react 資產庫元件和 API,請參閱官方的 Chakra 2 遷移文件

Important

為了支援 Chakra 2,針對根據 Retail React App 範本的專案,有一些檔案需要更新:

移除 Accordion 元件中的 allowToggle,因為在 Chakra 2 中不能同時使用 allowMultipleallowToggle

Footer 元件中,已棄用直接從 @chakra-ui/react 匯入 StylesProvider。您必須改由 createStylesContext('Footer') 建立之。

1import { createStylesContext } from "@chakra-ui/react";
2
3const [StylesProvider, useStyles] = createStylesContext("Footer");

@testing-library/react 

在呼叫任何動作之前先設定 userEvent,然後等待使用 userEvent 的單元測試中的動作,因為在 React 測試庫 v14.0.0 中,所有使用者動作都是非同步的,需要在執行使用者動作之前呼叫 setup

舉例來說:

1const user = userEvent.setup()`
2// Import `render`and`screen` from the framework library of your choice.
3// See https://testing-library.com/docs/dom-testing-library/install#wrappers
4render(<MyComponent />)
5
6await user.click(screen.getByRole('button', {name: /click me!/i}))

如需更多詳細資料,請參閱 testing-library 的 userEvent 官方文件。

或者,為了避免在許多單元測試中重複呼叫 setup(),您可以在轉譯測試元件之前,在 app/utils/test-util.js 中設定 userEvent,使它隨轉譯結果一起傳回,如此可讓測試執行使用者動作,而無需呼叫 setup()

1export const renderWithProvider = (children, options) => {
2   // some code here
3   const user = userEvent.setup()
4   const res = render(children, {
5        wrapper: () => (
6            <TestProvidersWithDataAPI {...options?.wrapperProps} locals={locals}>
7                {children}
8            </TestProvidersWithDataAPI>
9        ),
10        ...options
11    })
12    return {user, ...res}
13}
14
15//usage
16test('some test', async () => {
17   const {user} = renderWithProviders(<MyComponent />
18   const button = screen.getByText(/button/)
19   await user.click(button)
20}

Jest-setup 

在 jest-setup 中,有一個模擬相依項目可能會擲出關於 TextDecoder 未在 jest-setup.js. 中定義的錯誤。將以下內容加入 jest-setup.js

1global.TextDecoder = require("util").TextDecoder;

其他改進 

從 PWA Kit SDK 2.x 版或透過 npx pwa-kit-create-app@2.x 產生的專案遷移時,@salesforce/commerce-sdk-react 程式碼已大幅重構,移除了 app/commerce-api/ 目錄。以往處理 API 要求並充當 SDK 的檔案已不再使用,現在改以 @salesforce/commerce-sdk-react 取代該功能。SDK 的 v3 版本與 @salesforce/retail-react-app@^1.x 的第一個版本息息相關,因為 SDK 大量使用此資產庫。

@salesforce/commerce-sdk-react 的實作改變了 Retail React App 中的許多檔案。若要感受一下改變的大小,您可以到此 GitHub diff 比較 release-2.7.xrelease-3.0.x,並搜尋 @salesforce/commerce-sdk-react。在 diff 中,請記下所有包含此匯入的新增項目。