Atualizar para a v3

A partir da v3, agora é possível obter atualizações do@salesforce/retail-react-app adicionando-o como uma dependência npm e ativando a extensibilidade de modelos em seu projeto.

Este guia explica como atualizar um projeto do PWA Kit da v2.7.x para a v3.0.0.

Novidades 

Adicionamos vários recursos novos ao PWA Kit v3, incluindo:

⚛️ Obrigatório:

  • alteração significativa de getProps
  • Principais atualizações da biblioteca, incluindo suporte para React 18, Node 18, Chakra 2 e muito mais

🔨 Opcional: Extensibilidade de modelos — Diminua consideravelmente o tamanho do código de seu projeto e reduza o trabalho de desenvolvimento, o custo de propriedade e problemas futuros com atualizações. Para mais informações, consulte o guia Capacidade de extensão de modelos.

🪝 Opcional: integração de “ganchos” @salesforce/commerce-sdk-react — Separa as chamadas da API da implementação de um projeto, permite que as chamadas da API sejam atualizadas como uma dependência da biblioteca npm e traz muitos recursos excelentes (incluindo gerenciamento de estado e outros) por meio da TanStack Query. Consulte a documentação sobre Commerce SDK React para começar.

Alterações necessárias 

Novos pacotes do SDK 

Os SDKs do PWA Kit foram movidos para a organização NPM @salesforce. Para atualizar para a v3, instale os novos pacotes e substitua todas as instruções de importação para os seguintes pacotes:

  • 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

Alteração significativa em getProps 

A partir da v3.0.0, o PWA Kit introduz uma nova estratégiawithReactQuery de busca de dados. Essa estratégia usa a biblioteca react-query e permite que você escreva ganchos React para buscar dados isomorficamente. Ao contrário do getProps, você não precisa mais duplicar a lógica de busca de dados para o lado do cliente e o lado do servidor. Nesta versão, por padrão, @salesforce/retail-react-app usa @salesforce/commerce-sdk-react, o que é alimentado por react-query.

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);
  • Você pode usar withReactQuery e withLegacyGetProps ao mesmo tempo.
  • getProps e shouldGetProps foram removidos do modelo padrão de páginas do Retail React App, mas não foram descontinuados. O suporte de longo prazo para esses métodos permanece.

Note

Atualizações de dependências de pacote 

Altere as dependências no package.json conforme mostrado abaixo. Remova @chakra-ui/system de peerDependencies e inclua-o em dependencies ou devDependencies.

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"

Atualize mecanismos no package.json para oferecer suporte ao nó 18 e npm 9.

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

Reinstale as dependências para o seu projeto com npm i.

Opcional: Usar extensibilidade de modelo 

Ao migrar da v2.7.x para a v3.x, você pode escolher se deseja usar a Extensibilidade de modelos. Para se beneficiar dela, você deve importar pelo menos um arquivo do @salesforce/retail-react-app (ou outro modelo extensível no futuro).

Feito isso, avalie quantos arquivos você modificou em relação ao projeto original gerado via npx pwa-kit-create-app@2.x. Alguns clientes modificam um grande número de arquivos (talvez centenas), mas, mesmo assim, um número significativo pode ficar sem alterações. Esses arquivos não alterados são bons candidatos para importar do @salesforce/retail-react-app, mas recomendamos realizar esse processo de forma cuidadosa e gradual. Muitos arquivos em @salesforce/retail-react-app são parecidos, mas foram alterados em relação ao seu estado anterior na v2.x do Retail React App do PWA Kit. Em especial, a integração @salesforce/commerce-sdk-react (os detalhes da migração são abordados em mais detalhes posteriormente) fez com que um grande número de arquivos mudasse em termos de importação e de estrutura de arquivos. O diretório commerce-api inteiro foi removido do aplicativo, o que, por si só, já é uma mudança significativa.

Ao migrar um projeto para usar a extensibilidade de modelos, saiba que a versão 2.x dos SDKS e dos projetos do PWA Kit gerados via npx pwa-kit-create-app@2.x não depende da @salesforce/commerce-sdk-react. Já o código mais novo @salesforce/retail-react-app@^1.x usa muito essa biblioteca, o que abrange e altera muitos arquivos. Para entender a magnitude das modificações, compare release-2.7.xrelease-3.0.x neste relatório de diferenças do Github https://github.com/SalesforceCommerceCloud/pwa-kit/compare/release-2.7.x…release-3.0.x?diff=unified#files_bucket, pesquise por @salesforce/commerce-sdk-react e observe todas as adições que incluem essa importação.

Note

Se o seu aplicativo tentar compartilhar código com a versão 2.x (que inclui o diretório app/commerce-api), você correrá o risco de adicionar código desnecessário ao seu pacote onde esse código existir (de duas formas muito diferentes) na pasta commerce-api e no módulo npm @salesforce/commerce-sdk-react.

Warning

Opcional: Obter a biblioteca de ganchos commerce-sdk-react 

Com a v3.0.0, o PWA Kit passa a usar uma estratégia de busca withReactQuery diferente. Essa estratégia faz uso da biblioteca react-query e habilita consultas na transmissão da renderização SSR. O @salesforce/retail-react-app usa @salesforce/commerce-sdk-react, que é desenvolvido com base na react-query.

Para que os ganchos funcionem no lado do servidor, você precisa unir seu componente AppConfig ao novo componente de ordem superiorwithReactQuery.

Como parte da migração para o ReactQuery como estratégia de busca padrão, uma alteração em @salesforce/retail-react-app@^1 é necessária para garantir que as chamadas getProps() legadas continuem funcionando.

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

Solução de problemas e otimização 

Quando você concluir as atualizações de dependência descritas acima, você pode encontrar problemas em seu projeto relacionados às bibliotecas abaixo. Nas seções abaixo, propomos soluções para resolver essas questões. As particularidades do seu projeto variam e as soluções propostas devem ser tratadas como diretrizes e não como regras absolutas.

Upgrade de react-hook-form 

Para a migração do react-hook-form, consulte a documentação oficial do react-hook-form aqui. No projeto do PWA, há dois locais que requerem alteração:

  1. Mova o objeto de formulário errors para mais uma camada de destruição para ganchos em app/components/forms/, à medida que o objeto errors é movido para o objeto formState.
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. Mova as props de renderização em Controller para a prop field. A assinatura do callback de Render retorna um objeto que contém field e 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    />

Erro de hidratação do React 18 

A partir do React 18, as advertências de hidratação são exibidas como erros, e não como advertências como eram no React 17. Algumas atualizações ao código precisaram ser feitas para suprimir esses erros em potencial que impedem o aplicativo de criar quando há erros de hidratação. É essencial corrigir esses erros para garantir que o aplicativo possa renderizar isomorficamente. Esse erro ocorre porque há uma falta de correspondência entre o servidor e o cliente. Se um componente ou uma página renderiza condicionalmente, você precisa garantir que a hidratação terminou antes de renderizar qualquer código específico do cliente.

Em seu projeto, crie uma função utilitária para determinar se a hidratação terminou. Você pode usar uma variável integrada fornecida por window.__HYDRATING__ em pwa-kit-react-sdk.

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 

Se o seu projeto usa componentes e APIs da biblioteca @chakra-ui/react que são diferentes do modelo do Retail React App, reveja a documentação de migração oficial do Chakra 2.

Important

Para ser compatível com o Chakra 2, há alguns arquivos que precisam ser atualizados para projetos com base no modelo do Retail React App:

Remova allowToggle no componente Accordion, porque allowMultiple e allowToggle não podem ser usados ao mesmo tempo no Chakra 2.

No componente Footer, a importação de StylesProvider diretamente de @chakra-ui/react foi descontinuada. Agora, a criação precisa ser feita por createStylesContext('Footer').

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

@testing-library/react 

Configure userEvent antes chamar qualquer ação e espere a ação em testes de unidade que usam userEvent porque, na biblioteca de testes React v14.0.0, todas as ações do usuário são assíncronas e é preciso chamar setup antes de realizar essas ações.

Por exemplo:

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

Para mais informações, consulte a documentação oficial sobre userEvent na testing-library (biblioteca de testes).

Como alternativa, para evitar chamar repetidamente setup()in many unit tests, you can set up youruserEvent emapp/utils/test-util.js antes de renderizar o componente de teste e retorná-lo junto com os resultados da renderização para que o teste possa executar as ações do usuário sem ter que chamar 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 

Em jest-setup, há uma dependência simulada que pode gerar um erro indicando que TextDecoder está indefinido em jest-setup.js. Adicione o seguinte jest-setup.js:

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

Outras melhorias 

Ao migrar da versão 2.x dos SDKs do PWA Kit ou projetos gerados via npx pwa-kit-create-app@2.x, o código @salesforce/commerce-sdk-react foi refatorado significativamente para remover o diretório app/commerce-api/. Em vez de aqueles arquivos processarem solicitação da API e agirem como um SDK, @salesforce/commerce-sdk-react substitui essa funcionalidade. A v3 dos SDKs está correlacionada à primeira versão do @salesforce/retail-react-app@^1.x porque os SDKs usam muito essa biblioteca.

A implementação de @salesforce/commerce-sdk-react altera muitos arquivos no Retail React App. Para ter uma noção do tamanho das alterações, compare release-2.7.x com release-3.0.x neste diff do GitHub e procure por @salesforce/commerce-sdk-react. No diff, anote todas as adições que incluem essa importação.