18. Client Vue.js du serveur de calcul de l’impôt
18.1. Architecture
Nous allons implémenter une application client / serveur avec l’architecture suivante :

Le serveur de calcul de l’impôt sera la version 14 développée dans le document |https://tahe.developpez.com/tutoriels-cours/php7|
18.2. Les vues de l’application
Les vues de l’application [vuejs-10] sont celles de la version 13 du document |https://tahe.developpez.com/tutoriels-cours/php7| du serveur de calcul de l’impôt lorsqu’il est utilisé en mode HTML. Mais dans l’application présente, ces vues seront générées par le client Javascript et non par le serveur PHP.
La 1ère vue est la vue d’authentification :

La seconde vue est celle du calcul de l’impôt :

La 3ième vue est celle qui affiche la liste des simulations faites par l’utilisateur :

L’écran ci-dessus montre qu’on peut supprimer la simulation n° 1. On obtient alors la vue suivante :

Si on supprime maintenant la dernière simulation, on obtient la nouvelle vue suivante :

18.3. Eléments du projet [vuejs-20]
L’arborescence du projet [vuejs-20] est la suivante :

Les éléments du projet sont les suivants :
- [assets/logo.jpg] : le logo du projet ;
- [couches] : les couches [métier] et [dao] de l’application ;
- [plugins] : les plugins de l’application ;
- [views] : les vues de l’application ;
- [config.js] : configure l’application ;
- [router.js] : définit le routage de l’application ;
- [store.js] : le store de [Vuex] ;
- [main.js] : le script principal de l’application ;
18.3.1. Les couches [métier] et [dao]
18.3.1.1. La couche [dao]
La couche [dao] est implémentée par la classe [Dao] du paragraphe |vuejs-10|
18.3.1.2. La couche [métier]
La couche [métier] est implémentée par la classe [Métier] du document |https://tahe.developpez.com/tutoriels-cours/php7|. On y a ajouté la méthode [setTaxAdminData] suivante :
La méthode [setTaxAdminData] fait la même chose que le constructeur. Sa présence permet la séquence suivante :
- instancier la classe [Métier] avec une instruction [métier=new Métier()] lorsqu’on veut instancier la classe mais qu’on n’a pas encore la donnée [taxAdminData] ;
- puis renseigner ultérieurement sa propriété [taxAdminData] par une opération [métier.setTaxAdminData(taxAdmindata)] ;
18.3.2. Le fichier de configuration [config]
Le fichier [config.js] est le suivant :
Cette configuration est celle de la bibliothèque [axios] que la couche [dao] utilise pour faire ses requêtes HTTP. On notera ligne 8, que le serveur opère sur port sécurisé [https].
18.3.3. Les plugins
Les plugins [pluginDao, pluginMétier, pluginConfig] ont pour but de créer trois nouvelles propriétés à la fonction / classe [Vue] :
- [$dao] : aura pour valeur une instance de la classe [Dao] ;
- [$métier] : aura pour valeur une instance de la classe [Métier] ;
- [$config] : aura pour valeur l’objet exporté par le fichier de configuration [config] ;
[pluginDao]
[pluginConfig]
18.3.4. Le store [Vuex]
Le store de [Vuex] est implémenté par le fichier [store] suivant :
Commentaires
- lignes 2-4 : le plugin [Vuex] est intégré au framework [Vue] ;
- lignes 8-13 : nous mettons dans le store de [Vuex] les éléments suivants :
- [simulations] : la liste des simulations faites par l’utilisateur ;
- [idSimulation] : le n° de la dernière simulation faite par l’utilisateur ;
On rappelle que le store va être partagé entre les vues et que son contenu est réactif : lorsqu’il est modifié, les vues qui l’utilisent sont automatiquement mises à jour. Dans notre application, seul l’élément [simulations] a besoin d’être réactif, pas l’élément [idSimulation]. On a laissé cet élément dans le store par commodité ;
- lignes 14-40 : les mutations autorisées sur l’objet [state] des lignes 8-13. On rappelle que celles-ci reçoivent toujours l’objet [state] des lignes 8-13 en 1er paramètre ;
- ligne 16 : la mutation [deleteSimulation] permet de supprimer une simulation dont on donne le n° [index] ;
- ligne 25 : la mutation [addSimulation] permet d’ajouter une nouvelle simulation au tableau des simulations ;
- ligne 35 : la mutation [clear] permet de réinitialiser l’objet [state] des lignes 8-13 ;
18.3.5. Le fichier de routage [router]
Le fichier de routage est le suivant :
Commentaires
- ligne 16 : au démarrage de l’application, c’est la vue [Authentification] qui est affichée car son URL est la racine [/] ;
- ligne 20 : la vue [CalculImpot] est affichée lorsque l’URL [/calcul-impot] est demandée ;
- ligne 24 : la vue [ListeSimulations] est affichée lorsque l’URL [/liste-des-simualtions] est demandée ;
- ligne 28 : la vue [Authentification] est affichée lorsque l’URL [/fin-session] est demandée ;
- lignes 33-38 : un objet [router] est créé avec ces routes (ligne 35) et le mode [history] (ligne 37) de gestion des URL ;
- ligne 41 : ce routeur est exporté ;
18.3.6. Le script principal [main.js]
Le script [main.js] est le suivant :
On notera les points suivants :
- lignes 18-21, l’objet exporté par le script [./config] va être disponible dans l’attribut [Vue.$config] donc disponible à toutes les vues de l’application. C’était inutile ici car l’objet [config] n’est utilisé que par le script [main] (ligne 25). Néanmoins il est fréquent que la configuration soit nécessaire à plusieurs vues. On a donc voulu ici garder le principe de la rendre disponible dans un attribut de la vue ;
- lignes 24-25 : instanciation de la couche [dao]. La classe [Dao] est importée ligne 24 puis instanciée ligne 25. Son constructeur admet pour unique paramètre l’objet [axios], propriété de configuration ;
- lignes 27-29 : la couche [dao] est rendue disponible dans l’attribut [$dao] de toutes les vues ;
- lignes 31-37 : on répète la même séquence pour la couche [métier]. Le constructeur de la classe [Métier] a pour paramètre [taxAdminData] qui représente les données de l’administration fiscale. Nous n’avons pas encore cette donnée. L’objet [métier] de la ligne 33 devra donc être complété ultérieurement ;
- ligne 40 : on importe le store [Vuex] ;
- lignes 43-51 : on instancie la vue principale [Main] (lignes 5 et 50), en lui passant deux paramètres :
- ligne 46 : le routeur [router] défini ligne 16 ;
- ligne 48 : le store [Vuex] [store] défini ligne 40 ;
- dans les deux cas, le nom de la propriété est à gauche et sa valeur à droite. Les noms des propriétés [router, store] sont fixés par les frameworks [vue-router] et [vuex]. Les valeurs associées peuvent elles être quelconques ;
18.4. Les vues de l’application
18.4.1. La vue principale [Main]
Le code de la vue principale [Main] est le suivant :
Commentaires
- la vue [Main] assure une mise en page de la vue routée et affichée ligne 23 :

- les lignes 5-15 affichent la zone 1 ;
- le ligne 23 affiche la vue routée [2] ;
- lignes 16-19 : une alerte affichée seulement en cas d’erreur de communication avec le serveur de calcul de l’impôt ;
- lignes 25-28 : un message d’attente affiché à chaque requête HTTP faite au serveur ;
- toutes les vues vont être affichées avec cette mise en page puisque chaque vue routée est affichée par les lignes 20-24. La vue [Main] sert à factoriser ce qui peut être partagé par les différentes vues ;
- ligne 23 : chaque vue routée peut émettre trois événements :
- [loading] : une requête HTTP a été lancée. Il faut montrer le message d’attente de la réponse ;
- [error] : la requête HTTP s’est terminée sur une erreur. Il faut montrer le message d’erreur et cacher la vue routée ;
- lignes 38-49 : l’état de la vue :
- ligne 41 : [showLoading] contrôle l’affichage du message d’attente de la fin d’une requête HTTP (ligne 25) ;
- ligne 43 : [showError] contrôle l’affichage du message d’erreur d’une requête HTTP (lignes 17-21) ;
- ligne 45 : [showView] contrôle l’affichage de la vue routée (ligne 23) ;
- lignes 53-63 : la méthode [mShowError] gère l’événement [error] émis par la vue routée (ligne 23) ;
- lignes 65-70 : la méthode [mShowLoading] gère l’événement [loading] émis par la vue routée (ligne 23) ;
- ligne 23 : on prêtera attention aux événements [error] et [loading]. Ils ne sont interceptés que si la vue routée est affichée [showView=true]. C’est pourquoi la vue routée est au départ affichée (ligne 45). Elle n’est cachée qu’en cas d’erreur (ligne 60). Pour éviter ce problème on aurait pu utiliser la directive [v-show] au lieu de [v-if]. la différence entre ces deux directives est la suivante :
- [v-if=’false’] cache le bloc contrôlé en l’éliminant du code HTML global. Les événements de la vue routée ne peuvent plus alors être interceptés ;
- [v-show=’false’] cache le bloc contrôlé en jouant sur son CSS, mais le code du bloc reste présent dans le HTML global et peut ainsi intercepter les événements de la vue routée ;
18.4.2. La vue de mise en page [Layout]
Le code de la vue [Layout] est le suivant :
Commentaires
- la vue [Layout] permet de diviser la vue routée en deux zones :
- une zone de 3 colonnes Bootstrap à gauche (lignes 7-9). Cette zone accueillera le menu de navigation lorsqu’il y en a un ;
- une zone de 9 colonnes à droite (lignes 11-13). Cette zone accueillera l’information amenée par la vue routée ;
18.4.3. La vue [Authentification]
La vue d’authentification est la suivante :

Cette vue est obtenue à partir du [Layout] en supprimant la colonne de gauche pour n’afficher que la colonne de droite.
Son code est le suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
Commentaires
- ligne 3 : la vue [Authentification] utilise uniquement la colonne de droite du [Layout] (lignes 3 et 4) ;
- lignes 6-38 : le formulaire Bootstrap qui génère la zone 1 de la copie d’écran ci-dessus ;
- ligne 6 : l’événement [@submit] se produit lorsque l’utilisateur va cliquer sur le bouton de type [submit] de la ligne 35. Le modificateur [prevent] demande à ce que la page ne soit pas rechargée lors du [submit]. On aurait pu écrire également :
- une balise <b-form> sans gestion de l’événement [submit] ;
- une balise <b-button> avec l’événement [@click=’login’] et sans l’attribut [type=’submit’] ;
Ca marche également. L’avantage de la solution retenue est que le submit se fait non seulement avec un clic sur le bouton [Valider] mais également sur une validation (touche [Entrée]) dans les zones de saisie. C’est donc par commodité pour l’utilisateur que la solution [<b-form @submit.prevent="login">] a été retenue ici ;
- lignes 33-37 : une alerte qui apparaît lorsque le serveur a rejeté les identifiants saisis par l’utilisateur :

- ligne 35 : le bouton [Valider] n’est pas toujours actif. Son état dépend de l’attribut calculé [valid] des lignes 71-73. L’attribut [valid] est vrai si :
- il y a quelque chose dans les champs [user, password] du formulaire ;
- la session jSON a démarré. Au départ, cette session n’a pas démarré (ligne 59) et donc le bouton [Valider] est inactif.
- lignes 49-60 : l’état de la vue ;
- [user] représente la saisie de l’utilisateur dans le champ [user] (lignes 12-17) du formulaire. La directive [v-model] de la ligne 15 établit une liaison bidirectionnelle entre la saisie de l’utilisateur et l’attribut [user] de la vue ;
- [password] représente la saisie de l’utilisateur dans le champ [password] (lignes 19-24) du formulaire. La directive [v-model] de la ligne 22 établit une liaison bidirectionnelle entre la saisie de l’utilisateur et l’attribut [password] de la vue ;
- [showError] contrôle (ligne 29) l’affichage de l’alerte des lignes 26-31 ;
- [message] est le message d’erreur (ligne 31) à afficher dans l’alerte des lignes 26-31 ;
- [sessionStarted] indique si la session jSON avec le serveur a démarré ou non. Au départ cet attribut a la valeur [false] (ligne 59). La session jSON avec le serveur est initialisée dans l’événement [created] du cycle de vie de la vue, lignes 126-156. Si le serveur répond positivement, alors l’attribut [sessionStarted] est passé à [true] (ligne 149) ;
- lignes 126-156 : la fonction [created] est exécutée lorsque la vue [Authentification] a été créée (pas forcément encore affichée). En tâche de fond, on initialise alors une session jSON avec le serveur. On sait que c’est la 1ère action à faire avec le serveur de calcul de l’impôt. Pour ce faire, on utilise la couche [dao] de l’application (ligne 134). Toutes les méthodes de cette couche sont asynchrones. On utilise ici la promesse (Promise) rendue par la méthode [$dao.initSession] qui initialise la session jSON avec le serveur.
- lignes 138-150 : le code exécuté lorsque le serveur a rendu sa réponse sans erreur ;
- ligne 142 : on vérifie la propriété [état] de la réponse. Elle doit avoir la valeur [700] pour une opération réussie. Sinon, il s’est produit une erreur dont la cause est indiquée dans la propriété [response.réponse] (ligne 144). On affiche alors le message d’erreur de la vue (ligne 145) ;
- ligne 149 : on note que la session jSON a démarré ;
- lignes 152-155 : le code exécuté en cas d’erreur. Celle-ci est remontée à la vue parente [Main] qui
- affichera l’erreur ;
- cachera le message d’attente ;
- cachera la vue routée, la vue [Autentification] ;
- lignes 79-124 : la méthode [login] traite le clic sur le bouton [Valider] ;
- ligne 79 : la méthode a été préfixée avec le mot clé [async] pour permettre l’utilisation du mot clé [await], lignes 84 et 103 ;
- lignes 84-87 : appel bloquant à la méthode [$dao.authentifierUtilisateur(user, password)]. On aurait pu utiliser une promesse [Promise] comme il a été fait dans la fonction [created]. Nous avons voulu varier les styles. Il n’y a pas de risque à bloquer l’utilisateur car nous avons mis un [timeout] de 2 secondes à toutes les requêtes HTTP. Il n’attendra pas longtemps. De plus, il ne peut rien faire tant que le serveur n’a pas rendu sa réponse car alors le bouton [Valider] reste inactif ;
- ligne 91 : le serveur de calcul de l’impôt envoie des réponses jSON ayant toutes la structure [{‘action’:action, ‘état’:val, ‘réponse’:réponse}]. L’authentification a réussi si [état==200]. Si ce n’est pas le cas, un message d’erreur est affiché, lignes 93-94 ;
- ligne 98 : on cache un éventuel message d’erreur d’une opération précédente ;
- lignes 99-116 : on demande mainteant au serveur les données de l’administration fiscale qui permettent le calcul de l’impôt. Dans [this.$métier] nous avons une instance de la classe [Métier] qui pour l’instant ne peut rien faire car elle n’a pas ces données ;
- ligne 103 : les données de l’administration fiscale sont demandées au serveur par une opération bloquante ;
- lignes 107-112 : la réponse du serveur est analysée. Elle doit avoir une valeur d’état égale à 1000 sinon c’est qu’il s’est produit une erreur. Dans ce dernier cas, on affiche le message d’erreur (lignes 109-110) ;
- lignes 113-118 : en cas de réussite de l’opération, on :
- cache le message d’erreur, ligne 114 ;
- on transmet les données de l’administration fiscale à la couche [métier] (ligne 116) ;
- on fait afficher la vue [CalculImpot], ligne 118. On se rappelle que [this.$router] désigne le routeur de l’application. La méthode [push] permet de fixer la prochaine vue routée. Ici on la désigne par son attribut [name]. On aurait pu également la désigner par son attribut [path]. Ces informations sont dans le fichier de routage :
- lignes 119-122 : le [catch] se déclenche lorsqu’une des deux requêtes HTTP a échoué (serveur pas présent, timeout dépassé, ...). On signale alors l’erreur à la vue parente [Main] qui l’affichera, cachera le message d’attente et la vue [Authentification] ;
18.4.4. La vue [CalculImpot]
La vue [CalculImpot] est la suivante :

- [1] : un menu de navigation occupe la colonne de gauche de la vue routée ;
- [2] : le formulaire de calcul de l’impôt occupe la colonne de droite de la vue routée ;
Le code de la vue [CalculImpot] est le suivant :
Commentaires
- ligne 4 : les deux colonnes du [Layout] sont ici présentes ;
- ligne 6 : le formulaire de calcul de l’impôt occupe la colonne de droite. Il émet l’événement [resultatObtenu] lorsque le résultat du calcul de l’impôt a été obtenu. On notera que les noms d’événements et les noms des méthodes qui les gèrent ne peuvent contenir de caractères accentués ;
- ligne 8 : le menu de navigation occupe la colonne de gauche ;
- lignes 11-20 : le résultat du calcul de l’impôt est affiché sous le formulaire :

- ligne 11 : le résultat n’est affiché que si l’attribut [résultatObtenu] (ligne 47) vaut [true] ;
- lignes 34-48 : l’état de la vue :
- [options] : la liste des options du menu de navigation. Ce tableau est passé en paramètre au composant [Menu], ligne 8 ;
- [résultat] : le résultat du calcul de l’impôt. Ce résultat est une chaîne HTML. C’est pourquoi on a utilisé la directive [v-html] à la ligne 17 pour l’afficher ;
- [résultatObtenu] : le booléen qui contrôle l’affichage du résultat, ligne 11 ;
- lignes 59-81 : la méthode [handleResultatObtenu] affiche le résultat du calcul de l’impôt que lui a envoyé la vue fille [FormCalculImpot], ligne 6. Ce résultat est un objet avec les propriétés [impot, décôte, réduction, surcôte, taux, marié, enfants, salaire] ;
- lignes 61-75 : on inscrit l’objet [impot, décôte, réduction, surcôte, taux] dans un texte HTML qui est visualisé par la ligne 17 du template ;
- ligne 77 : on affiche ce résultat ;
- ligne 80 : on appelle la mutation [addSimulation] du store Vuex qui va ajouter [résultat] aux simulations déjà présentes dans le store ;
18.4.5. Le menu de navigation [Menu]
Le menu de navigation s’affiche dans la colonne de gauche des vues routées :

Le code de la vue [Menu] est le suivant :
Commentaires
- les options du menu sont fournies par le paramètre [options] (lignes 7, 20-22) ;
- chaque élément du tableau [options] a une propriété [text] (ligne 12) qui est le texte du lien et une propriété [path] (ligne 9) qui sera le chemin de la vue cible du lien ;
18.4.6. La vue [FormCalculImpot]
Cette vue fournit le formulaire de calcul de l’impôt :

Son code est le suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | |
Commentaires
- lignes 4-51 : le formulaire Bootstrap ;
- lignes 11-17 : un groupe de boutons radio avec leur libellé ;
- lignes 14-15 : la balise <b-form-radio> assure l’affichage d’un bouton radio :
- ligne 14 : la directive [v-model] assure que lors d’un clic sur le bouton, l’attribut [marié] de la ligne 61 recevra la valeur [oui] (attribut [value="oui"]) ;
- ligne 15 : la directive [v-model] assure que lors d’un clic sur le bouton, l’attribut [marié] de la ligne 61 recevra la valeur [non] (attribut [value="non"]) ;
- lignes 19-29 : la partie saisie du nombre d’enfants :
- ligne 24 : la saisie du nombre d’enfants est liée à l’attribut [enfants] de la ligne 63 ;
- ligne 25 : la validité de la saisie est vérifiée par l’attribut calculé [enfantsValide] des lignes 87-89 ;
- ligne 28 : assure l’affichage d’un message d’erreur si la saisie est invalide ;
- lignes 31-45 : la partie saisie du salaire annuel :
- ligne 35 : affiche un message d’aide juste sous la zone de saisie ;
- ligne 41 : la saisie du salaire est liée à l’attribut [salaire] de la ligne 65 ;
- ligne 42 : la validité de la saisie est vérifiée par l’attribut calculé [salaireValide] des lignes 82-85 ;
- ligne 45 : assure l’affichage d’un message d’erreur si la saisie est invalide ;
- lignes 48-50 : un bouton de type [submit]. Lorsqu’on clique sur ce bouton ou lorsqu’on valide une saisie avec la touche [Entrée], la méthode [calculerImpot] est exécutée (ligne 94) ;
- ligne 49 : l’état du bouton actif / inactif est contrôlé par l’attribut calculé [formInvalide] des lignes 71-80 ;
- lignes 71-80 : le formulaire est valide si :
- le nombre d’enfants est valide ;
- le salaire est valide ;
- l’application a obtenu du serveur les données de l’administration fiscale permettant le calcul de l’impôt. On rappelle que cette donnée est enregistrée dans la propriété [$métier.taxAdminData]. La vue [FormCalculImpot] peut être affichée avant que cette donnée ait été obtenue car elle est demandée de façon asynchrone en même temps que se produit l’affichage de la vue. On s’assure ici que l’utilisateur ne peut pas cliquer sur le bouton [Valider] tant que la donnée n’a pas été obtenue ;
- lignes 94-109 : la méthode de calcul de l’impôt :
- lignes 96-100 : c’est la couche [métier] qui fait ce calcul. C’est un calcul synchrone. Une fois la donnée [taxAdminData] a été obtenue, le client [Vue] n’a plus à communiquer avec le serveur. Tout se fait localement. On obtient un objet [résultat] avec les propriétés [impôt, décôte, surcôte, réduction, taux] ;
- lignes 104-106 : on ajoute les propriétés [marié, enfants, salaire] au résultat ;
- ligne 108 : le résultat est passé à la vue parent [CalculImpot] via l’événement [resultatObtenu]. Cette vue est chargée d’afficher le résultat ;
18.4.7. La vue [ListeSimulations]
La vue [ListeSimulations] affiche la liste des simulations faites par l’utilisateur :

Le code de la vue est le suivant :
Commentaires
- ligne 5 : la vue occupe les deux colonnes de la mise en page [Layout] des vues routées ;
- lignes 7-26 : les simulations vont dans la colonne de droite ;
- ligne 28 : le menu de navigation va dans la colonne de gauche ;
- lignes 8, 14, 20, 75 : les simulations proviennent du store [Vuex] [$this.store] ;
- lignes 8-13 : alerte affichée lorsque la liste des simulations est vide ;
- lignes 14-25 : la table HTML affichée lorsque la liste des simulations n’est pas vide ;
- lignes 20-24 : la table HTML est générée par une balise <b-table> ;
- ligne 20 : le tableau des simulations est fourni par l’attribut calculé [simulations] des lignes 74-76 ;
- ligne 20 : la configuration de la table HTML est faite par l’attribut calculé [fields] des lignes 58-69. Ligne 67, la colonne de clé [action] est la dernière colonne de la table HTML ;
- lignes 21-23 : template de la dernière colonne de la table HTML ;
- ligne 22 : on y met un bouton de type lien. Lorsqu’on clique dessus, la méthode [supprimerSimulation(data.index)] est appelée, où [data] représente la ligne courante (ligne 21). [data.index] représente le n° de cette ligne dans la liste des lignes affichées ;
- ligne 28 : génération du menu de navigation. Les options de celui-ci sont fournies par l’attribut [options] des lignes 47-56 ;
- lignes 80-85 : la méthode qui réagit au clic sur un lien [Supprimer] de la page HTML ;
- ligne 84 : on fait appel à la mutation [deleteSimulation] du store [Vuex] (cf paragraphe |vuejs-15|) ;
18.5. Exécution du projet

Il faut également lancer le serveur [Laragon] (cf document |https://tahe.developpez.com/tutoriels-cours/php7|) pour que le serveur de calcul d’impôt soit en ligne.
18.6. Déploiement de l’application sur un serveur local
Actuellement, notre client [Vue] est déployé sur un serveur de test à l’URL [http://localhost:8080]. Nous allons le déployer sur le serveur [Laragon] à l’URL [http://localhost:80]. Il y a plusieurs étapes à effectuer pour en arriver là.
étape 1
Tout d’abord, nous allons faire en sorte que le client [Vue] soit déployé sur le serveur de test à l’URL [http://localhost:8080/client-vuejs-impot/].
Nous créons un fichier [vue.config.js] à la racine de notre projet [VSCode] actuel :

Le fichier [vue.config.js] [1] aura le contenu suivant :
Il nous faut également modifier le fichier de routage [router.js] [2] :
- ligne 39 : on indique au routeur que les chemins des routes définies lignes 13-30 sont relatives au chemin défini ligne 39. Par exemple, le chemin de la ligne 20 [/calcul-impot] deviendra [/client-vuejs-impot/calcul-impot] ;
On peut alors tester de nouveau le projet [vuejs-20] pour vérifier le changement des chemins de l’application :

étape 2
Nous construisons maintenant la version de production du projet [vuejs-20] :

- en [1-2], nous configurons la tâche [build] [2] dans le fichier [package.json] [1] ;
- en [3-5], nous exécutons cette tâche. C’est elle qui va construire la version de production du projet [vuejs-20] ;
L’exécution de la tâche [build] se passe dans un terminal de [VSCode] :


- en [3-6], des avertissements nous disent que le code généré est trop gros et qu’il faudrait le découper [8]. Cela relève de l’optimisation de l’architecture du code que nous n’aborderons pas ici ;
- en [7], on nous dit que le dossier [dist] contient la version de production générée :

- en [3], le fichier [index.html] est le fichier qui sera utilisé lorsqu’on demandera l’URL [https://localhost:80/client-vue-js-impot/];
On a ici un site statique qui peut être déployé sur n’importe quel serveur. Nous allons le déployer sur le serveur Laragon local (cf document |https://tahe.developpez.com/tutoriels-cours/php7|). Le dossier [dist] [2] est copié dans le dossier [<laragon>/www] [4] où <laragon> est le dossier d’installation du serveur Laragon. Nous renommons ce dossier [client-vuejs-impot] [5] puisque nous avons configuré la version de production pour fonctionner à l’URL [/client-vuejs-impot/].
étape 3
Nous ajoutons dans le dossier [client-vuejs-impot] qui vient d’être créé le fichier [.htaccess] suivant :

Ce fichier est un fichier de configuration du serveur web Apache. Si nous ne le mettons pas et que nous demandons directement l’URL [https://localhost/client-vuejs-impot/calcul-impot], sans passer d’abord par l’URL [https://localhost/client-vuejs-impot/] nous obtenons une erreur 404. Avec ce fichier, nous obtenons bien la vue [CalculImpot].
Ceci fait, nous lançons le serveur Laragon si ce n’est déjà fait et demandons l’URL [https://localhost/client-vuejs-impot/] :

Le lecteur est invité à tester la version de production de notre application.
Nous pouvons modifier le serveur de calcul de l’impôt sur un point : les entêtes CORS qu’il envoie systématiquement à ses clients. Cela avait été nécessité pour la version du client exécutée à partir du domaine [localhost:8080]. Maintenant que client et serveur s’exécutent tous deux dans le domaine [localhost:80], les entêtes CORS deviennent inutiles.
Nous modifions le fichier [config.json] de la version 14 du serveur :

- en [4], nous indiquons que désormais les requêtes CORS sont refusées ;
Sauvegardons cette modification et redemandons l’URL [https://localhost/client-vuejs-impot/]. Ca doit continuer à marcher.
18.7. Gestion des URL manuelles
Au lieu d’utiliser sagement les liens du menu de navigation, l’utilisateur peut vouloir taper les URL de l’application manuellement dans le champ d’adresse du navigateur. Demandons par exemple l’URL [https://client-vuejs-impot/calcul-impot] sans passer par la case d’authentification. Un hacker tenterait sûrement ça. On obtient la vue suivante :

On obtient bien la vue du calcul de l’impôt. Maintenant essayons de remplir les zones de saisie et de les valider :

On découvre alors que le bouton [1] [Valider] reste toujours désactivé même si les saisies sont correctes. Regardons le code de la vue [FormCalculImpot] :
Ligne 2, on voit que son état actif / inactif dépend de la propriété [formInvalide]. Celle-ci est la propriété calculée suivante :
Ligne 8, on voit que pour que le formulaire soit valide, il faut avoir obtenu les données fiscales. Or celles-ci sont obtenues lors de la validation de la vue [Authentification] que l’utilisateur a ‘sautée’. Il ne pourra donc pas valider le formulaire. S’il avait pu le faire, il aurait reçu un message d’erreur du serveur lui indiquant qu’il n’était pas authentifié. Les vérifications doivent toujours être faites côté serveur. Les vérifications côté navigateur peuvent toujours être contournées. Il suffit de prendre un client de type [Postman] qui enverra des requêtes brutes au serveur.
Maintenant demandons l’URL [https://localhost/client-vuejs-impot/liste-des-simulations]. On obtient la vue suivante :

Maintenant l’URL [https://localhost/client-vuejs-impot/fin-session]. Nous obtenons la vue suivante :

Maintenant une vue qui n’existe pas [https://localhost/client-vuejs-impot/abcd] :

Notre application résiste plutôt bien aux URL tapées à la main. Lorsque celles-ci sont appelées, le routeur de l’application le sait. Il est donc possible d’intervenir avant que la vue ne soit finalement affichée. Nous allons regarder ce point dans le projet [vuejs-21].
Un autre point à regarder est le suivant. Imaginons que l’utilisateur ait fait quelques simulations dans les règles :

Maintenant rafraîchissons la page par un F5 :

On a fait quelque chose de déconseillé : taper l’URL à la main (faire F5 revient à ça). Nous avons alors perdu nos simulations.
Le projet suivant [vuejs-21] se propose d’apporter deux améliorations :
- contrôler les URL tapées par l’utilisateur ;
- garder une mémoire de l’application même si l’utilisateur tape une URL. Ci-dessus, on voit qu’on a perdu la liste des simulations ;