Fusion — php стал ещё ближе к javascript
- вторник, 25 февраля 2025 г. в 00:00:06
Каждый PHP-разработчик, работая с современными JavaScript-фреймворками, наверняка задумывался о том, как было бы здорово передавать данные напрямую в компоненты без танцев вокруг контроллеров и типов данных. Арон Френсис, видимо, тоже терзал себя этим вопросом, поэтому 4 февраля 2025 года на своём ютуб-канале представил новую веху развития фронтенда на Laravel — Fusion. В этом статье мы рассмотрим базовые принципы работы библиотеки и основные нюансы работы с ней.
У Laravel уже есть Inertia, которая позволяет использовать vue шаблоны для рендеринга, напрямую передавая туда данные из php, но всё-равно требовалось писать контроллеры и вручную передавать данные в шаблоны. Fusion решает эту проблему
Что делает Fusion:
Использует Vite для извлечения PHP-блоков из JavaScript-файлов и сохраняет их на диск.
В процессе трансляции использует Vite для добавления информации в JavaScript-файлы.
Запускает PHP на бэкенде, а JavaScript — на фронтенде.
Превращает PHP-блоки в подобие контроллеров.
Использует стандартный жизненный цикл запроса/ответа Laravel, включая маршрутизацию, аутентификацию, middleware и т. д.
Позволяет вам управлять синхронизацией состояния frontend/backend.
Можно представить <php>-блок в вашем файле как контроллер, к которому автоматически подключается состояние и добавляются вызовы методов.
Fusion поддерживает два стиля написания php-кода в SFC
(single file components) — процедурный и классовый.
Процедурный:
<php>
// Определяем пропс в PHP
$name = prop(Auth::user()->name);
</php>
<template>
<!-- Используем его во Vue! -->
Hello {{ name }}!
</template>
Class-based (классовый):
<php>
new class {
// Определяем пропс в PHP
public string $name;
public function mount()
{
$this->name = Auth::user()->name;
}
}
</php>
<template>
<!-- Используем его во Vue! -->
Hello {{ name }}!
</template>
Код выше позволяет передать переменную $name
в ваш шаблон Vue в качестве name
. Она будет передана приложению при первой загрузке. Вам не нужно определять какие-либо пропсы на стороне Vue, библиотека позаботится об этом вместо вас.
Теперь, чтобы разобраться с магией, мы рассмотрим жизненный цикл Fusion. Он состоит из четырёх этапов.
Когда вы выполняете npm run dev
или npm run build
, запускается Vite. Fusion добавляет в процесс плагин, который перехватывает работу над Vue-компонентами до того, как их обработает Vue-плагин.
Fusion-плагин ищет <php>-блоки. Если они найдены, код извлекается и передается Artisan-команде:
php artisan fusion:conform
Она, в свою очередь, делает так, что:
Код проходит серию парсеров, чтобы соответствовать стандарту Fusion.
PHP-файл записывается на диск.
Этот процесс выполняется на этапе сборки, а не во время выполнения скрипта (для экономии ресурсов).
После валидации PHP-блоков выполняется команда:
php artisan fusion:shim
Она запускает следующие процессы:
Создается небольшой JavaScript-файл с информацией о свойствах состояния и доступных методах.
В этом файле находится функция useFusion
. Для каждого компонента создается своя useFusion.
Стоит заметить, что вы не обязаны импортировать useFusion
, Fusion автоматически подключит ее в Vue-компонент. Однако, если хотите вручную управлять состоянием и методами, можете использовать useFusion
в script
или script setup
.
После генерации PHP-класса Fusion использует стандартный жизненный цикл Laravel запросов и ответов:
Ходящие запросы обрабатывает FusionController, который направляет их в соответствующий PHP-класс (из Vue-шаблона).
Если запрос — страничный (открытие страницы), возвращается Inertia-ответ с названием нужного компонента.
Если отправляется запрос действия (например, вызов метода), ответ передается фронтенду для обработки.
Fusion поддерживает только Laravel приложения, использующие Inertia, но в будущем это, по словам авторов, может измениться.
Для первоначальной установки требуется поставить нужный пакет:
composer require fusionphp/fusion
После — запустить скрипт установки:
php artisan fusion:install
Скрипт сделает следующее:
опубликует конфиг (config/fusion.php),
создаст нужные директорий в storage,
добавит Vue-пакет в package.json,
изменит postinstall-скрипт и добавит fusion:install,
подключит Vue-плагин в resources/js/app.js,
подключит Vite-плагина в vite.config.js,
добавит post-update-cmd в composer.json,
выполнит миграцию внутренней SQLite-базы Fusion.
Кроме этого, Fusion создает резервные файлы ([original].backup
) на случай ошибок. Копии можно удалить, если всё работает корректно.
Запуск и сборка происходит с помощью Vite, собственно, командами npm run dev
и npm run build
.
Fusion представляет на выбор 2 пути для маршрутизации: file-based или индивидуальное назначение маршрутов для компонентов.
Удобный способ автоматической маршрутизации, когда структура URL отражает структуру файлов в вашем проекте.
Для включения файлового роутинга в web.php
используется метод Fusion::pages()
:
use Fusion\Fusion;
Fusion::pages();
По умолчанию маршрутизируются все файлы из resources/js/Pages (настраивается в config/fusion.php под ключом paths.pages), начиная с корневого URI /.
Каждый .vue-файл в этой директории становится страницей, даже без <php>-блока, где название файла преобразуется в рут, например, HelloWorld.vue
→ /hello-world
Привязка моделей к маршрутам в Fusion позволяет автоматически включать экземпляры моделей Laravel в ваш код на основе параметров маршрута, вместо того чтобы вручную искать их по ID или другим ключам. Это работает аналогично стандартному механизму Laravel, но адаптировано для интеграции с файловым роутингом Fusion.
Route Model Binding используется с файловым роутингом, где параметры маршрута задаются в именах файлов с помощью квадратных скобок, например, Podcasts/[Podcast].vue
. При посещении URL вроде /podcasts/
1 Fusion может автоматически подтянуть модель вместо передачи строки "1".
Для получения данных в процедурном стиле достаточно использовать метод fromRoute()
с указанием класса модели:
<php>
$podcast = prop()->fromRoute(class: \App\Models\Podcast::class);
</php>
Для классового же укажите тип параметра в методе mount
или свойстве:
<php>
new class {
public function mount(\App\Models\Podcast $podcast) {
// $podcast — экземпляр модели
}
}
// или же
new class {
public \App\Models\Podcast $podcast; // Автоматически привязывается
}
</php>
Если модель не найдена, то вернётся ошибка 404.
Для создания ручных маршрутов в Fusion используется метод Fusion::page()
в файле web.php
. Этот метод связывает конкретный URI с определённым компонентом. Вот пример:
// web.php
use Fusion\Fusion;
Fusion::page(uri: '/hello-world', component: 'Custom/HelloWorld');
Кроме способа, который мы рассматривали выше, для большего контроля, получить переменную состояния из php можно с помощью композабла useFusion
. Она позволяет импортировать состояние и действия в ваши JavaScript-скрипты.
<php>
new class {
public string $name = 'Aaron';
public string $email = 'aaron@example.com';
}
</php>
<script setup>
import { useFusion } from '$fusion/Pages/Hello.js';
const { name } = useFusion(['name']);
</script>
<template>
Hello {{ name }}, your email is {{ email }}!
</template>
Здесь мы импортировали только name через useFusion
, а email продолжает автоматически внедряться в шаблон. Это полезно, если вам нужно работать с конкретными частями состояния в JavaScript.
Если же вы хотите получить доступ ко всему состоянию, можно сделать так:
const data = useFusion();
Действия (Actions) в Fusion — это удобный механизм для взаимодействия между фронтендом (JavaScript) и бэкендом (PHP) в приложениях на Laravel. Они позволяют вызывать серверные функции из клиентской части, обеспечивая автоматическое управление состоянием, обработку ошибок и валидацию. Давайте разберём, как они работают, как их определять и использовать.
1. Процедурный стиль. В этом подходе действия задаются через функцию expose
. Каждое действие передаётся как именованный аргумент в виде анонимной функции:
expose(
hello: function() {
return "Привет!";
},
anotherAction: function() {
return "Другое действие";
}
);
2. Классовый стиль. В классовом стиле действия задаются в качестве публичных методов анонимного класса. Все публичные методы становятся действиями, которые можно вызвать со стороны javascript:
new class {
public function hello() {
return "Привет!";
}
public function anotherAction() {
return "Другое действие";
}
};
Если вы хотите, чтобы какой-то метод не был доступен на фронтенде, используйте атрибут #[ServerOnly]
:
use Fusion\Attributes\ServerOnly;
new class {
#[ServerOnly]
public function internalMethod() {
// Этот метод доступен только на сервере
}
};
Fusion не обновляет состояние автоматически при каждом изменении на фронтенде. Вместо этого синхронизация происходит в двух случаях:
При вызове действий:
Когда вы вызываете действие (например, через @click="someAction"
), текущее состояние фронтенда отправляется на бэкенд, обновляется там, а затем возвращается на фронтенд.
С помощью fusion.sync:
Это магическая функция, которая позволяет вручную синхронизировать состояние.
Действия, определенные в php, становятся доступны в js как функции. Например, если на бэкенде есть метод favorite
, вы можете использовать его так:
<template>
<button @click="favorite">Favorite</button>
</template>
Каждое действие в Fusion — это не просто функция, а прокси-объект, который содержит информацию о состоянии запроса. Это позволяет отслеживать выполнение действия и реагировать на него в интерфейсе. Доступные свойства:
processing: Запрос выполняется.
succeeded: Запрос успешно завершён.
recentlySucceeded: True, но становится false через 3.5 секунды (удобно для флеш-сообщений).
failed: Запрос завершился с ошибкой.
recentlyFailed: Выдает сообщение об ошибке, становится false через 3.5 секунды.
finished: Запрос завершён (успешно или с ошибкой).
recentlyFinished: Запрос завершён, становится false через 3.5 секунды.
error: Объект с ошибками (например, ошибки валидации из ответа 422).
errors: Массив сообщений об ошибках.
Пример с отслеживанием статуса:
<template>
<button @click="favorite">Favorite</button>
<div v-if="favorite.processing">Загрузка...</div>
<div v-if="favorite.succeeded">Успех!</div>
</template>
Fusion — это мощный инструмент, который упрощает создание современных веб-приложений на Laravel и Vue.js. Благодаря Vite он обеспечивает быструю разработку и оптимизацию, а как дополнение к Inertia.js предлагает более тесную и удобную связь между фронтендом и бэкендом. На мой взгляд, это делает Fusion интересным выбором для тех, кто ищет эволюцию привычных подходов к интеграции в будущем.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
-15% на заказ любого VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.