Extensibilidade de modelos
A extensibilidade de modelos é um recurso introduzido no PWA Kit v3. O objetivo desse recurso é permitir que você personalize modelos para criar projetos do PWA Kit com mais facilidade. Você pode personalizar modelos-base já existentes, como o Retail React App, ou criar seu próprio. Nós sugerimos aos membros da comunidade PWA Kit que compartilhem seus modelos-base com todos.
A extensibilidade de modelos ajuda a modificar um modelo escolhido sem ter que duplicar cada arquivo dentro dele.
A extensibilidade de modelos é um recurso opcional. No entanto, os novos projetos gerados após 15 de junho de 2023 são configurados automaticamente para usar a extensibilidade de modelos.
No PWA Kit v3, um projeto pode ter um modelo base e um diretório de substituições, sendo que os dois podem ser configurados no arquivo package.json
do projeto. Para usar a extensibilidade de modelos, você precisa declarar um modelo base com ccExtensibility.extends
em package.json
e um diretório de substituições com ccExtensibility.overridesDir
. (Os detalhes da configuração são abordados na próxima seção).
Um modelo base é um módulo npm que contém um projeto do PWA Kit totalmente operacional que foi pré-configurado de forma que outro projeto do PWA Kit possa substituir alguns de seus arquivos. Às vezes, um modelo base também é chamado de “aplicativo extensível” ou “aplicativo expansível”."
O diretório de substituições é um diretório em um projeto onde você pode armazenar arquivos que substituem arquivos correspondentes em um modelo base.
Suponha que você já tenha definido um diretório de substituições e estabeleceu o Retail React App como seu modelo base. Digamos que você queira substituir o componente da página inicial do Retail React App. No Retail React App, o código do componente da página inicial está em app/pages/home/index.jsx
no pacote @salesforce/retail-react-app
. Para substituir esse arquivo, você precisa recriar o mesmo arquivo no diretório declarado via ccExtensibility.overridesDir
em package.json
. Portanto, o caminho para o novo arquivo é <ccExtensibility.overridesDir>/app/pages/home/index.jsx
.
Agora, sempre que index.jsx
for importado para qualquer arquivo no pacote @salesforce/retail-react-app
, o arquivo no diretório de substituições vai ser carregado em vez do arquivo no pacote. Somente a base do nome do arquivo precisa ser a mesma para que a substituição ocorra. As extensões dos arquivos podem ser diferentes.
Durante a criação do seu aplicativo, você pode adicionar gradualmente arquivos do modelo base ao seu diretório de substituições.
Quanto mais arquivos você substituir, mais esforço é preciso para acompanhar as mudanças no modelo base.
Para ver a extensibilidade de modelos em ação, gere um novo projeto PWA Kit v3 executando npx @salesforce/pwa-kit-create-app@latest --outputDir <path/to/new/local/project>
.
O projeto gerado usa o modelo base do Retail React App, o que vai produzir um aplicativo bastante parecido com o encontrado em https://pwa-kit.mobify-storefront.com/.
Nos tutoriais de extensibilidade de modelos, você aprenderá como adicionar algumas personalizações comuns ao seu site:
- Personalizar um componente — extensibilidade em nível de componente
- Personalizar uma página — extensibilidade no nível da página
As instruções nesta seção pressupõem que você quer habilitar a extensibilidade de modelos para um projeto existente que não foi gerado com o recurso já habilitado.
Para atualizar para a versão mais recente do Retail React App, execute este comando:
npm install @salesforce/retail-react-app@latest
Depois de executar esse comando, recomendamos que você teste seu site para confirmar se ele funciona conforme o esperado.
Para definir um modelo base, adicione @salesforce/retail-react-app
(ou um modelo diferente) como uma dependência npm no arquivo package.json
do seu projeto.
Depois, adicione uma chave ccExtensibility
a package.json
com as seguintes chaves e valores:
Se você usar um modelo base diferente do Retail React App, lembre-se de substituir @salesforce/retail-react-app
pelo identificador de pacote do outro modelo.
Você pode substituir os valores de overridesDir
por um nome de diretório personalizado, mas recomendamos usar overrides
para manter a consistência entre projetos (e nosso código de exemplo).
Não liste as mesmas dependências npm no projeto principal e no modelo base. Confirme se as dependências listadas package.json
no seu projeto são diferentes daquelas no modelo base. Isso garante que @salesforce/pwa-kit-dev
possa diferenciar entre os dois na resolução de dependência. Defina um modelo base no projeto principal, package.json
conforme descrito em Configuração. O projeto principal não pode herdar de si mesmo.
Seu projeto não pode ter conflitos de versão com as dependências npm do modelo base listadas no arquivo package.json
. Se o modelo subjacente usa @chakra-ui
, seu projeto precisa também tê-lo como uma dependência e com a mesma versão. Essa precaução evita sobrecarga acidental no seu pacote (sem falar em falhas no funcionamento) devido a versões conflitantes do mesmo pacote. Há uma exceção a essa regra: Quando você adiciona substituições para todos os arquivos no modelo base que importam uma determinada dependência. Nesse caso, a versão da dependência do modelo base nunca é importada para seu projeto, porque você eliminou todos os arquivos que a importariam com as substituições.
Não há problema em incluir dependências npm adicionais que não são usadas no modelo subjacente. 👌
Todo projeto do PWA Kit implantado no Managed Runtime precisa ter os seguintes arquivos:
<overridesDir>/app/main.jsx
<overridesDir>/app/ssr.js
<overridesDir>/app/routes.jsx
<overridesDir>/app/request-processor.js
config/default.js
(exceção: se você estiver usando a chavemobify
empackage.json
para armazenar os dados de config do seu site)
Para personalizar comportamentos no projeto, é normal substituir esses arquivos em @salesforce/retail-react-app
:
app/pages/home/index.jsx
: A remoção do conteúdo-padrão de marketing da Salesforce da página inicial é a primeira etapa em quase todos os projetos.app/static/*
: Esses arquivos-padrão disponibilizam os ícones da marca usados no seu site por navegadores em dispositivos móveis e desktops. Atualize-os para que correspondam à marca.app/constants.js
app/assets/svg/brand-logo.svg
: Esse arquivo é substituído no projeto gerador. Siga esse exemplo para substituir outros ícones em seu projeto.
O propósito dessa configuração “sistema de arquivos como uma API” é ajudar você a encontrar os arquivos subjacentes, copiá-los e, então, personalizar o comportamento e a lógica. A divisão do código em arquivos menores que orquestram vários subcomponentes permite que você se concentre apenas no comportamento que quer substituir.
Dito isso, às vezes você vai ter que copiar um arquivo para suas substituições a fim de mudar apenas uma parte do comportamento daquele arquivo. Sempre que possível, é melhor importar as exportações do modelo subjacente e exportá-las novamente, para que as mudanças na versão do modelo não exijam atualizações manuais de código no seu projeto expandido.
Por exemplo, no arquivo routes.jsx
em um projeto gerado, observe que as rotas-padrão são importadas porimport {routes as _routes} from '@salesforce/retail-react-app/app/routes'
com _routes
concebidas como uma convenção para indicar que essas rotas-padrão são gerenciadas por uma dependência externa. Como o arquivo @salesforce/retail-react-app/app/routes.jsx
, nossa implementação personalizada routes.jsx
exporta rotas. Ela adiciona uma rota /
(Início/Home). A nova rota tem prioridade sobre a rota-padrão, porque o React Router localiza o primeiro item de um determinado nome de caminho no array de rotas.
As importações relativas são a melhor abordagem para a maioria dos projetos que usa a extensibilidade de modelos. O comportamento de importação para os arquivos em seu modelo base (por exemplo, @salesforce/retail-react-app
) apresenta uma lógica especial que dá prioridade ao arquivo em seu diretório de substituições. Essa lógica de importação não é válida para os arquivos em seu diretório de substituições. Sendo assim, recomendamos o uso de importações relativas para a maioria das implementações.
Um problema com a extensibilidade de modelos que deve ser observado é a importação acidental de dois arquivos conflitantes diferentes. Um projeto do PWA Kit é criado por meio de @salesforce/pwa-kit-dev
, que usa o webpack internamente. Há um plug-in em @salesforce/pwa-kit-dev
que habilita a funcionalidade “substituir” da extensibilidade de modelos. Esse plug-in inspeciona todas as solicitações de arquivos webpack e faz duas perguntas:
- Essa solicitação de arquivo tem origem no modelo base?
- Esse arquivo existe no diretório de substituições?
Se a resposta para ambas as perguntas for “sim”, a solicitação de arquivo é regravada no momento da criação para direcionar ao arquivo no diretório de substituições.
Essa lógica não é ativada para as solicitações de arquivo webpack que se originam no diretório de substituições. Sendo assim, é possível importar o mesmo arquivo do diretório de substituições e do modelo base. Se essa situação ocorrer com, por exemplo, a importação de @saleforce/retail-react-app/my-file
e <overrides directory>/my-file
no mesmo pacote, o webpack emite um erro confuso parecido com can’t find <export name> from <filename>
O webpack emite esse erro porque o pacote não sabe qual importação é o destino esperado para inclusão no pacote.
É importante evitar a importação de arquivos do modelo base quando um arquivo equivalente existe nas substituições, com uma exceção relevante. Como explicado anteriormente no exemplo de código na seção sobre Arquivos especiais e demonstrado com constants.js
, é melhor importar o modelo subjacente e exportar novamente todas as exportações dele, substituindo ou adicionando o mínimo de exportações necessárias.
Quando você precisa substituir o componente app/components/_app/index.jsx
, há muitos componentes globais, como Header
, Footer
e DrawerMenu
. Depois que a substituição de _app/index.jsx
tiver sido feita, toda tentativa de importação desse componente pelo modelo base vai redirecionar a solicitação de arquivo para <ccExtensibility.overridesDir>/app/components/_app/index.jsx
. Só que nem tudo é tão simples. Como Header
e Footer
são importados por app/components/_app/index.jsx
, a importação também precisa ser atualizada em _app/index.jsx
! Caso contrário, _app/index.jsx
vai importar Header
e Footer
do modelo base.
As importações do ECMAScript com origem em ccExtensibility.extends
são “mágicas”, pois @salesforce/pwa-kit-dev
busca em vários lugares por um arquivo com aquele nome, com ccExtensibility.overridesDir
tendo prioridade.
Por outro lado, as importações com origem em <ccExtensibility.overridesDir>/*
não apresentam esse comportamento mágico. Sendo assim, você precisa especificar os arquivos que deseja, e <ccExtensibility.overridesDir>/app/components/header/index.jsx
precisa ser importado de forma explícita para<ccExtensibility.overridesDir>/app/components/_app/index.jsx
da seguinte forma:
Não importe do pacote dessa maneira, porque isso vai ignorar o cabeçalho em seu diretório de substituições:
É importante destacar que routes.jsx
é um arquivo especial. Ele forma o “entryPoint”, na terminologia webpack, para o aplicativo todo. Se você tiver alguma configuração incorreta no routes.jsx
, o aplicativo inteiro vai apresentar falha na fase de compilação, pois o chunking com base nas rotas em pwa-kit-dev
não vai ser resolvido adequadamente. Por isso, incluímos um exemplo de como ampliar as rotas adequadamente combinando importações do @salesforce/retail-react-app/app/routes.jsx
padrão e um routes.jsx
local no overridesDir
.
Como as importações estão na parte superior do caminho, se você substituir esses arquivos e, então, substituir footer.jsx
, vai ser preciso retornar a _app/index.jsx
e modificar essa importação para que ela aponte para a sua importação relativa do modelo.
Uma limitação conhecida do sistema de extensibilidade de modelos é que, devido à extração mágica (por exemplo, retail-react-app/constants
), sempre que o modelo base (@salesforce/retail-react-app
) importa esse arquivo, ele espera que os mesmos valores sejam exportados.
Um arquivo nas substituições que não exporta as mesmas exportações do ECMAScript como seu equivalente no modelo base pode causar erros inesperados, como o mostrado abaixo.
Incluir um arquivo constants.js
ao seu diretório de substituições dessa maneira gera um erro:
Exemplo de mensagem de erro:
O motivo desse erro é que CAT_MENU_DEFAULT_ROOT_CATEGORY
é uma exportação esperada em @salesforce/retail-react-app/components/_app/index.jsx
e, durante o processo de substituição dele com a única exportação CUSTOM_MESSAGE
acima, sua substituição quebra o “contrato com a API” subjacente (a capacidade de arquivos dependerem de um determinado valor, nesse caso CAT_MENU_DEFAULT_ROOT_CATEGORY
) ao ser exportada por constants.js
A abordagem correta seria a mostrada a seguir. Essa abordagem evita a omissão de CAT_MENU_DEFAULT_ROOT_CATEGORY
como uma exportação esperada e obrigatória. Dessa maneira, mantemos a consistência da API exportada.
Essa abordagem só funciona para alterações aditivas. No exemplo a seguir, adicionamos uma exportação CUSTOM_MESSAGE
que não está nas exportações do arquivo retail-react-app/constants.js
subjacente.
Essa abordagem funciona para o caso a seguir, em que DEFAULT_LOCALE
é exportado por retail-react-app/constants
e nós estamos alterando esse valor:
Os ganchos de modelo são uma nova maneira de interagir com o modelo do Retail React App historicamente disponível pelo comando npx pwa-kit-create-app
(agora renomeado npx @salesforce/pwa-kit-create-app
).
Como parte do recurso de extensibilidade de modelos, os novos “ganchos de modelo” foram adicionados ao @salesforce/retail-react-app
que permite a inclusão global de um pequeno subconjunto de componentes, enumerados na lista a seguir. Por padrão, cada um desses componentes retorna null
e fica intencionalmente em branco para evitar sobrecarga desnecessária a um projeto de implementação do PWA Kit concluído. A base @salesforce/retail-react-app
nunca adiciona funcionalidades a esses componentes. Os ganchos de modelo sempre retornam null
para garantir que as implementações do cliente possam sempre se “enganchar” no modelo nesses locais para personalizar o projeto sem ter que substituir mais arquivos do que o necessário.
A partir de @salesforce/retail-react-app@1.0.0
, os seguintes ganchos de modelo estão disponíveis:
app/components/_app/partials/above-header.jsx
app/pages/product-list/partials/above-page-header.jsx
Quando do lançamento do PWA Kit v3, só haverá um modelo base extensível disponível publicamente: @salesforce/retail-react-app
(outros vão chegar em breve).
Para ser usado como um modelo base, um projeto do PWA Kit precisa ser publicado no npm, e todas as suas importações do ECMAScript precisam ser prefixadas com um valor que corresponda ao nome do pacote. Por exemplo, @salesforce/retail-react-app
é publicado no npm, e suas importações são prefixadas com @salesforce/retail-react-app
. Esse prefixo é uma referência ao diretório raiz do pacote, o que é necessário para que ele funcione corretamente como um modelo base.
Para usar um projeto do PWA Kit como um modelo base extensível, ele precisa usar <npm package name>
em todas as importações. Por exemplo, @salesforce/retail-react-app
adiciona ccExtensibility
a package.json
, o que assegura que todas as referências do IDE (por exemplo, @salesforce/retail-react-app/app/components/_app
) resolvam adequadamente.
- Use a extensibilidade de modelos em vez de copiar o modelo do Retail React App e editá-lo.
- À medida que você faz alterações, teste seu projeto regularmente para identificar e corrigir quaisquer problemas que surjam.
- Teste a funcionalidade personalizada em um ambiente que não seja de produção antes de implantá-la em Production (produção).
- Itere em suas substituições conforme necessário para refinar o comportamento.
Esta seção sugere soluções para erros comuns que você pode encontrar ao usar a extensibilidade de modelos.
Depois que você alterar os arquivos em seu projeto, as atualizações não aparecerão quando você visualizar seu site.
Causa: Você não reiniciou o servidor local.
Solução sugerida: Execute npm start
e visualize seu site novamente.
Isso se aplica somente se você estiver usando uma versão do PWA Kit mais antiga que a versão 3.
Causa: Seu arquivo package.json
não tem a configuração ccExtensibility
necessária.
Solução sugerida: Conclua esta configuração em package.json
.
Causa: Os arquivos necessários estão ausentes do diretório de substituições (overridesDir
).
Solução sugerida: Certifique-se de que seu projeto inclua todos os arquivos necessários no diretório overrides
. Consulte Arquivos de projeto necessários.
Causa: Há versões conflitantes de dependências entre o modelo base e seu projeto
Solução sugerida: Certifique-se de que o modelo base e seu projeto usem a mesma versão de dependências compartilhadas. Consulte Conflitos de versão.