Build
L'étape du build se fait en trois temps :
- build classique par
react-scripts build
- build pour le service-worker
- build final
Problème : le problème du micro-frontend
Lorsque l'application est utilisée en mode embarquée, ses scripts sont directement importés dans l'application parente. Queen peut alors fonctionner normalement sauf pour les images.
Explication
Prenons l'exemple où Queen est desservis par l'adresse https://queen.com
et est utilisé au sein d'une autre application comme Pearl-Jam desservis par l'adresse https://pearl.com
.
Lorsqu'une application react est construite avec un build classique, les URLs sont relatives. Par exemple si l'application a besoin de l'image /static/media/insee.png
, le script final envoie une requête vers /static/media/insee.png
qui est résolu par le navigateur par la concaténation de l'origine de la page et de la requête, ce qui donne pour un site dont l'origine est https://example.com
-> https://example.com/static/media/insee.png
.
Ainsi lorsque Queen est embarquée dans une autre application et qu'elle a besoin de l'image /static/media/insee.png
de Queen, le navigateur va résoudre de la même manière mais comme Queen est en mode embarqué, l'origine au yeux du navigateur est l'origine de l'application parente, il va donc chercher l'image à l'adresse https://pearl.com/static/media/insee.png
au lieu de https://queen.com/static/media/insee.png
dans notre exemple. On aura donc une erreur 404 si l'image n'existe par sur le serveur https://pearl.com
.
Solution
Le problème étant identifié, il faut une solution sous les contraintes suivantes :
- le build doit être indépendant de l'environnement où il est déployé (modulo le fichier
configuration.json
). - utiliser
react-scripts build
car déjà bien optimisé
La solution est relativement simple.
Lors du build par react, on peut définir la variable PUBLIC_URL (ou homepage dans package.json
). Cette variable permet de palier au problème d'URL relative.
Dans l'exemple précédent, il suffit de définir PUBLIC_URL=https://queen.com
lors du build pour régler le problème.
Cette solution ne respecte pas la contrainte d'indépendance du build.
Pour régler ce problème, on définit PUBLIC_URL=__PUBLIC_URL_TO_REPLACE__
, une expression facilement identifiable après build qu'on remplace par une expression en javascript.
L'expression est la suivante : (localStorage.getItem('QUEEN_URL') || '')
.
Au démarrage de l'application en mode embarqué, la valeur de QUEEN_URL est enregistrée dans le localStorage
du navigateur via le script entry.js
Avec cette solution :
- quand Queen est autonome :
localStorage.getItem('QUEEN_URL')
n'est pas défini, on se retrouve après résolution avec''
, cela ne pose pas de problème, on reste avec une adresse relative. - quand Queen est embarqué :
localStorage.getItem('QUEEN_URL')
vaut dans l'exemple précédenthttps://queen.com
, pour rechercher l'image on aura bien une adresse absolue grâce à la concaténation par le script delocalStorage.getItem('QUEEN_URL')
et de l'url de l'image :/static/media/insee.png
.
Votre aide est la bienvenue !
Si vous trouvez une meilleure solution, merci de la proposer via des Pull Request.
Build final :
- Etape 1 : build par react :
env PUBLIC_URL=__PUBLIC_URL_TO_REPLACE__ react-scripts build
Etape 2 : ajout du service-worker :
node ./configuration/build/build-sw.js
- creation du service-worker externe (à importer via
importScripts
par une application parente) via workbox (injectManifest) - remplacement dans le service-worker original (pour le mode autonome) généré par react de :
__PUBLIC_URL_TO_REPLACE__
par''
- creation du service-worker externe (à importer via
Etape 3: remplacement de l'expression
__PUBLIC_URL_TO_REPLACE__
:npm post-build
node ./configuration/build/manage-public-url.js
: Parcours des fichiers générés, on remplace l'expression__PUBLIC_URL_TO_REPLACE__
par(localStorage.getItem('QUEEN_URL') || '')
copy-and-watch configuration/* build
: On ajoute les fichiersconfiguration.json
etoidc.json
: à valoriser lors du déploiement de l'application.