Це справді особлива стаття.
Два тижні тому, 3–4 лютого 2025 року, в Амстердамі пройшла конференція Laracon EU. Хоча я не зміг бути там особисто, я уважно стежив за подією через стрім. Такі конференції — це завжди шанс отримати свіжі інсайди та ще глибше зануритися в неймовірну ecosystem Laravel. Сподіваюся, колись я все ж потраплю на Laracon наживо.
Особливо мою увагу привернула доповідь Aaron Francis — «Introducing [REDACTED]: A New Paradigm for Laravel + Javascript». Це заінтригувало, адже ми вже маємо Inertia та Livewire — чудові інструменти для сучасних додатків на Laravel. Що ж нового можна запропонувати?
![]()
Аарон представив Fusion — інноваційний підхід до інтеграції фронтенду з Laravel-бекендом. Ідея в тому, щоб писати PHP-код безпосередньо у файлі фронтенду. Після обробки цей PHP виконується на стороні сервера, а результати передаються на клієнт. Це нагадує Inertia, але йде значно далі.
Обов'язково подивіться відео. Воно захоплює, легко сприймається і допоможе краще зрозуміти решту цієї статті.
У інтерв'ю для подкасту Navbar Аарон пояснив мету Fusion: стерти межу між фронтендом та бекендом, спростити розробку та наблизити Laravel з Inertia до можливостей сучасних meta-frameworks на кшталт Next або Nuxt. Разом зі своїм партнером Steve Аарон помітив, що звичні для Laravel концепції (як-от роути у web.php) не завжди інтуїтивні для JavaScript-розробників, які звикли до file-based routing. Fusion має зробити Laravel доступнішим для JS-спільноти.
Завдяки Fusion у Vue SFC з'являється новий блок для PHP-коду, що робить його невід'ємною частиною додатка.
<php>
// Визначаємо prop на PHP
$name = prop(Auth::user()->name);
</php>
<template>
<!-- Використовуємо його у Vue! -->
Hello {{ name }}!
</template>
Ця стаття не про те, чи варто використовувати Fusion у продакшені або чи етично писати PHP всередині Vue SFC. Ці дискусії вже активно точаться на X та Reddit.
Натомість я хочу розібратися, як Fusion працює «під капотом», з двох причин:
- Аналіз чужого коду — найкращий спосіб навчання. Я часто вивчаю кодові бази проектів, щоб знайти цікаві прийоми та патерни, які інші могли пропустити.
- Fusion — це технічний пік того, чого можна досягти за допомогою Laravel, Vue та Vite. Мені було щиро цікаво зрозуміти його механіку. Аналогічно я вивчаю бібліотеку Alien Signals від Johnson Chu. А щоб розібратися в чомусь досконало, варто спробувати пояснити це іншим.
Інтеграція Vite з Laravel просто неймовірна. Якщо ви ще не дослідили можливості Vite, обов'язково зробіть це.
А тепер зануримося в код.
Вивчати цей codebase дуже цікаво — це схоже на читання PHP, написаного мовою JavaScript.
# Codebase проекту Fusion
Через тиждень після Laracon EU Аарон відкрив код Fusion. Мені здавалося, що все тримається на плагіні Vite, який витягує PHP із Vue SFC, подібно до того, як стандартний плагін Vue обробляє script, template та style.
Для Vite підтримка HTML, CSS та JavaScript є природною. Однак PHP — це виклик, оскільки Vite не підтримує його «з коробки».
Давайте сформулюємо питання, на які ми знайдемо відповіді. Перше: як саме Fusion керує PHP-кодом?
Переглядаючи промо-відео, стає зрозуміло: Fusion робить більше, ніж просто витягує код. Він передає результати PHP-коду як props у Vue-компонент і підтримує RPC-виклики до Laravel-бекенда прямо з клієнта. Крім того, ключове слово sync дозволяє синхронізувати стан між фронтендом і бекендом.
Наприклад, функція favorite стає доступною на фронтенді миттєво:
<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>
Виникає друге питання: які механізми працюють за лаштунками, щоб усе це стало можливим?
І нарешті: Fusion позиціонується як інструмент, що виводить Inertia на новий рівень. Отже, як саме Fusion використовує Inertia?
Розберемося по черзі.
# Як Fusion керує PHP-кодом?
Усе починається з Vite. Як і завжди.
Для тих, хто не в курсі: Vite — це надшвидкий інструмент збірки фронтенду. Його філософія — обробка «на вимогу» (on-demand). Vite виступає проксі-сервером між браузером і файловою системою. Коли браузер запитує файл, Vite перехоплює запит, трансформує код, ін'єктує потрібні фрагменти або навіть генерує віртуальні файли. Завдяки системі плагінів Vite можна адаптувати під будь-які потреби.
Ось як Vite зазвичай обробляє файл SFC:
<script setup>
// JavaScript код
</script>
<template>
<div />
</template>
<style scoped>
/* CSS код */
</style>
Коли браузер запитує .vue файл, плагін vite-plugin-vue перетворює його на валідний JavaScript. CSS виноситься в окремий потік обробки. За допомогою плагіна vite-plugin-inspect можна побачити цей процес крок за кроком.
У Fusion відбувається те саме, але додається обробка PHP-блоку. Коли запит надходить на Vite, плагін fusion-vue активує функцію transform:
function transform(code, filename) {
if (!filename.endsWith('.vue')) {
return code
}
return new Transformer({
config: fusionConfig,
code,
filename,
isProd
}).transform()
}
Клас Transformer виконує наступні завдання:
- Витягує PHP-блок із Vue SFC за допомогою парсера @vue/compiler-sfc. До речі, подібний підхід використовує Vue I18n для своїх блоків перекладів.
import { parse } from '@vue/compiler-sfc'
const descriptor = parse(code, { filename }).descriptor
const php = descriptor.customBlocks.find(block => block.type === 'php')
- Видаляє PHP-блок з оригінального файлу, щоб він не заважав подальшій обробці Vue.
- Перевіряє актуальність коду. Якщо код не змінився (перевірка за хешем), трансформація пропускається.
- Валідує та зберігає PHP. Для цього викликається Laravel-команда:
await runPhp(['fusion:conform', this.relativeFilename])
Якщо в PHP-коді є помилка, Vite перехоплює її та виводить інформативне повідомлення прямо в браузері.

Якщо все добре, PHP-код зберігається в папці storage як окремий файл.
- Створює JavaScript-файл (shim). Цей файл є «містком» між фронтендом та PHP-частиною. Тут знову викликається Laravel:
await runPhp(['fusion:shim', this.relativeFilename])
- Повертає трансформований код у Vite для завершення збірки.
Це створює певну складність. Fusion працює як file-based router: перший запит йде на PHP-сервер, який віддає початковий код, а вже потім браузер звертається до Vite. Але якщо ми ще не відвідали маршрут, відповідного PHP-файлу в storage може не існувати. Щоб вирішити це, Fusion використовує власний watcher.
Vite-плагін Fusion робить дві важливі речі через watcher (Chokidar):
- Очищує застарілі файли у
storageпри видаленні компонентів. - Запускає трансформацію при зміні файлів, не чекаючи запиту від браузера. Це гарантує, що PHP-файли завжди готові до роботи, навіть якщо ви щойно створили новий роут.
Ось загальна схема процесу:

# Що відбувається на стороні PHP?
Після того як Vite витягнув PHP-код, його потрібно інтегрувати в екосистему Laravel. Цим займається команда fusion:conform.
# Обробка та трансформація PHP
Код, витягнутий із SFC, не може бути виконаний просто так — його потрібно перетворити на повноцінний клас. Fusion використовує серію «трансформерів» (на базі PHP Parser), які крок за кроком змінюють код:
- Procedural Transformer: перетворює процедурний код на метод
runProceduralCodeанонімного класу. - Props Transformer: замінює виклики
prop()на внутрішні методи класу. - Anonymous Class Transformer: створює іменований клас у спеціальному просторі імен
Fusion\Generated.
Результатом є клас, що успадковує FusionPage. Він діє як міні-контролер, що обробляє логіку конкретної сторінки та синхронізує змінні між сервером і клієнтом.
# База даних Fusion
Fusion використовує окрему базу даних SQLite (fusion.sqlite), щоб координувати роботу PHP та JavaScript. Там зберігаються зв'язки між шляхами до SFC-файлів, згенерованими класами та хешами коду. Fusion реєструє окреме з'єднання __fusion, тому це ніяк не впливає на основну базу вашого додатка.
# Обробка запитів та роль Inertia
Fusion автоматично реєструє роути для всіх SFC у resources/js/Pages. Коли ви заходите на сторінку, FusionController вирішує, що робити:
- Для звичайного запиту — рендерить сторінку через Inertia.
- Для RPC-запитів (через
expose) або синхронізації — повертає JSON.
Fusion ін'єктує у ваш Vue-компонент спеціальний script setup, який містить composable useFusion. Це дозволяє прозоро використовувати змінні та функції, визначені в PHP-блоці, так само як звичайні JS-змінні.
# Підсумки
Fusion має великий потенціал, особливо для розробників, які переходять з Nuxt/Next на Laravel. Він зберігає звичний досвід (file-based routing, RPC), але додає потужність Laravel.
Цей проект демонструє, наскільки глибокою може бути синергія Vite та Laravel. Fusion не намагається замінити Inertia — він використовує її як надійний фундамент, зосереджуючись на інноваціях у самій структурі коду.
Дослідження цього проекту було справжньою пригодою. Сподіваюся, цей аналіз відкрив для вас щось нове!
# Ще дещо
Під час написання статті я помітив, що для PHP-блоків у Vue SFC немає підсвічування синтаксису. Оскільки мій сайт використовує Shiki та TextMate grammars, я вирішив це виправити.
Я створив розширення для VSCode, яке додає підтримку блоків <php> у файлах .vue. Ви можете знайти його на marketplace. Тепер писати Fusion-компоненти значно приємніше!
Успішного кодингу! 👨💻