Extensibilité des modèles
L’extensibilité des modèles est une fonctionnalité introduite dans PWA Kit v3. Cette fonctionnalité doit vous permettre de créer plus facilement des projets PWA Kit en personnalisant des modèles. Vous pouvez personnaliser les modèles de base existants, tels que l’application Retail React App, ou vous pouvez créer le vôtre. Nous encourageons les membres de la communauté PWA Kit à partager leurs modèles de base entre eux.
L’extensibilité des modèles vous aide à modifier un modèle choisi sans avoir à dupliquer tous les fichiers qu’il contient.
C’est une fonctionnalité facultative. Les nouveaux projets générés après le 15 juin 2023 sont toutefois automatiquement configurés afin d’utiliser l’extensibilité des modèles.
Dans PWA Kit v3, un projet peut avoir un modèle de base et un répertoire overrides, et ils peuvent tous deux être configurés dans le fichier package.json
du projet. Pour utiliser l’extensibilité des modèles, vous devez déclarer un modèle de base avec ccExtensibility.extends
dans package.json
, ainsi qu’un répertoire overrides avec ccExtensibility.overridesDir
. (Les détails de configuration sont traités dans la section suivante.)
Un modèle de base est un module npm qui contient un projet PWA Kit entièrement fonctionnel et préconfiguré de sorte qu’un autre projet PWA Kit puisse remplacer certains de ses fichiers. Parfois, un modèle de base est également appelé « application extensible »."
Le répertoire overrides est un répertoire de votre projet dans lequel vous pouvez stocker des fichiers qui remplaceront les fichiers correspondants dans le modèle de base.
Nous partirons de l’hypothèse que vous avez déjà défini un répertoire overrrides et défini l’application Retail React App comme modèle de base. Supposons que vous souhaitiez maintenant remplacer le composant de page d’accueil de l’application Retail React App. Dans l’application Retail React App, le code du composant de page d’accueil se trouve dans app/pages/home/index.jsx
dans le paquet @salesforce/retail-react-app
. Pour remplacer ce fichier, vous devez le recréer dans le répertoire déclaré via ccExtensibility.overridesDir
dans package.json
. Le chemin du nouveau fichier est donc <ccExtensibility.overridesDir>/app/pages/home/index.jsx
.
Désormais, chaque fois que index.jsx
est importé dans l’un des fichiers du paquet @salesforce/retail-react-app
, le fichier du répertoire overrides est chargé à la place du fichier du paquet. Il suffit que la base du nom de fichier soit la même pour que le remplacement ait lieu. Les extensions de fichiers peuvent être différentes.
Vous pouvez ajouter progressivement des fichiers du modèle de base à votre répertoire overrides au fil de la création de votre application.
Plus vous remplacez de fichiers, plus l’effort nécessaire pour suivre les modifications apportées au modèle de base augmente.
Pour voir l’extensibilité des modèles en action, générez un nouveau projet PWA Kit v3 en exécutant npx @salesforce/pwa-kit-create-app@latest --outputDir <path/to/new/local/project>
.
Le projet généré utilise le modèle de base Retail React App. Vous obtenez donc une application qui ressemble beaucoup à celle que vous trouverez à l’adresse https://pwa-kit.mobify-storefront.com/.
Dans les tutoriels sur l’extensibilité des modèles, vous apprendrez à ajouter des personnalisations courantes à votre site :
- Personnaliser un composant — extensibilité au niveau du composant
- Personnaliser une page — extensibilité au niveau de la page
Les instructions de cette section supposent que vous souhaitez activer l’extensibilité des modèles pour un projet existant, mais pour lequel la fonctionnalité n’était pas déjà activée lors de sa création.
Pour effectuer une mise à niveau à la dernière version de l’application Retail React App, exécutez la commande suivante :
npm install @salesforce/retail-react-app@latest
Après avoir exécuté cette commande, nous vous recommandons de tester votre site pour vérifier qu’il fonctionne comme prévu.
Pour définir un modèle de base, ajoutez @salesforce/retail-react-app
(ou un autre modèle) en tant que dépendance npm dans le fichier package.json
de votre projet.
Ajoutez ensuite une clé ccExtensibility
à package.json
avec les clés et valeurs suivantes :
Si vous utilisez un modèle de base autre que Retail React App, n’oubliez pas de remplacer @salesforce/retail-react-app
par l’identifiant du paquet de l’autre modèle.
Vous pouvez remplacer les valeurs pour overridesDir
par un nom de répertoire personnalisé, mais nous vous recommandons d’utiliser overrides
par souci de cohérence entre les projets (et avec notre exemple de code).
Ne répertoriez pas les mêmes dépendances npm à la fois dans le projet principal et dans le modèle de base. Vérifiez que les dépendances répertoriées dans le package.json
de votre projet sont différentes de celles du modèle de base. Cela permet d’assurer que @salesforce/pwa-kit-dev
fait la différence entre les deux dans la résolution des dépendances. Définissez un modèle de base dans le package.json
du projet principal, comme décrit dans la section Configuration. Le projet principal ne peut pas hériter de lui-même.
Votre projet ne doit pas avoir de conflits de versions avec les dépendances npm du modèle de base répertoriées dans son fichier package.json
. Si le modèle sous-jacent utilise @chakra-ui
, votre projet doit également l’avoir comme dépendance et il doit s’agir de la même version. Cette précaution évite un gonflement accidentel de votre paquet (sans parler des ruptures fonctionnelles) qu’entraîneraient des versions conflictuelles du même paquet. Il y a une exception à cette règle : lorsque vous avez ajouté des remplacements pour tous les fichiers du modèle de base qui importent une dépendance donnée. Dans ce cas, la version de la dépendance du modèle de base n’est jamais importée dans votre projet car vous avez éliminé tous les fichiers qui l’importent via des remplacements.
L’ajout de dépendances npm supplémentaires qui ne sont pas utilisées dans le modèle sous-jacent est tout à fait possible.
Chaque projet PWA Kit déployé sur Managed Runtime doit contenir les fichiers suivants :
<overridesDir>/app/main.jsx
<overridesDir>/app/ssr.js
<overridesDir>/app/routes.jsx
<overridesDir>/app/request-processor.js
config/default.js
(exception : si vous utilisez la clémobify
danspackage.json
pour stocker les données de configuration de votre site)
Pour personnaliser les comportements dans le projet, il est courant de remplacer ces fichiers dans @salesforce/retail-react-app
:
app/pages/home/index.jsx
: la suppression du contenu marketing Salesforce par défaut de la page d’accueil est la première étape de presque tous les projets.app/static/*
: ces fichiers sont des fichiers par défaut qui fournissent les icônes utilisées par les navigateurs sur ordinateur et sur mobile pour personnaliser votre site. Mettez-les à jour pour qu’ils correspondent à votre marque.app/constants.js
app/assets/svg/brand-logo.svg
: ce fichier est remplacé dans le projet générateur. Suivez cet exemple pour remplacer d’autres icônes de votre projet.
Cette configuration de « système de fichiers en tant qu’API » a pour but de vous aider à trouver les fichiers sous-jacents, à les copier, puis à en personnaliser le comportement et la logique. En décomposant le code en fichiers plus petits qui orchestrent de nombreux sous-composants, il est plus facile de cibler uniquement le comportement que vous souhaitez remplacer.
Cela dit, vous devez parfois copier un fichier dans vos remplacements pour modifier uniquement une partie du comportement de ce fichier. Dans la mesure du possible, il est préférable d’importer les exportations de modèles sous-jacents puis de les réexporter, afin que les modifications apportées à la version du modèle ne nécessitent pas de mises à jour manuelles du code dans votre projet étendu.
Par exemple, dans le fichier routes.jsx
d’un projet généré, notez que les routes par défaut sont importées via import {routes as _routes} from '@salesforce/retail-react-app/app/routes'
. _routes
sert de convention pour indiquer que ces routes par défaut sont gérées par une dépendance externe. Tout comme le fichier @salesforce/retail-react-app/app/routes.jsx
, notre implémentation personnalisée de routes.jsx
exporte les routes ; il ajoute une route /
(Accueil). La nouvelle route est prioritaire sur la route par défaut car React Router trouve le premier élément d’un chemin donné dans le tableau routes.
Les importations relatives constituent la meilleure approche pour la plupart des projets qui utilisent l’extensibilité des modèles. Le comportement d’importation des fichiers de votre modèle de base (par exemple, @salesforce/retail-react-app
) a une logique spéciale qui donne la priorité au fichier situé dans votre répertoire overrides. Cette logique d’importation ne s’applique pas aux fichiers de votre répertoire overrides. Par conséquent, nous recommandons d’utiliser des importations relatives pour la plupart des implémentations.
L’extensibilité des modèles peut être complexe à appréhender en termes de « modèle mental », mais un « piège » inattendu peut survenir lors de l’importation accidentelle de deux fichiers différents en conflit. Un projet PWA Kit est généré via @salesforce/pwa-kit-dev
, qui utilise webpack en interne. Il existe un plug-in dans @salesforce/pwa-kit-dev
qui permet la fonctionnalité « override » de l’extensibilité des modèles. Ce plug-in inspecte toutes les requests de fichiers Webpack et pose deux questions :
- Cette request de fichier provient-elle du modèle de base ?
- Ce fichier existe-t-il dans le répertoire overrides ?
Si la réponse aux deux questions est « oui », la request de fichier est réécrite au moment du build pour pointer vers le fichier situé dans le répertoire overrides.
Cette logique n’entre pas en jeu pour les requests de fichiers Webpack provenant du répertoire overrides. Il est en effet possible d’importer le même fichier depuis le répertoire overrides et depuis le modèle de base. Si cette situation se produit avec, par exemple, @saleforce/retail-react-app/my-file
et <overrides directory>/my-file
importés dans le même paquet, webpack lève une erreur déroutante du type can’t find <export name> from <filename>
. Webpack génère cette erreur car le paquet ne sait pas quelle importation est la cible prévue pour l’inclusion du paquet.
Il est important d’éviter d’importer des fichiers à partir du modèle de base lorsqu’un fichier équivalent existe dans overrides, à une exception notable près. Comme indiqué précédemment dans l’exemple de code de la section Fichiers spéciaux et comme illustré avec constants.js
, il est préférable d’importer le modèle sous-jacent et de réexporter toutes ses exportations, en remplaçant ou en ajoutant aussi peu d’exportations que nécessaire.
Si vous devez remplacer le composant app/components/_app/index.jsx
, il existe de nombreux composants globaux, tels que Header
, Footer
et DrawerMenu
. Une fois le remplacement de _app/index.jsx
en place, à chaque fois que le modèle de base cherchera à importer ce composant, la request de fichier sera redirigée vers <ccExtensibility.overridesDir>/app/components/_app/index.jsx
. Mais il y a un piège ! Étant donné que Header
et Footer
sont importés par app/components/_app/index.jsx
, l’importation doit également être mise à jour dans _app/index.jsx
! Sinon, _app/index.jsx
importe Header
et Footer
depuis le modèle de base.
Les importations ECMAScript provenant de ccExtensibility.extends
sont « magiques » dans la mesure où @salesforce/pwa-kit-dev
recherche à plusieurs endroits un fichier de ce nom (ccExtensibility.overridesDir
étant prioritaire).
D’un autre côté, les importations provenant de <ccExtensibility.overridesDir>/*
n’ont pas de comportement magique, vous devez donc cibler les fichiers souhaités, et <ccExtensibility.overridesDir>/app/components/header/index.jsx
doit donc être importé explicitement dans <ccExtensibility.overridesDir>/app/components/_app/index.jsx
comme ceci :
N’importez pas à partir du paquet comme illustré, car cela contourne l’en-tête dans votre répertoire overrides :
Notez que routes.jsx
est un fichier spécial. Il constitue le « point d’entrée », dans la terminologie webpack, pour l’ensemble de l’application. Une erreur de configuration dans routes.jsx
entraînera l’échec de l’ensemble de votre application lors de la phase de compilation, car le découpage basé sur le routage dans pwa-kit-dev
ne pourra pas être résolu correctement. C’est pour cette raison que nous incluons un exemple d’extension correcte des routes (en mélangeant les importations du @salesforce/retail-react-app/app/routes.jsx
par défaut et d’un routes.jsx
local dans overridesDir
).
Étant donné que les importations se trouvent ici « en haut de l’arborescence », si vous remplacez ces fichiers puis remplacez footer.jsx
, vous devez revenir à _app/index.jsx
pour modifier cette importation afin qu’elle pointe vers l’importation relative de votre modèle.
Il existe une limitation connue du système d’extensibilité des modèles : d’après l’extraction magique, par exemple de retail-react-app/constants
, chaque fois que le modèle de base (@salesforce/retail-react-app
) importe ce fichier, il s’attend à ce que les mêmes valeurs soient exportées.
Un fichier de remplacement qui ne parvient pas à exporter les mêmes exportations ECMAScript que son équivalent dans le modèle de base peut provoquer des erreurs inattendues comme celle ci-dessous.
L’ajout d’un fichier constants.js
à votre répertoire overrides comme ceci provoque une erreur :
Exemple de message d’erreur :
Voici la raison de cette erreur : CAT_MENU_DEFAULT_ROOT_CATEGORY
est une exportation attendue dans @salesforce/retail-react-app/components/_app/index.jsx
. En la remplaçant par la seule exportation CUSTOM_MESSAGE
ci-dessus, votre remplacement rompt le « contrat de l’API » sous-jacent (la capacité des fichiers à dépendre d’une valeur donnée, dans ce cas CAT_MENU_DEFAULT_ROOT_CATEGORY
), car elle est exportée par constants.js
L’approche correcte serait la suivante. Cette approche évite d’omettreCAT_MENU_DEFAULT_ROOT_CATEGORY
en tant qu’exportation requise et attendue. Nous maintenons ainsi la cohérence de l’API exportée.
Cette approche ne fonctionne que pour les changements additifs. Dans l’exemple suivant, nous ajoutons une exportation CUSTOM_MESSAGE
qui ne figure pas dans les exportations du fichier retail-react-app/constants.js
sous-jacent.
Cette approche fonctionne pour le scénario suivant, dans lequel DEFAULT_LOCALE
est exporté par retail-react-app/constants
, et nous modifions cette valeur :
Les hooks de modèle offrent une nouvelle façon d’interagir avec le modèle Retail React App, historiquement disponible via la commande npx pwa-kit-create-app
(maintenant renommée npx @salesforce/pwa-kit-create-app
).
Dans le cadre de la fonctionnalité d’extensibilité des modèles, de nouveaux « hooks de modèle » ont été ajoutés à @salesforce/retail-react-app
. Ils prennent en charge l’ajout global d’un petit sous-ensemble de composants, répertoriés dans la liste suivante. Par défaut, chacun de ces composants renvoie null
et est intentionnellement vide afin d’éviter d’ajouter une surcharge inutile à un projet d’implémentation de PWA Kit terminé. La base @salesforce/retail-react-app
n’ajoute jamais aucune fonctionnalité à ces composants. Les hooks de modèle renvoient toujours null
afin de garantir que les implémentations client puissent « s’accrocher » au modèle à ces emplacements et personnaliser le projet sans avoir à remplacer plus de fichiers que nécessaire.
À partir de @salesforce/retail-react-app@1.0.0
, les hooks de modèles suivants sont disponibles :
app/components/_app/partials/above-header.jsx
app/pages/product-list/partials/above-page-header.jsx
Au moment de la sortie de PWA Kit v3, un seul modèle de base extensible est disponible au grand public : @salesforce/retail-react-app
(d’autres sont attendus par la suite).
Pour servir de modèle de base, un projet PWA Kit doit être publié sur npm et toutes ses importations ECMAScript doivent être préfixées par une valeur correspondant au nom du paquet. Par exemple, @salesforce/retail-react-app
est publié sur npm et ses importations sont préfixées par @salesforce/retail-react-app
. Ce préfixe est une référence au répertoire racine du paquet, nécessaire à son bon fonctionnement en tant que modèle de base.
Pour vous servir d’un projet PWA Kit comme modèle de base extensible, il doit utiliser <npm package name>
pour toutes ses importations. Par exemple, @salesforce/retail-react-app
ajoute ccExtensibility
dans package.json
, ce qui garantit la résolution correcte des références à l’IDE local (par exemple, @salesforce/retail-react-app/app/components/_app
).
- Utilisez l’extensibilité du modèle au lieu de copier le modèle Retail React App et de le modifier.
- À mesure que vous apportez des modifications, testez régulièrement votre projet pour identifier et résoudre les problèmes qui surviennent.
- Testez la fonctionnalité personnalisée dans un environnement hors production avant de la déployer en production.
- Effectuez des itérations sur vos remplacements si nécessaire pour affiner le comportement.
Cette section suggère des solutions pour les erreurs courantes que vous pouvez rencontrer lors de l’utilisation de l’extensibilité des modèles.
Une fois que vous avez modifié des fichiers dans votre projet, les mises à jour n’apparaissent pas lorsque vous prévisualisez votre site.
Cause : vous n’avez pas redémarré votre serveur local.
Solution suggérée : exécutez npm start
puis prévisualisez à nouveau votre site.
Cela ne s’applique que si vous utilisez une version de PWA Kit antérieure à la version 3.
Cause : la configuration ccExtensibility
requise est absente de votre fichier package.json
.
Solution suggérée : effectuez cette configuration dans package.json
.
Cause : les fichiers requis sont manquants dans le répertoire overrides (overridesDir
).
Solution suggérée : assurez-vous que votre projet inclut tous les fichiers requis dans le répertoire overrides
. Reportez-vous à la section Fichiers de projet requis.
Cause : il existe des versions conflictuelles des dépendances entre le modèle de base et votre projet
Solution suggérée : assurez-vous que le modèle de base et votre projet utilisent la même version des dépendances partagées. Reportez-vous à la section Conflits de versions.