---
contentId: c3e7499a-3b98-4008-b25e-756b529d8dcc
title: Fusion ou l'art d'intégrer PHP dans des composants Vue
description: Relier le frontend et le backend est un défi que tente de résoudre Fusion. En chemin, il apporte beaucoup de choses à apprendre.
date: 2025-02-18
---

Cet article est vraiment **spécial**.

Il y a deux semaines, les 3 et 4 février 2025, [Laracon EU](https://laracon.eu/) a eu lieu à Amsterdam. Bien que je n'ai pas pu y assister en personne, j'ai suivi l'événement entier en direct. Les conférences offrent toujours une occasion fantastique d'acquérir de nouvelles connaissances et de s'immerger davantage dans le merveilleux **écosystème Laravel**. _J'espère assister à Laracon un jour._

Une des présentations qui a retenu mon attention était ["Introducing \[REDACTED\]: A New Paradigm for Laravel + Javascript"](https://youtu.be/lXjYStxGFIQ?si=ntTW6zP-tAzV0OZO) par [Aaron Francis](https://x.com/aarondfrancis). Cela m'a intrigué puisqu'il existe déjà **Inertia** et **Livewire**, qui sont d'excellents outils pour créer des applications modernes avec **Laravel**. Quelles nouvelles avancées pouvaient-elles alors être proposées ?

![Miniature de la vidéo "Introducing \[REDACTED\]: a new paradigm for Laravel + Javascript" par Aaron Francis](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/thumbnail.jpg)

Aaron a présenté [**Fusion**](https://github.com/fusion-php), décrit comme une approche novatrice pour intégrer votre frontend moderne avec votre backend Laravel. Le concept permet d'écrire du code PHP directement dans un fichier frontend, et à travers un certain traitement, le code PHP est exécuté côté serveur, avec les résultats envoyés au frontend. Cela rappelle **Inertia**, mais poussé beaucoup plus loin.

> [!NOTE]
> Veuillez visionner la vidéo. C'est fascinant, facile à suivre et cela aidera considérablement à comprendre le reste de cet article.

Lors d'[une interview sur le podcast Navbar](https://youtu.be/vqWlJCtoD-k?si=Xnd4MOa5-dcBvPhi), Aaron a articulé l'objectif de Fusion : combler le fossé entre le frontend et le backend, simplifiant le développement et transformant Laravel avec Inertia pour ressembler à des méta-frameworks actuels comme **Next** ou **Nuxt**. Avec son partenaire commercial [Steve](https://x.com/steve_tenuto), Aaron a découvert que les conventions Laravel, comme les routes dans `web.php`, n'étaient pas intuitives pour les développeurs JavaScript qui préfèrent le routage basé sur des fichiers. L'objectif d'Aaron est de rendre Laravel plus accessible aux développeurs JavaScript.

Avec Fusion, un nouveau bloc est introduit dans le SFC de Vue pour écrire du code PHP, en étant une partie intégrante de l'application Laravel.

```vue
<php>
  // Définir une prop en PHP
  $name = prop(Auth::user()->name);
</php>

<template>
  <!-- Utilisez-le dans Vue ! -->
  Bonjour {{ name }} !
</template>
```

---

Cet article n'a pas pour but de déterminer si Fusion devrait être utilisé en production ou si l'intégration de PHP dans un SFC de Vue est conseillée. Ce débat est bien couvert, notamment sur X ou Reddit.

Au lieu de cela, je compte explorer le fonctionnement de Fusion pour deux raisons principales :

1. Il y a beaucoup à apprendre en examinant le code. Très honnêtement, je ne lis pas beaucoup de livres, mais je parcoure le code des projets, volant des astuces et des manières de faire négligés ailleurs.
2. Fusion incarne un sommet technique de ce qui est réalisable avec **Laravel**, **Vue**, et **Vite**. Mon désir de comprendre son fonctionnement m'a conduit à rédiger cet article. En ce moment, j'étudie également la bibliothèque [Alien Signals](https://github.com/stackblitz/alien-signals) de [Johnson Chu](https://github.com/johnsoncodehk) de la même manière. Comprendre quelque chose en profondeur implique souvent de l'expliquer aux autres, d'où cet article.

> [!NOTE]
> L'intégration de Vite avec Laravel est exceptionnelle, offrant de nombreux avantages aux développeurs Laravel. Si vous n'avez pas encore exploré **Vite**, vous devriez absolument le faire.

Maintenant, plongeons dans le code.

> [!NOTE]
> Lire la base de code est fascinant ; cela ressemble à lire du PHP écrit en JavaScript.

## Le code de Fusion

Une semaine après sa présentation à [Laracon EU](https://laracon.eu/), Aaron a rendu la base de code de Fusion publique. Curieux de ses mécanismes, j'ai supposé qu'un plugin Vite pourrait extraire le PHP d'un SFC de Vue, de manière similaire à la façon dont le [plugin Vue de Vite](https://github.com/vitejs/vite-plugin-vue) gère les balises script, template et style.

Le support pour HTML, CSS et JavaScript est simple pour Vite puisqu'ils sont gérés nativement par Vite. Cependant, le PHP pose un défi car il n'est pas pris en charge.

Pour mieux comprendre l'organisation de l'article, posons-nous quelques questions. D'abord : comment Fusion gère-t-il le code PHP ?

<figure>
  <video autoplay loop muted playsinline>
    <source src="https://images.soubiran.dev/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/hype-video.mp4" type="video/mp4">
  </video>

  <figcaption>
    Vidéo Hype de Fusion par <a href="https://x.com/aarondfrancis" target="_blank">Aaron Francis</a> et <a href="https://x.com/steve_tenuto" target="_blank">Steve Tenuto</a>, <a href="https://x.com/aarondfrancis/status/1886768725509976146" target="_blank">disponible sur X</a>.
  </figcaption>
</figure>

En regardant la vidéo hype, il est évident qu'il y a plus que simplement extraire le code PHP et l'exécuter. Fusion passe les résultats du code PHP en tant que props au composant Vue et prend en charge le RPC sur le backend Laravel depuis le client. De plus, le mot-clé `sync` permet la synchronisation entre les états frontend et backend.

Par exemple, une fonction appelée `favorite` devient facilement utilisable dans le frontend :

```vue
<php>
use function \Fusion\{prop, expose};
use \App\Models\Podcast;

$podcasts = prop(fn () => Podcast::all())->readonly();

expose(favorite: fn (Podcast $podcast) => response()->json($podcast->toggleFavorite()));
</php>

<script lang="ts" setup>
import Podcast from '@Components/Podcast.vue'
</script>

<template>
  <Podcast
    v-for="podcast in podcasts"
    :key="podcast.id"
    v-bind="podcast"
    @favorite="favorite({ podcast }).then(fav => podcast.favorited = fav)"
  />
</template>
```

Une autre question se pose : que fait Fusion en coulisses pour permettre cette fonctionnalité ?

<!-- Lors de sa présentation, Aaron a mentionné que Fusion supporte le Hot Module Reloading (HMR). C'est un gros avantage, et je prends ces travaux à cœur : "si l'expérience n'est pas agréable, personne ne l'utilisera". Je suis totalement d'accord avec cela. Mais, la troisième question : comment le HMR fonctionne-t-il dans Fusion ? -->

Enfin, il est dit que Fusion repousse Inertia au-delà de ses limites actuelles. Donc, une autre question : comment Fusion exploite-t-il Inertia ?

Répondons à ces questions une par une.

1. Comment Fusion gère-t-il le code PHP ?
2. Quels mécanismes Fusion emploie-t-il en coulisses pour permettre le RPC ?
<!-- 3. Comment le HMR fonctionne-t-il dans Fusion ? -->
4. De quelle manière Fusion utilise-t-il Inertia ?

Prêts pour une exploration ? Commençons.

## Comment Fusion gère-t-il le code PHP ?

Tout commence avec [Vite](https://vite.dev/). _Comme d'habitude._

Pour ceux qui ne le connaissent pas, **Vite** est un outil de build frontend remarquablement rapide qui alimente la prochaine génération d'applications web. Il a introduit une nouvelle philosophie connue sous le nom de philosophie à la demande. Essentiellement, Vite agit comme un proxy entre le navigateur, qui demande des fichiers, et le système de fichiers qui les contient. Lorsque le navigateur demande un fichier, Vite intercepte la requête, récupère le fichier et le renvoie. Cependant, agir comme un proxy permet à Vite des capacités supplémentaires, telles que la transformation de fichiers, l'injection de code, la récupération de fichiers distants et la génération de fichiers virtuels (fichiers non présents sur le système de fichiers). C'est semblable à un pipeline. Sans aucun doute, l'avènement de Vite a été transformateur pour l'écosystème frontend. En ajoutant des plugins à son pipeline, il peut être adapté à n'importe quel besoin.

Avec cela en tête, nous pouvons comprendre comment un fichier SFC subit un traitement par Vite.

```vue
<script setup>
// Le code JavaScript ira ici
</script>

<template>
  <div />
  <!-- Votre code de modèle ira ici -->
</template>

<style scoped>
  /* Votre code CSS ira ici */
</style>
```

Lorsqu'une requête de fichier `.vue` atteint le navigateur, un plugin Vite nommé [vite-plugin-vue](https://github.com/vitejs/vite-plugin-vue) transforme le fichier en traitant le script et le modèle pour en faire du code JavaScript lisible. Le CSS est extrait et envoyé dans le pipeline CSS avant d'être dispatché au navigateur. L'aspect intéressant est la possibilité de créer un plugin capable d'examiner le pipeline de transformation. Mieux encore, il n'est pas nécessaire de le construire de toutes pièces ; c'est exactement ce que fait le plugin [vite-plugin-inspect](https://github.com/antfu-collective/vite-plugin-inspect).

Par exemple, la transformation d'un SFC de Vue ressemble à ceci :

![Transformation d'un SFC de Vue vue à l'aide du plugin vite-plugin-inspect](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/vue-sfc-transformation.png)

D'accord, merci pour l'explication, mais que se passe-t-il dans Fusion ? Exactement la même chose mais pour le bloc PHP. Lorsqu'une requête contacte le serveur Vite en utilisant un fichier `.vue`, un plugin nommé [`fusion-vue`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L38-L40) extrait le bloc PHP. Ce processus commence dans la fonction [`transform`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L112) ci-dessous :

```ts
function transform(code, filename) {
  if (!filename.endsWith('.vue')) {
    return code
  }

  return new Transformer({
    config: fusionConfig,
    code,
    filename,
    isProd
  }).transform()
}
```

La fonction `transform` forme le cœur du pipeline de Vite. Elle transforme les fichiers avant qu'ils n'atteignent le navigateur. Dans le cas de Fusion, elle passe le fichier (l'intégralité du contenu) à une classe nommée `Transformer`, qui gère la transformation du fichier. Vous pourriez remarquer la condition `filename.endsWith('.vue')`, signifiant que la transformation ne s'applique qu'aux fichiers `.vue`. Cette approche est un modèle courant parmi les plugins Vite.

La classe Transformer est responsable de :

1. [Extraire le bloc PHP](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L16-L19) du SFC de Vue. Il utilise ici un parseur de [@vue/compiler-sfc](https://github.com/vuejs/core/tree/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/compiler-sfc) pour accomplir cette tâche. Notamment, le plugin `vite-plugin-vue` utilise ce même parseur, illustrant qu'ajouter un bloc personnalisé à un SFC de Vue est simple. J'ai déjà observé cette pratique ; le projet [Vue I18n](https://vue-i18n.intlify.dev/guide/introduction.html) supporte [un bloc personnalisé `i18n`](https://vue-i18n.intlify.dev/guide/advanced/sfc.html) spécifiant des traductions au sein d'un SFC de Vue.

```js
import { parse } from '@vue/compiler-sfc'

const descriptor = parse(code, { filename }).descriptor
const php = descriptor.customBlocks.find(block => block.type === 'php')
```

![Le SFC de Vue transformé dans le pipeline Vite](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/vue-sfc-with-php-transformation.png)

2. [Supprimer le bloc PHP](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L88-L91) du SFC de Vue.
3. [Déterminer si le code PHP mérite d'être persisté](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L96). Un autre aspect critique que nous examinerons dans [la section suivante](#que-fait-fusion-en-coulisses-pour-rendre-cela-possible).
4. [Valider et sauvegarder le code PHP](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L107). Cette vérification se fait via un processus externe exécutant une commande Laravel.

```ts
await runPhp(['fusion:conform', this.relativeFilename])
```

Tout code PHP comportant des erreurs déclenche un message d'erreur [interprété par Vite](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L124), si précisément qu'il s'affiche dans le navigateur pour indiquer une erreur dans le bloc de code PHP.

![L'overlay d'erreur Vite montrant l'erreur dans le code PHP](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/vite-error-overlay.png)

Si le fonctionnement se déroule sans accroc, le [code PHP, stocké en tant que fichier extrait](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L68), est sauvegardé dans le dossier `storage`. Cet aspect est à notable, car nous allons l'explorer davantage dans [la section suivante](#comment-fusion-gère-le-code-php).

5. Création d'un fichier JavaScript [basé sur le code PHP](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L112) qui fait le pont [entre les besoins du frontend](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Shim.php#L78-L113) et le code du bloc PHP. Cette étape intéressante nécessite une exploration plus approfondie.

Encore une fois, une commande Laravel est invoquée durant cette étape :

```ts
await runPhp(['fusion:shim', this.relativeFilename])
```

6. Enfin, elle renvoie le code transformé à Vite, permettant au SFC de poursuivre son chemin.

Voici une illustration de la transformation du SFC de Vue :

![Schéma montrant toutes les étapes que nous avons vues jusqu'à présent](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/fusion-schema-vite-transform.png)

Dans Fusion, les fichiers SFC de Vue fonctionnent comme un routeur basé sur des fichiers à l'instar du mécanisme de Nuxt. La première requête atteint généralement le serveur PHP, qui répond avec le code initial côté client, lequel vise ensuite le serveur Vite pour des requêtes de ressources supplémentaires. Cependant, si une route SFC de Vue n'a pas été visitée, la fonctionnalité PHP correspondante ne sera pas prête à la gérer, résultant en une erreur 404 du serveur Laravel. En conséquence, le serveur Vite reste intouché, entravant le processus de transformation. Cela pose un obstacle, un énorme.

Pour comprendre pleinement comment ce problème est abordé, nous devons examiner tous les aspects du plugin Vite.

Dans la configuration Vite, nous trouvons deux caractéristiques notables :

1. La [configuration Vite](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L42-L65) où Vite reconnaît l'emplacement pour trouver le fichier JavaScript généré (le shim), qui reçoit [un alias](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L61) attribué dans le résolveur Vite. Cet alias obscurcit l'emplacement du fichier, encourageant les meilleures pratiques comme éviter les chemins codés en dur et rendant l'emplacement du code agnostique aux changements de chemin. Cette configuration liée à Vite provient d'un fichier config PHP pour éliminer les configurations redondantes, donc le [plugin Vite Fusion engendre un processus](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L45) exécutant une commande Laravel pour résoudre les nécessités de configuration.
2. Un observateur [ajouté pour surveiller les changements dans l'ensemble du projet](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L79) utilisant l'observateur Vite, une [instance Chokidar](https://vite.dev/guide/api-javascript.html#vitedevserver:~:text=/**%0A%20%20%20*%20Chokidar%20watcher%20instance.%20If%20%60config.server.watch%60%20is%20set%20to%20%60null%60%2C%0A%20%20%20*%20it%20will%20not%20watch%20any%20files%20and%20calling%20%60add%60%20or%20%60unwatch%60%20will%20have%20no%20effect.%0A%20%20%20*%20https%3A//github.com/paulmillr/chokidar/tree/3.6.0%23api%0A%20%20%20*/%0A%20%20watcher%3A%20FSWatcher).

```ts
function configureServer(server) {
  server.watcher.on('all', (event, filename) => {
    // Faites ce que vous voulez
  })
}
```

Cet observateur prend en charge deux fonctions :

1. [Nettoyer](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L88) la base de données et le dossier de stockage lors de la suppression de fichiers ou de dossiers. Le dossier de stockage contient les fichiers SFC de Vue transformés, servant de routeur basé sur des fichiers. Sans suppression, l'utilisateur peut toujours accéder aux fichiers supprimés.
2. [Déclencher la transformation de fichiers](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/vite.js#L97-L99). Cela fonctionne de manière identique à la fonction `transform` rencontrée précédemment, nécessitant un chargement manuel de fichiers. Seuls les fichiers SFC de Vue subissent une transformation.

```ts
function configureServer(server) {
  server.watcher.on('all', async (event, filename) => {
    if (filename.endsWith('.vue')) {
      const fileContent = fs.readFileSync(filename, 'utf-8')

      await new Transformer({
        config: fusionConfig,
        code: fileContent,
        filename,
        isProd
      }).transform()
    }
  })
}
```

Mais pourquoi transformer des fichiers lors de leur création ou modification ? Cette approche semble contredire la philosophie à la demande et la fonction `transform` définie précédemment. Pourtant, une justification existe.

Considerons qu'une erreur se produise dans le bloc PHP, comme un oubli dans l'importation d'une fonction ou d'une classe, ou en tentant de visiter une route pour la première fois. Lorsque la page est rechargée, le serveur PHP renvoie un message d'erreur, comme Laravel le fait par défaut. Cependant, corriger le bloc PHP du SFC de Vue ne rectifie pas l'erreur du serveur PHP puisque la transformation Vite ne déclenchera pas à nouveau. En conséquence, appuyer à plusieurs reprises sur `cmd+r` ne sert à rien.

Pour cette raison, le système de fichiers doit être surveillé pour les changements SFC de Vue, déclenchant une transformation manuelle. Bien que suboptimale, cette méthode est nécessaire. Aaron a conçu une stratégie priorisant les transformations via la méthode `transform` sur celles déclenchées par l'observateur, avec application d'un throttling sur l'observateur.

C'est également pour résoudre le problème vu précédemment : lorsque le serveur PHP est touché en premier, le fichier PHP généré n'est pas encore créé.

Résumons nos apprentissages jusqu'à présent avec ce schéma :

![Un schéma montrant toutes les étapes qui font fonctionner Fusion.](/posts/fusion-or-the-art-of-writing-php-into-a-vue-sfc-components/fusion-schema.png)

Bien que nous n'ayons pas complètement couvert chaque composant, ce diagramme aide notre compréhension du reste de l'article.

> [!NOTE]
> Assurez-vous que le serveur Vite fonctionne correctement pour que tout fonctionne sans accroc.

Cette exploration nous a profondément engagés dans le plugin Vite de Fusion. Passons maintenant à comprendre comment Fusion organise la gestion de son code PHP.

> [!NOTE]
> Vous avez des questions ? [Demandez-moi tout](/ama) ou laissez un commentaire ci-dessous. J'aime vraiment lire vos retours !

## Que fait Fusion en coulisses pour rendre cela possible ?

Plongeons dans les opérations côté PHP.

Nous avons vu le code PHP extrait, validé et sauvegardé sur le disque. Nous devons maintenant dénouer deux étapes cruciales pour mieux comprendre le fonctionnement de Fusion :

1. Déterminer si le code PHP doit être persistant.
2. Sauvegarder le code PHP dans le système de fichiers.

Pour faciliter la compréhension, abordons d'abord la deuxième étape. La première étape deviendra ensuite claire.

### Écriture du code PHP sur le système de fichiers

Une fois extrait du SFC de Vue, le code PHP doit être persistant sur le système de fichiers. Ce processus est crucial puisque le PHP écrit au sein du SFC de Vue devient une partie intégrante de l'application Laravel, non pas simplement un script PHP indépendant. Ce fichier généré est essentiel pour que l'application Laravel réponde aux requêtes entrantes.

Après l'extraction, le code PHP est placé dans [un fichier temporaire](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L97). Ce fichier temporaire maintient le contenu exact du code inhérent au SFC de Vue. Par la suite, Fusion crée une entrée dans une [base de données SQLite dédiée](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Database.js#L3). Nous reviendrons sur cette base de données plus tard, en comprenant qu'elle facilite la communication entre les processus PHP et JavaScript.

Enfin, le plugin Vite déclenche la [`commande fusion:conform`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L107).

### La commande `fusion:conform`

Nous avons retardé la compréhension de cette commande ; il est maintenant temps de clarifier. Dans la commande `fusion:conform`, une commande Laravel écrite en PHP, ni Vite ni JavaScript ne s'appliquent, strictement du PHP.

Lors de l'invocation, cette commande utilise un argument `src` représentant le chemin du fichier SFC de Vue. Agissant comme un identifiant unique, elle permet à Fusion de [récupérer l'entrée de la base de données pertinente](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L38).

Cette entrée contient le chemin de destination pour le fichier PHP final qui sera utilisé par l'application Laravel. Actuellement, ce fichier n'existe pas ; un fichier temporaire conserve seulement le code. Ainsi, l'étape suivante consiste à lire [le contenu du fichier temporaire](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L44-L47) avant un traitement ultérieur.

Le processus suivant mobilise une [classe conformante](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L56), chargée de :

1. Modifier le code pour l'adapter à l'application Laravel.
2. S'assurer de la validité du code en le passant par un parseur PHP.

La fonction examine la conformité du code PHP en le faisant passer par une séquence de [classes de transformation](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Conformity/Conformer.php#L65C24-L79).

Chaque classe de transformer étend une super-classe `Transformer`, conçue sur mesure pour étendre `NodeVisitorAbstract` et met en œuvre l'interface `TransformerInterface` provenant de [PHP Parser](https://github.com/nikic/PHP-Parser).

```php [Transformer.php]
<?php

namespace Fusion\Conformity\Transformers;

abstract class Transformer extends NodeVisitorAbstract implements TransformerInterface
{
    public function __construct(
        protected ?string $filename = null
    ) {}
}
```

Chaque transformateur personnalisé, de plus, implémente la méthode `enterNode` pour faire avancer la transformation du code.

```php [PropTransformer.php]
<?php

namespace Fusion\Conformity\Transformers;

class PropsTransformer extends Transformer
{
    public function enterNode(Node $node)
    {
        if ($node instanceof MethodCall) {
            // Effectuer une opération
        }
    }
}
```

> [!NOTE]
> Une exploration détaillée des transformateurs ou des parseurs PHP est en dehors du champ d'application de cet article car ils offrent une fonctionnalité avancée pas immédiatement nécessaire pour comprendre le fonctionnement de Fusion.

Au total, dix transformateurs sont impliqués, chacun ayant une responsabilité spécifique. Concevez-les comme des étapes au sein d'un pipeline, un modèle conventionnel en programmation conçu pour décomposer des tâches complexes en segments plus petits et abordables. Par conséquent, lorsque le code utilisateur subit une transformation et est rendu compatible avec l'application Laravel, la sortie d'un transformateur devient l'entrée du suivant.

```txt
Code PHP du SFC de Vue
    | |
[Transformateur procédural]: Transforme le code procédural en une méthode de classe anonyme intitulée runProceduralCode.
[Transformateur de props]: Change les appels de fonction prop() en appels de méthode de cet objet dans la classe.
[Transformateur d'importation de fonction]: Supprime les importations de fonction inutiles, spécifiquement celles connues à l'avance.
[Transformateur de valeur de prop]: Spécifie que les chaînes d'appels de méthode $this->prop() se terminent par ->value().
[Transformateur d'exposition]: Modifie les appels de fonction expose() en appels de méthode de cet objet, excluant les affectations de variable.
[Transformateur de montage]: Valide et modifie les appels de fonction mount(), s'assurant qu'il n'y ait qu'un seul argument fonction anonyme.
[Transformateur de découverte de prop]: Découvre et documente les noms de propriétés des fonctions prop() rencontrées.
[Transformateur de découverte d'action]: Découvre et construit des méthodes pour les gestionnaires d'action exposés via expose().
[Transformateur de retour anonyme]: Garantit des retours d'expression directs pour les retours de classe anonyme.
[Transformateur de classe anonyme]: Convertit les classes anonymes en classes nommées, dans un espace de noms généré, rassemblant les exigences nécessaires.
    | |
Code PHP utilisable
```

Considérons un exemple concret avant de continuer. Supposons que le code PHP suivant existe au sein du SFC de Vue :

```vue
<php>
use function \Fusion\{prop};

$name = prop('bienvenue');

$name = strtoupper($name);
</php>
```

Après avoir passé par la transformation, cela donne :

```php
<?php

/**
 * Fichier auto-généré par Fusion.
 * Les modifications ne sont pas conseillées.
 */
namespace Fusion\Generated\Pages;

class IndexGenerated extends \Fusion\FusionPage
{
    #[\Fusion\Attributes\ServerOnly]
    public array $discoveredProps = ['name'];
    use \Fusion\Concerns\IsProceduralPage;
    public function runProceduralCode()
    {
        $name = $this->prop(name: 'name', default: 'bienvenue')->value();
        $name = strtoupper($name);
        $this->syncProps(get_defined_vars());
    }
}
```

Cette classe `IndexGenerated` sera utilisée par l'application Laravel lors du traitement des requêtes à la route '/'. Visualisez-la comme un mini-contrôleur contenant le code utilisateur. Dans les coulisses, une grande partie de la complexité est abstraite dans la classe [`FusionPage`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionPage.php#L22).

Le tableau `discoveredProps` enregistre les noms des propriétés traitées lors des appels de fonction **prop()**, assurant la synchronisation entre les propriétés frontend et backend.

La méthode `runProceduralCode`, invoquée lors du chargement de la page, exécute le code utilisateur aux côtés du code généré par Fusion, garantissant la synchronisation des props entre le frontend et le backend.

La méthode [`syncProps`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Concerns/IsProceduralPage.php#L36) maintient la synchronisation des propriétés intérieur-extérieur. Cela récupère les variables définies dans la méthode, et le contenu du tableau discoveredProps, garantissant que la propriété `props` générée contient uniquement les données requises par l'utilisateur.

> [!NOTE]
> Utiliser `get_defined_vars`, une fonction PHP intégrée, retourne un tableau de variables représentatives de la portée actuelle. Dans ce cas, cela constitue `['name' => 'bienvenue']`.

> [!NOTE]
> `#[ServerOnly]` classe les propriétés pour une application exclusivement côté serveur. Analogues [décorateurs TypeScript](https://www.typescriptlang.org/docs/handbook/decorators.html) fonctionnent de manière similaire sous [reflect-metadata](https://www.npmjs.com/package/reflect-metadata).

Enfin, Fusion place le contenu transformé dans le chemin de fichier fourni par la base de données, mettant à jour les entrées associées avec le nom législatif de la classe composée du nom d'espace et de la désignation de la classe. La procédure reste enfermée dans un bloc `try/catch`, prête à traiter toute erreur de transformation qui pourrait survenir. Lorsqu'une erreur se produit, [un fichier temporaire est supprimé](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L131) tandis qu'[un message d'erreur est dirigé vers Vite](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Console/Commands/Conform.php#L124), comme noté plus tôt.

À ce stade, notre système de fichiers apparaît maintenant comme suit :

<Tree
  name="Une application Fusion"
  :items="[
    {
      title: 'resources/js/Pages',
      children: [
        { id: '1', title: '[Podcast].vue' },
        { id: '2', title: 'Index.vue' },
        { id: '3', title: 'Search.vue' },
      ],
    },
    {
      title: 'storages/fusion',
      children: [
        {
          id: '4', title: 'JavaScript', children: [
            { id: '7', title: 'Index.js' },
            { id: '8', title: '[Podcast].js' },
            { id: '9', title: 'Search.js' },
          ]
        },
        {
          id: '5', title: 'PHP', children: [
            { id: '10', title: 'DynamicPodcastGenerated.php' },
            { id: '11', title: 'IndexGenerated.php' },
            { id: '12', title: 'SearchGenerated.php' },
          ]
        },
        { id: '6', title: 'fusion.sqlite' },
      ],
    }
  ]"
  :default-expanded="['resources/js/Pages', 'storages/fusion']"
/>

Ensuite, le plugin Vite reprend son opération, comme décrit dans [la section suivante](#gestion-des-demandes-entrantes).

### La base de données

Puisque nous avons mentionné une base de données au cours de cet article, nous avons abstenu de donner des détails jusqu'à présent. Il est temps de comprendre son but !

La base de données aide à établir la communication entre les processus PHP et JavaScript, stockant des informations essentielles à cette fin. D'un coup d'œil, nous pouvons discerner les données stockées et son utilisation.

| id | src                            | php_class                                      | php_path                                            | shim_path                                   | php_hash                            |
|----|--------------------------------|------------------------------------------------|-----------------------------------------------------|---------------------------------------------|-------------------------------------|
| 1  | /resources/js/Pages/Index.vue  | \Fusion\Generated\Pages\IndexGenerated         | /storage/fusion/PHP/Pages/IndexGenerated.php        | /storage/fusion/JavaScript/Pages/Index.js   | php_1e182535deedd9b60e12c277bef58603|
| 2  | /resources/js/Pages/Search.vue | \Fusion\Generated\Pages\SearchGenerated        | /storage/fusion/PHP/Pages/SearchGenerated.php       | /storage/fusion/JavaScript/Pages/Search.js  | php_468b4badedbe0cb6ce4734fcc921ea5f|
| 3  | /resources/js/Pages/[Podcast].vue | \Fusion\Generated\Pages\DynamicPodcastGenerated | /storage/fusion/PHP/Pages/DynamicPodcastGenerated.php | /storage/fusion/JavaScript/Pages/[Podcast].js | php_2ca978b1c880558f54c4a59ce7584e6c |

Lors de la transformation des SFC de Vue et de l'extraction du code PHP, un [calcul de hash](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L50) se produit, enregistré dans la colonne `php_hash` de la base de données.

Le hash sert à vérifier si [le code PHP a été modifié](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/Transformer.js#L96). Un hash correspondant signifie que le code PHP n'a pas changé, introduisant une optimisation pour omettre les transformations redondantes.

> [!NOTE]
> Un hash est une fonction à sens unique générant une chaîne de caractères de taille fixe à partir d'une entrée, généralement composée de séquences numériques et alphanumériques. Un hash identifie de manière unique son entrée, signifiant que des hashes identiques indiquent des entrées identiques.

Ce dépôt de base de données incarne des données supplémentaires comme les chemins de fichiers PHP et JavaScript utilisés principalement pour gérer efficacement les requêtes entrantes.

Une question supplémentaire se pose : comment la base de données SQLite affecte-t-elle l'expérience développeur ?

Tout en utilisant une base de données SQLite, Fusion ne dicte pas le choix de la base de données de l'application Laravel : les deux restent entièrement distincts.

Le fournisseur de services de Fusion attribue [une connexion de base de données appelée `__fusion`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Providers/FusionServiceProvider.php#L103C1-L110C12) utilisant SQLite, qui n'interfère pas avec la connexion de la base de données de l'application Laravel. Cela signifie qu'il est possible d'avoir plusieurs connexions de base de données au sein d'une seule application Laravel. Vraiment intéressant à savoir !

```php
public function boot()
{
  ConfigFacade::set('database.connections.__fusion', [
    'name' => '__fusion',
    'driver' => 'sqlite',
    'database' => Fusion::storage('fusion.sqlite'),
    'foreign_key_constraints' => true,
    'journal_mode' => 'OFF',
  ]);
}
```

> [!NOTE]
> Un fournisseur de services Laravel s'exécute lors du démarrage de l'application pour enregistrer des services ou lier des classes dans le conteneur de services. C'est un lieu capital pour gérer et configurer des services.

Le [modèle Component](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Models/Component.php#L7) utilise désormais cette connexion :

```php
<?php

namespace Fusion\Models;

use Illuminate\Database\Eloquent\Model;

class Component extends Model
{
    protected $connection = '__fusion';
}
```

Avec cette configuration, la classe `Component` utilise la connexion de base de données `__fusion`. Par conséquent, la base de données SQLite est uniquement utilisée par Fusion ; elle n'exerce aucun impact visible sur l'application Laravel, permettant à l'application de choisir librement son mode de connexion de base de données. C'est une stratégie simple et intelligemment mise en œuvre.

### Gestion des requêtes entrantes

Plongeons dans peut-être le segment le plus intrigant de l'article : la gestion des requêtes entrantes via Fusion.

En commençant à lire, nous avons largement couvert le développement, incluant le fonctionnement du plugin Vite et la transformation PHP. Notre tâche consiste maintenant à comprendre comment Fusion harmonise ces éléments pour la gestion des requêtes.

Fusion adopte une approche de routeur basé sur des fichiers. Les SFC de Vue s'enregistrent automatiquement en tant que routes au sein de l'application Laravel, réalisé en appelant [`Fusion` comme un facade](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Fusion.php), soutenu par [le gestionnaire Fusion](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionManager.php), qui est ensuite [enregistré dans le `FusionServiceProvider`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Providers/FusionServiceProvider.php#L30) dans le cadre de la configuration habituelle des routes dans `routes/web.php`.

```php
<?php

use Fusion\Fusion;

Fusion::pages();
```

Cela semble être toute l'explication mais continuons pour dévoiler davantage de complexités. Dans la méthode `pages`, [tous les composants SFC de Vue](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionManager.php#L67) situés dans `resources/js/Pages` sont localisés et [enregistrés méticuleusement](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionManager.php#L83). Utiliser le [routeur Laravel](https://laravel.com/docs/11.x/routing) facilite l'implémentation.

```php
Route::any($uri, [FusionController::class, 'handle'])
  ->defaults('__component', $component)
  ->defaults('__class', Component::where('src', $src)->first()?->php_class);
```

Notamment, le processus d'acheminement attribue deux valeurs par défaut :

1. `__component`: Chemin menant au fichier SFC de Vue.
2. `__class`: Nom de classe PHP pleinement qualifié, cette classe a été générée dans la commande `fusion:conform`.

Par conséquent, lorsqu'une requête accède à la route `/`, l'opération `handle` du `FusionController` s'active. À l'intérieur du contrôleur se trouve un système qui gère les différentes possibilités tout en synchronisant les actions, et en interagissant sans accroc avec le frontend.

Après la gestion des requêtes, une réponse appropriée est envoyée, guidée par la nature de la requête comme suit :

1. Les requêtes HMR ou d'action reçoivent [une réponse JSON](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionPage.php#L61-L63).
2. Les requêtes standards délèguent les tâches de rendu [à Inertia](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionPage.php#L65-L67).

L'attribut `data-page` révèle l'objet Inertia accompagné des composants Fusion associés :

```html
<div id="app" data-page="{&quot;component&quot;:&quot;Index&quot;,&quot;props&quot;:{&quot;errors&quot;:{},&quot;auth&quot;:{&quot;user&quot;:null},&quot;fusion&quot;:{&quot;meta&quot;:[],&quot;state&quot;:{&quot;name&quot;:&quot;AARON&quot;},&quot;actions&quot;:[{&quot;handler&quot;:&quot;applyServerState&quot;,&quot;priority&quot;:40,&quot;_handler&quot;:&quot;Fusion\\Http\\Response\\Actions\\ApplyServerState&quot;}]}},&quot;url&quot;:&quot;\/&quot;,&quot;version&quot;:&quot;f7e418d032bf1c4cc3cc55d947cab622&quot;,&quot;clearHistory&quot;:false,&quot;encryptHistory&quot;:false}"></div>
```

L'objet `fusion` est d'un intérêt particulier. Il est composé de données initialisées dans le bloc PHP du SFC de Vue via la fonction **prop** ; comprenant **state** et **actions** injectées au client en conséquence. La classe `PendingResponse`, responsable de la gestion, catégorise spécifiquement ces opérations au sein de Fusion [comme suit](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Http/Response/PendingResponse.php#L31-L43).

Spécifiquement, l'action `applyServerState` utilise :

```js
import { ref, unref } from 'vue'

export default function applyServerState({ fusion, state }, next) {
  Object.keys(fusion.state).forEach((key) => {
    state[key] = ref(unref(fusion.state[key]))
  })

  return next({ fusion, state })
}
```

Les développeurs bénéficient d'exploiter automatiquement le traitement des actions par Fusion sans appels manuels.

Je n'ai pas encore tout révélé. En plus d'extraire du bloc PHP du SFC de Vue, Fusion injecte de la logique JavaScript dans le SFC de Vue, précédant la transformation. Ce qui a commencé comme un composant initial :

```vue
<php>
use function \Fusion\{prop};

$name = prop('Aaron');
$name = strtoupper($name);
</php>

<template>
  Bonjour {{ name }} !
</template>
```

Se transforme durant la transformation du plugin Fusion (plus tard gérée par Vite) comme suit :

```vue
<script setup>
import { useFusion } from '$fusion/Pages/Index.js'
import useHotFusion from '@fusion/vue/hmr'

// __props est une variable magique fournie au script setup par Vue.
const __fusionData = useFusion(['name', 'fusion'], __props.fusion)

const { name, fusion } = __fusionData

useHotFusion(__fusionData, { id: 'hot_07f7c82af56ef80f306d905892430461', hot: import.meta?.hot })
</script>

<template>
  Bonjour {{ name }} !
</template>
```

Notez le bloc [`script setup`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/injectors/createScriptSetup.js) injecté synthétiquement, ne nécessitant aucun input manuel. Il présente un composable `useFusion`, acceptant deux arguments, le premier détaillant les clés de props nécessitant extraction (affinées par la reconnaissance des variables PHP via les appels à **prop**) et un argument `props` signifiant les props. En essence, cela ressemble à l'utilisation de `const props = defineProps()`. Fusion déclenche la variable `__props`, fournie par Vue, permettant aux développeurs d'écrire leur bloc `script setup` sans entraves. Cela permet de conserver la syntaxe normale des SFC de Vue non entravée par les processus Fusion.

Essentiellement, les valeurs composables `name` et `fusion` sont extraites via `script setup` avec une injection de modèle sans interruption.

D'où vient `useFusion` ? Le préfixe `$fusion/Pages` révèle la vue d'ensemble.

Concernant `$fusion/Pages`, nous avons déjà vu sa fonctionnalité en action via l'alias généré par le plugin Vite. Cet alias abstrait l'emplacement réel du fichier JavaScript, provenant d'une précédente entreprise formulant le `fusion:shim`. Son contenu se lit :

```js
import ActionFactory from '@fusion/vue/actionFactory'
import Pipeline from '@fusion/vue/pipeline'

export const state = ['name']
export const actions = []
export const fusionActions = ['fusionSync']

let cachedState

export function useFusion(keys = [], props = {}, useCachedState = false) {
  const state = (useCachedState && cachedState) ? cachedState : new Pipeline(props).createState()

  if (!useCachedState) {
    cachedState = state
  }

  const all = {
    ...state,
    ...new ActionFactory([...actions, ...fusionActions], state),
  }

  const shouldExport = {}
  for (const key of keys) {
    if (key in all) {
      shouldExport[key] = all[key]
    }
  }

  return shouldExport
}
```

Les variables `state` et `fusion` résident dans ce fichier, reflétant les déclarations du SFC de Vue dans les fonctions PHP **prop** et **expose**. Accompagné d'un `ActionFactory` responsable de l'application des actions imposées par le serveur à l'état, y compris `applyServerState`, la synchronisation automatique et transparente se produit.

En tout, Fusion propose plusieurs actions préétablies, telles que :

- [`applyServerState`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/actions/applyServerState.js): Synchronise les données d'état entre le backend et le client, mettant à jour l'état pour correspondre aux attentes du serveur en temps réel.
- [`syncQueryString`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/actions/syncQueryString.js): Synchronise les paramètres de chaîne de requête et l'état.
- [`log`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/actions/log.js): Permet l'enregistrement à des fins de débogage.
- [`logStack`](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/actions/logStack.js): Enregistre la progression de l'action pour le débogage.

La discussion devient encore plus captivante en voyant la fonction `expose`. Cette méthode exposent une fonctionnalité PHP côté serveur au client, créant des comportements de type RPC permettant à des requêtes côté client de déclencher des opérations côté serveur.

> [!NOTE]
> Le concept `expose` est apparenté à des approches comme [tRPC](https://trpc.io/) et [React Server Functions](https://react.dev/reference/rsc/server-functions).

Un exemple illustratif :

```vue
<php>
expose(favorite: function(Podcast $podcast) {
    return response()->json($podcast->toggleFavorite());
});
</php>

<template>
  <button @click="favorite({ podcast }).then(fav => podcast.favorited = fav)">
    Favori
  </button>
</template>
```

L'exposition d'une méthode comme `favorite` facilite son utilisation au sein du modèle. Le composable `useFusion` décrit précédemment gère la fonctionnalité, néanmoins, Fusion garantit un traitement approfondi permettant l'interaction de bouton côté client pour déclencher des opérations soutenues par le serveur.

1. Le client [envoie une requête au serveur](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/ActionFactory.js#L72-L77) pourvue des en-têtes `x-fusion-action-request` et `x-fusion-action-handler`.
2. Le backend traite ces requêtes, aidé par les métadonnées fournies, répondant au client en conséquence, semblable à [comment Inertia gère son protocole avec les en-têtes](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Http/Controllers/FusionController.php#L50).
3. L'état côté client correspond aux retours du serveur, [après traitement](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/vue/ActionFactory.js#L87).

Cliquer sur le bouton favori dans l'exemple ci-dessus génère cette requête ciblée vers le serveur :

```http
POST /search HTTP/1.1
Accept: application/json, text/plain, */*
X-Fusion-Action-Handler: favorite
X-Fusion-Action-Request: true

{
  "fusion": {
    "args": {
      "podcast": {
        "id": 1,
        "title": "Art Of Product",
        "author": "Derrick Reimer & Ben Orenstein",
        "image": "/art/art-of-product.jpg",
        "favorited": false,
        "created_at": "2025-02-15T18:01:36.000000Z",
        "updated_at": "2025-02-19T20:49:13.000000Z"
      }
    },
    "state": {
      "search": "",
      "podcasts": [
        {
          "id": 1,
          "title": "Art Of Product",
          "author": "Derrick Reimer & Ben Orenstein",
          "image": "/art/art-of-product.jpg",
          "favorited": false,
          "created_at": "2025-02-15T18:01:36.000000Z",
          "updated_at": "2025-02-19T20:49:13.000000Z"
        }
      ]
    }
  }
}
```

Pendant ce temps, le serveur traite ce type de requête en interprétant les en-têtes `x-fusion-action-request` et `x-fusion-action-handler`. Dans son fournisseur de services, Fusion [enregistre des macros de requête pour une identification et un traitement faciles des types de requête](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/Providers/FusionServiceProvider.php#L62-L65).

À l'intérieur du corps de la requête, `args` détient les arguments de la méthode (podcast), tandis que `state` comprend l'état actuel de l'application.

En réponse, le serveur envoie la suivante :

```json
true
```

Ce qui est la réponse de la méthode `favorite`. Le client met ensuite à jour l'état en conséquence.

Fusion offre une méthode `sync` favorisant la synchronisation des états entre le frontend et le backend. Par exemple, un champ de recherche pourrait filtrer des éléments basés sur des calculs du backend, réalisé via `sync`. Essentiellement, sync imite une action catégorisée par le gestionnaire `fusionSync` !

<!--## Comment le HMR fonctionne-t-il dans Fusion ?

Pour garantir la meilleure expérience développeur, Fusion tire parti du Hot Module Replacement (HMR) de Vite. Par conséquent, apporter des modifications à votre SFC de Vue transgresse les recharges de page complètes.

**En attente de l'avis d'Aaron**

-->

## Comment Fusion utilise-t-il Inertia ?

En vérité, Fusion simplifie ingénieusement et s'appuie sur l'intégration transparente d'Inertia pour traiter efficacement les SFC de Vue sans réinventer son framework frontend. La méthode [Inertia::render](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/src/FusionPage.php#L65-L67) illustre le rendu basé sur Inertia tandis que [createInertiaApp](https://github.com/fusion-php/fusion/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/apps/vue/resources/js/app.js#L11) établit l'environnement de l'application Vue de manière efficace, constituant l'ampleur totale de l'empreinte d'Inertia dans le projet Fusion.

Construire sur Inertia se révèle judicieux, permettant à Aaron de se concentrer sur l'innovation autour de l'objectif de Fusion sans être distrait par les complexités d'intégration de Vue au sein de Laravel. L'utilité d'Inertia annule toute redondance. De plus, transcender le parcours intermédiaire fait évoluer Fusion pour englober d'autres frameworks comme React de manière fluide.

## Dernières pensées

Fusion a un potentiel, notamment pour les développeurs en transition de Next ou Nuxt vers une capacité full-stack, accueillant avec enthousiasme Laravel avec Inertia. En préservant des concepts chers aux développeurs de ces frameworks, tels que le routage basé sur des fichiers et la communication pilotée par le RPC, tout en les enrichissant avec la puissance de Laravel, Fusion devient un choix convaincant. Vous devriez absolument l'essayer !

Au sein de la feuille de route de Fusion, Aaron envisage la compatibilité avec React, réalisable en s'appuyant sur les épaules d'Inertia. Toutefois, je suis impatient de voir la perspective d'Aaron sur la gestion de l'exécution du code serveur dans JSX, peut-être à l'aide d'une directive `'use php'` ? 🤔

Ce projet illustre efficacement la force de la relation profonde entre Vite et Laravel. Accéder sans effort à l'utilité complète de Vite demeure une capacité révolutionnaire. Cela réaffirme également la capacité modulaire du SFC dans Vue, Fusion le confirme assurément. Il n'y a pratiquement aucune limite à ce que vous pouvez réaliser en utilisant Vite et des composants SFC de Vue !

Enfin, la communication de la base de données SQLite inter-processus de Fusion renforce un modèle élégant et intelligent !

L'article a été passionnant à rédiger alors que j'explorais la base de code de Fusion. J'espère qu'il a révélé de nouvelles perspectives pour vous, et si vous êtes enclin à explorer les subtilités d'une autre bibliothèque, n'hésitez pas à commenter ou à utiliser la page [Demandez-moi tout](/ama).

Mais j'ai un supplément pour vous ! 👇

## Une dernière chose

Tout en rédigeant cet article, les exemples de code PHP en bloc fréquents manquaient de surlignement syntaxique approprié. J'ai réfléchi et décidé de m'attaquer à cette tâche. Puisque **Shiki** est utilisé pour la mise en surbrillance des codes sur ce site et qu'il utilise **TextMate grammars**, je sais que je pourrais ajouter le support pour le bloc PHP dans VSCode.

Mais comment ?

En fouillant, j'ai réalisé que l'intégration de langages dans des contextes à fichier unique n'est pas nouvelle. Les SFC de Vue sont notables, tout comme Markdown, Angular, et même HTML impliquant différents langages. Par la suite, je me suis concentré sur la grammaire TextMate des SFC de Vue.

> [!NOTE]
> Une grammaire TextMate définit les mises en surbrillance de syntaxe du langage de codage via des modèles et définit des règles. Fonctionnant derrière VSCode et Shiki, c'est le moteur du surligneur de syntaxe.

Examiner le [dépôt textmate-grammars-themes de Shikijs](https://github.com/shikijs/textmate-grammars-themes/) qui s'occupe de chaque langue et thème soutenu par Shiki a mis au jour la [grammaire Vue](https://github.com/shikijs/textmate-grammars-themes/blob/1355f60ed3897846cf33e31b8d2c06563a563db7/packages/tm-grammars/grammars/vue.json). Bien que long, des concepts éclairants émergent lors de la lecture, tels que les intégrations HTML, CSS, et JavaScript au sein des blocs respectifs:

```json
{
  "begin": "(script)\\b",
  "beginCaptures": {
    "1": {
      "name": "entity.name.tag.$1.html.vue"
    }
  },
  "end": "(</)(\\1)\\s*(?=>)",
  "endCaptures": {
    "1": {
      "name": "punctuation.definition.tag.begin.html.vue"
    },
    "2": {
      "name": "entity.name.tag.$2.html.vue"
    }
  },
  "patterns": [
    {
      "include": "#tag-stuff"
    },
    {
      "begin": "(?<=>)",
      "end": "(?=<\\/script\\b)",
      "name": "source.js",
      "patterns": [
        {
          "include": "source.js"
        }
      ]
    }
  ]
}
```

Cela gère la mise en surbrillance de JavaScript au sein des blocs `<script>` en utilisant l'inclusion de la grammaire JavaScript à travers `include`. Le même modèle s'applique probablement à d'autres langages, y compris PHP.

C'est exactement ce que je veux atteindre, mais avec `<php>` et la grammaire PHP. Bien sûr, il existe déjà une grammaire PHP, donc je dois juste l'inclure de la même manière. J'essaie, et ça fonctionne. Youpi ! 🥳

Mais attendez, je ne peux pas soumettre un PR à [Vue Language Tools](https://github.com/vuejs/language-tools) (Shiki récupère la grammaire de ce dépôt) pour ajouter le support de la grammaire PHP. Cela n'a aucun sens, et il n'y a aucune raison de leur part de l'accepter. Donc, je dois trouver une autre solution.

Après avoir continué ma recherche, j'ai trouvé la grammaire [angular-inline-style](https://github.com/shikijs/textmate-grammars-themes/blob/main/packages/tm-grammars/grammars/angular-inline-style.json). Celle-ci est utilisée pour mettre en évidence les styles (CSS, SCSS) à l'intérieur d'un composant Angular (TypeScript). Pour ce faire, la grammaire utilise le mot clé injectTo, qui agit comme une extension d'une grammaire existante, dans ce cas, source.ts.ng. C'est parfait ! Que se passerait-il si je créais une nouvelle grammaire qui étend la grammaire Vue en injectant la grammaire PHP ? Rétrospectivement, cela semblait plus facile que cela ne l'a été en réalité.

Après quelques heures d'essais et d'erreurs, j'ai finalement réussi à créer une grammaire qui fonctionne dans Shiki. L'un des éléments les plus compliqués a été de comprendre ce qui n'allait pas lorsque les choses ne fonctionnaient pas. Avec ce genre de configuration, il n'y a pas de messages d'erreur, pas d'avertissements, rien. Vous devez juste deviner ce qui ne va pas. Vous pouvez trouver la solution fonctionnelle dans le code source de [mon générateur de code en image](https://github.com/barbapapazes/code.soubiran.dev).

Enfin, j'ai créé une extension VSCode que tout le monde peut utiliser pour ajouter le support des blocs PHP dans les SFC de Vue. Vous pouvez la trouver sur le [marketplace](https://github.com/Barbapapazes/fusion-vscode) avec la grammaire fonctionnelle : [source.vue.php](https://github.com/Barbapapazes/fusion-vscode/blob/main/syntaxes/vue.php.tmLanguage.json).

Si Fusion devient populaire, je pourrais éventuellement soumettre un PR pour ajouter le language à Shiki, rendant plus facile à tous la mise en surbrillance des blocs PHP.

Bon code ! 👨‍💻
