PHP на сервере и JavaScript на клиенте — классическое сочетание, которое, несмотря на свою эффективность, создает определенный когнитивный диссонанс при разработке. В этом контексте появляются различные решения, пытающиеся сгладить этот разрыв, и одним из таких революционных подходов стал Fusion.
Fusion — это новый инструмент, представленный в феврале 2025 года на конференции Laracon EU, который позволяет писать PHP-код непосредственно в Vue SFC (Single File Components). Это кардинально меняет парадигму разработки, объединяя серверную и клиентскую логику в одном файле. По сути, Fusion — это мост между backend и frontend, который устраняет необходимость дублирования кода и логики между серверной и клиентской частями приложения.
Особенности синтаксиса и отличия Fusion от Livewire и Inertia.js
Синтаксис Fusion отличается лаконичностью и интуитивностью. Вместо создания отдельных контроллеров и компонентов, разработчик может написать код в едином файле:
| TypeScript | 1
2
3
4
5
6
7
8
9
| <php>
// Определение пропса в PHP
$name = prop(Auth::user()->name);
</php>
<template>
<!-- Использование в Vue! -->
Hello {{ name }}!
</template> |
|
В отличие от Livewire, который полностью основан на PHP и генерирует JavaScript под капотом, Fusion сохраняет преимущества Vue SFC, при этом позволяя напрямую интегрировать PHP-код. Если сравнивать с Inertia.js, который соединяет Laravel и JavaScript-фреймворки через JSON API, Fusion идет дальше, предлагая более тесную интеграцию кода.
Где завкладка “Vue” в консоле моего Vue.js приложения ? Всем привет
Я установил Vue.js devtools на Google Chrome Version 85.0(kubuntu 18)
Но я не вижу... Vue.js не видит пути из vue.config.js Здравствуйте. Пытаюсь сделать многостраничное приложение. Следую инструкции для Vue.js 3, сделал... Vue.draggable + vue-lazyload Есть лист на 800+ элементов, и количество элементов будет только увеличиваться. Реализовано это всё... vue 3. Как использовать метод из миксина с параметрами в компоненте vue по нажатию на кнопку? Как вызвать метод query в компонент при клике на кнопку Subscribe
axiosMixin.js
const...
Ключевые проблемы традиционных методов обмена данными
Традиционные методы обмена данными между PHP и фронтендом страдают от нескольких фундаментальных проблем:
1. Избыточный сетевой обмен — каждый запрос данных требует отдельного HTTP-запроса.
2. Дублирование кода валидации и бизнес-логики на фронтенде и бэкенде.
3. Сложность поддержания согласованности между моделями данных.
4. Необходимость создания и поддержки API-контрактов.
5. Разрыв контекста разработки, вынуждающий программиста постоянно переключаться между разными файлами.
Fusion решает эти проблемы, позволяя работать в едином контексте компонента. Более того он делает возможным вызов PHP-функций с фронтенда почти так же просто, как вызов JavaScript-функций, используя механизм RPC (Remote Procedure Call).
Целевая аудитория Fusion
Fusion особенно привлекателен для определенных групп разработчиков:- Команды с сильным PHP-бэкграундом, желающие использовать современный фронтенд без глубокого погружения в JavaScript-экосистему.
- Разработчики Laravel, стремящиеся упростить архитектуру своих приложений.
- Проекты с интенсивным обменом данными между клиентом и сервером.
- JavaScript-разработчики, приходящие в экосистему Laravel, которым привычнее файловая маршрутизация и компонентный подход.
Fusion может быть особенно полезен в проектах, где требуется быстрое прототипирование и итеративная разработка функционала с тесной интеграцией клиентской и серверной частей.
Концепция Vue SFC в контексте Fusion
Vue SFC (Single File Components) — это подход, при котором шаблон, логика и стили компонента объединяются в одном файле с расширением .vue. Это делает компоненты более самодостаточными и реализует принцип инкапсуляции на уровне файловой системы. Традиционно Vue SFC включает три секции:
<template> — HTML-разметка компонента,
<script> — JavaScript-логика,
<style> — CSS-стили.
Fusion расширяет эту концепцию, добавляя новую секцию <php>, в которой можно писать PHP-код. Этот код выполняется на сервере, а результаты передаются на фронтенд как пропсы компонента. Такое расширение позволяет использовать все возможности PHP-экосистемы (ORM, аутентификацию, валидацию и т.д.) непосредственно в контексте Vue-компонента. Это не просто синтаксический сахар, а фундаментальное изменение способа взаимодействия фронтенда и бэкенда. По сути, Fusion делает для Laravel то же, что современные метафреймворки вроде Next.js или Nuxt.js делают для React и Vue соответственно — сближает серверную и клиентскую разработку, делая процесс более интегрированным и интуитивным.
Технический обзор Fusion
Fusion представляет собой технологическую связку между PHP-бэкендом и Vue-фронтендом, функционирующую на принципах единого источника истины для данных и автоматической синхронизации состояний. Вместо создания дополнительных слоев абстракции, Fusion органично вписывается в существующий стек технологий, расширяя возможности стандартных компонентов Vue SFC.
Принципы работы и архитектура
В основе архитектуры Fusion лежит плагин для Vite, который обрабатывает файлы .vue и извлекает из них PHP-код. Этот код затем валидируется, трансформируется в формат, совместимый с Laravel, и сохраняется в специально выделенной директории. При обращении к соответствующему маршруту сгенерированный PHP-класс выполняется, а результаты передаются обратно во фронтенд как пропсы Vue-компонента. Схематически процесс работы Fusion можно представить так:
1. Vue SFC с PHP-блоком → Плагин Vite → Извлечение PHP-кода.
2. Валидация и трансформация PHP → Генерация PHP-класса.
3. Создание JavaScript-шима для связи с PHP.
4. Регистрация маршрута в Laravel.
5. Выполнение PHP-кода при обращении к маршруту.
6. Передача данных в Vue через Inertia.
7. Двусторонняя синхронизация состояний.
Для хранения метаданных о компонентах Fusion использует локальную SQLite базу данных, что позволяет эффективно связывать фронтенд и бэкенд без влияния на основную базу данных приложения.
Инструменты и зависимости, необходимые для работы с Fusion
Для полноценной работы с Fusion требуется следующий набор технологий:
Laravel 10+ – основной фреймворк для бэкенда,
Vue 3 – фронтенд-фреймворк для создания компонентов,
Vite – современный сборщик фронтенда,
Inertia.js – библиотека, связывающая Laravel и Vue,
Node.js – среда выполнения JavaScript,
SQLite – для внутреннего хранения метаданных.
Важно понимать, что Fusion не заменяет Inertia.js, а надстраивается над ним, существенно расширяя его возможности. Это позволяет использовать привычные подходы к разработке на Inertia, добавляя к ним новые возможности Fusion.
Жизненный цикл Fusion-компонента от написания до рендеринга
Жизненный цикл компонента начинается с создания файла .vue, содержащего блок <php>:
| TypeScript | 1
2
3
4
5
6
7
8
9
| <php>
use function \Fusion\{prop};
$name = prop('Мир');
$name = strtoupper($name);
</php>
<template>
Привет, {{ name }}!
</template> |
|
При запуске сервера разработки или изменении файла плагин Vite обнаруживает PHP-блок, извлекает его и запускает процесс валидации. Если код корректен, он трансформируется в PHP-класс:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <?php
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: 'Мир')->value();
$name = strtoupper($name);
$this->syncProps(get_defined_vars());
}
} |
|
Одновременно генерируется JavaScript-шим для связи с этим классом, а в исходный Vue-компонент добавляется скрипт для использования этого шима:
| TypeScript | 1
2
3
4
5
6
7
| <script setup>
import { useFusion } from '$fusion/Pages/Index.js'
import useHotFusion from '@fusion/vue/hmr'
const __fusionData = useFusion(['name', 'fusion'], __props.fusion)
const { name, fusion } = __fusionData
</script> |
|
При обращении к маршруту Laravel выполняет соответствующий PHP-класс, подготавливает данные и передает их через Inertia в Vue-компонент, который использует их для рендеринга.
Механизмы обработки состояний и реактивных данных в Fusion
Fusion предлагает два основных механизма для работы с данными: prop() для определения свойств и expose() для экспорта серверных методов. Функция prop() создает реактивное свойство, которое автоматически синхронизируется между сервером и клиентом. Свойства могут быть простыми значениями или функциями, возвращающими данные:
| TypeScript | 1
2
3
4
5
6
| <php>
use function \Fusion\{prop};
use \App\Models\Podcast;
$podcasts = prop(fn () => Podcast::all())->readonly();
</php> |
|
Функция expose() открывает серверные методы для вызова с клиента, формируя RPC-интерфейс:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
| <php>
use function \Fusion\{expose};
use \App\Models\Podcast;
expose(favorite: fn (Podcast $podcast) => response()->json($podcast->toggleFavorite()));
</php>
<template>
<button @click="favorite({ podcast }).then(fav => podcast.favorited = fav)">
Избранное
</button>
</template> |
|
Это позволяет вызывать PHP-методы прямо из шаблона или JavaScript-кода, как если бы они были обычными клиентскими функциями. Дополнительно Fusion предоставляет функцию sync() для двунаправленной синхронизации состояния, что особенно удобно для форм и других интерактивных элементов.
Внутреннее устройство компилятора Fusion
При трансформации PHP-кода Fusion использует серию специализированных трансформеров, каждый из которых отвечает за определенный аспект преобразования. Среди них:
ProceduralTransformer – преобразует процедурный код в метод класса.
PropsTransformer – обрабатывает вызовы функции prop().
ExposeTransformer – преобразует вызовы функции expose().
PropDiscoveryTransformer – обнаруживает имена свойств.
ActionDiscoveryTransformer – находит и создает методы для обработчиков действий.
Процесс трансформации использует библиотеку PHP Parser для анализа и модификации PHP-кода, что позволяет создавать корректные PHP-классы из произвольного кода в блоке <php>. На стороне JavaScript Fusion генерирует композабл useFusion, который извлекает данные из пропсов и предоставляет доступ к серверным методам. Это создает единый интерфейс для работы с данными, независимо от их источника.
Анализ производительности: сравнение нативного Vue и Fusion
В плане производительности Fusion находится на уровне нативных Vue-приложений на Inertia, поскольку фактический рендеринг все равно происходит на стороне клиента с использованием Vue. Основные отличия касаются начальной загрузки (где Fusion может добавить небольшую задержку из-за дополнительных преобразований) и последующи взаимодействий (где Fusion потенциально может быть эффективнее за счет оптимизированного обмена данными). Для приложений средней сложности эти различия практически незаметны, а преимущества в скорости разработки и поддержки могут значительно перевешивать любые теоретические потери в производительности.
Сравнение с традиционными подходами к интеграции PHP и Vue
По сравнению с традиционными подходами, Fusion предлагает несколько существенных преимуществ:
1. Единый контекст разработки – вместо создания отдельных контроллеров и компонентов, вся логика находится в одном файле.
2. Отсутствие дублирования кода – нет необходимости дублировать валидацию и бизнес-логику.
3. Прозрачный RPC – вызов серверных методов выглядит как обычный вызов JavaScript-функций.
4. Файловая маршрутизация – маршруты автоматически создаются на основе структуры файлов, как в Next.js или Nuxt.js.
В традиционном подходе с REST API разработчику приходится создавать контроллеры, определять маршруты, создавать JavaScript-код для взаимодействия с API и т.д. Fusion автоматизирует большую часть этого процесса, делая разработку более быстрой и интуитивной.
Процесс компиляции компонентов
Углубимся в технические аспекты преобразования PHP-кода в Fusion. Процесс компиляции компонентов является комплексным и включает несколько ключевых этапов:
1. Обнаружение и извлечение – с помощью парсера @vue/compiler-sfc плагин Fusion извлекает блок <php> из Vue SFC.
2. Валидация синтаксиса – извлеченный PHP-код проверяется на корректность с использованием PHP Parser.
3. Конформация – код преобразуется в структуру, совместимую с Laravel, с применением цепочки трансформеров.
4. Генерация класса – создается PHP-класс с необходимыми методами и свойствами.
5. Генерация шима – создается JavaScript-файл для связи с серверным кодом.
Каждый из этих этапов имеет свои особенности и технические нюансы, которые делают Fusion таким мощным инструментом.
Детальный анализ Vite-плагина
Работа Fusion начинается с Vite-плагина, который интегрируется в процесс сборки фронтенда. Этот плагин выполняет две ключевые функции:
1. Трансформация – обрабатывает Vue SFC при запросе через функцию transform:
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
| function transform(code, filename) {
if (!filename.endsWith('.vue')) {
return code
}
return new Transformer({
config: fusionConfig,
code,
filename,
isProd
}).transform()
} |
|
2. Наблюдение за файловой системой – мониторит изменения во всём проекте:
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 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()
}
})
} |
|
Наблюдение за файловой системой позволяет Fusion оперативно реагировать на изменения Vue SFC и автоматически обновлять сгенерированный PHP-код. Это особенно важно при первом обращении к маршруту, когда PHP-файл еще не создан.
Роль SQLite в архитектуре Fusion
Для связи между PHP и JavaScript процессами Fusion использует локальную SQLite базу данных. В ней хранятся метаданные о компонентах и связях между Vue SFC и сгенерированными PHP-классами. Структура основной таблицы базы данных выглядит примерно так:
id – уникальный идентификатор,
src – путь к Vue SFC файлу,
php_class – имя сгенерированного PHP-класса,
php_path – путь к сгенерированному PHP-файлу,
shim_path – путь к JavaScript-шиму,
php_hash – хеш PHP-кода для определения изменений.
Хеш PHP-кода используется для оптимизации – если код не изменился, повторная трансформация не выполняется.
При этом база данных никак не влияет на основное приложение Laravel. Для неё создается отдельное соединение:
| PHP | 1
2
3
4
5
6
7
| ConfigFacade::set('database.connections.__fusion', [
'name' => '__fusion',
'driver' => 'sqlite',
'database' => Fusion::storage('fusion.sqlite'),
'foreign_key_constraints' => true,
'journal_mode' => 'OFF',
]) |
|
Это изящное решение позволяет Fusion функционировать не затрагивая основную базу данных проекта.
Файловая маршрутизация в Fusion
Одним из главных преимуществ Fusion является автоматическая файловая маршрутизация, аналогичная той, что используется в Next.js или Nuxt.js. Vue SFC, размещенные в директории resources/js/Pages, автоматически регистрируются как маршруты Laravel. Регистрация происходит при запуске приложения через вызов Fusion::pages() в файле routes/web.php:
| PHP | 1
2
3
4
| <?php
use Fusion\Fusion;
Fusion::pages(); |
|
При этом Fusion анализирует структуру директории, находит все Vue SFC и регистрирует маршруты, используя стандартный Laravel Router:
| PHP | 1
2
3
| Route::any($uri, [FusionController::class, 'handle'])
->defaults('__component', $component)
->defaults('__class', Component::where('src', $src)->first()?->php_class); |
|
Это позволяет использовать привычные соглашения об именовании файлов для определения маршрутов. Например:
resources/js/Pages/Index.vue → /
resources/js/Pages/About.vue → /about
resources/js/Pages/Users/[Id].vue → /users/{id}
Интеграция с Inertia.js
Важно понимать, что Fusion не является полной заменой Inertia.js, а скорее его расширением. Fusion все еще использует Inertia для рендеринга компонентов и передачи данных. Это видно по атрибуту data-page в HTML-ответе:
| JSON | 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
| {
"component": "Index",
"props": {
"errors": {},
"auth": {
"user": null
},
"fusion": {
"meta": [],
"state": {
"name": "AARON"
},
"actions": [
{
"handler": "applyServerState",
"priority": 40,
"_handler": "Fusion\\Http\\Response\\Actions\\ApplyServerState"
}
]
}
},
"url": "/",
"version": "f7e418d032bf1c4cc3cc55d947cab622",
"clearHistory": false,
"encryptHistory": false
} |
|
Fusion добавляет специальный объект fusion в пропсы, который содержит состояние и действия, необходимые для работы компонента. Это позволяет сохранить совместимость с существующими Inertia-приложениями и постепенно переходить на Fusion там, где это нужно.
Обработка запросов к серверу
Когда клиент совершает действие, требующее взаимодействия с сервером (например, нажатие на кнопку, которая вызывает метод, экспортированный через expose()), Fusion генерирует POST-запрос с специальными заголовками:
X-Fusion-Action-Handler – имя обработчика,
X-Fusion-Action-Request – флаг, указывающий, что это запрос действия.
Тело запроса содержит аргументы для метода и текущее состояние:
| JSON | 1
2
3
4
5
6
7
8
9
10
11
| {
"fusion": {
"args": {
"podcast": { /* данные подкаста */ }
},
"state": {
"search": "",
"podcasts": [ /* список подкастов */ ]
}
}
} |
|
Сервер обрабатывает запрос, выполняет соответствующий метод и возвращает результат, который автоматически применяется к состоянию на клиенте. Такой подход позволяет создавать интерактивные приложения, сохраняя при этом простоту разработки и поддержки кода.
Практическое применение
Теперь, когда мы разобрались с теоретическими основами и внутренним устройством Fusion, пришло время рассмотреть практические аспекты использования этой технологии. Познакомимся с настройкой окружения, созданием компонентов и типичными сценариями применения Fusion в реальных проектах.
Настройка окружения для работы с Fusion
Для начала работы с Fusion требуется выполнить несколько шагов по настройке проекта. Процесс установки достаточно прямолинеен, поскольку Fusion интегрируется с существующей инфраструктурой Laravel и Inertia.js.
1. Создаем новый проект Laravel или используем существующий:
| Bash | 1
2
| composer create-project laravel/laravel fusion-app
cd fusion-app |
|
2. Устанавливаем и настраиваем Inertia.js с Vue 3:
| Bash | 1
2
| composer require inertiajs/inertia-laravel
npm install @inertiajs/vue3 |
|
3. Добавляем пакет Fusion:
| Bash | 1
2
| composer require fusion-php/fusion
npm install @fusion-php/vue |
|
4. Регистрируем сервис-провайдер Fusion в конфигурации приложения (config/app.php):
| PHP | 1
2
3
4
| 'providers' => [
// Другие провайдеры
Fusion\Providers\FusionServiceProvider::class,
], |
|
5. Настраиваем Vite для работы с Fusion, добавляя соответствующий плагин в vite.config.js:
| JavaScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import fusion from '@fusion-php/vue/vite';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
vue(),
fusion(),
],
}); |
|
6. Создаем структуру каталогов для Vue-компонентов:
| Bash | 1
| mkdir -p resources/js/Pages |
|
7. Настраиваем файловую маршрутизацию в routes/web.php:
| PHP | 1
2
3
4
| <?php
use Fusion\Fusion;
Fusion::pages(); |
|
После выполнения этих шагов окружение готово к созданию компонентов с использованием Fusion. Важно запустить сервер разработки Vite, который будет обрабатывать Vue SFC с PHP-блоками:
Пошаговое создание первого PHP-Vue компонента
Создадим простой компонент для управления списком задач, демонстрирующий основные возможности Fusion.
1. Сначала создадим модель Task и миграцию для неё:
| Bash | 1
| php artisan make:model Task -m |
|
2. Определим структуру таблицы в миграции:
| PHP | 1
2
3
4
5
6
| Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->boolean('completed')->default(false);
$table->timestamps();
}); |
|
3. Настроим модель Task:
| PHP | 1
2
3
4
5
6
7
| class Task extends Model
{
protected $fillable = ['title', 'completed'];
protected $casts = [
'completed' => 'boolean',
];
} |
|
4. Теперь создадим компонент resources/js/Pages/Tasks.vue:
| TypeScript | 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
| <php>
use function \Fusion\{prop, expose};
use \App\Models\Task;
// Получаем список задач из базы данных
$tasks = prop(fn () => Task::all());
// Метод для создания новой задачи
expose(createTask: function (string $title) {
$task = Task::create([
'title' => $title,
'completed' => false,
]);
return $task;
});
// Метод для изменения статуса задачи
expose(toggleTask: function (Task $task) {
$task->completed = !$task->completed;
$task->save();
return $task;
});
// Метод для удаления задачи
expose(deleteTask: function (Task $task) {
$task->delete();
return true;
});
</php>
<script setup>
import { ref } from 'vue';
const newTaskTitle = ref('');
function handleCreateTask() {
if (!newTaskTitle.value.trim()) return;
createTask({ title: newTaskTitle.value })
.then(task => {
tasks.push(task);
newTaskTitle.value = '';
});
}
</script>
<template>
<div class="tasks-container">
<h1>Список задач</h1>
<div class="task-form">
<input
v-model="newTaskTitle"
placeholder="Что нужно сделать?"
@keyup.enter="handleCreateTask"
/>
<button @click="handleCreateTask">Добавить</button>
</div>
<ul class="task-list">
<li v-for="task in tasks" :key="task.id" class="task-item">
<input
type="checkbox"
:checked="task.completed"
@change="toggleTask({ task }).then(updated => Object.assign(task, updated))"
/>
<span :class="{ 'completed': task.completed }">
{{ task.title }}
</span>
<button @click="deleteTask({ task }).then(() => {
const index = tasks.findIndex(t => t.id === task.id);
if (index !== -1) tasks.splice(index, 1);
})">
Удалить
</button>
</li>
</ul>
</div>
</template>
<style scoped>
.tasks-container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.task-form {
display: flex;
margin-bottom: 20px;
}
.task-form input {
flex-grow: 1;
padding: 8px;
margin-right: 10px;
}
.task-list {
list-style: none;
padding: 0;
}
.task-item {
display: flex;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.task-item input {
margin-right: 10px;
}
.completed {
text-decoration: line-through;
color: #888;
}
.task-item button {
margin-left: auto;
background: #ff4757;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
</style> |
|
В этом примере демонстрируются основные концепции Fusion:- Использование
prop() для получения данных из базы данных,
- Функция
expose() для экспорта методов, которые могут вызываться с клиента,
- Автоматическая типизация аргументов в PHP (параметр
Task $task),
- Двусторонняя связь между Vue-компонентом и серверным кодом.
При обращении к маршруту /tasks будет отображён этот компонент, позволяющий управлять списком задач без необходимости создания отдельного API.
Интеграция Fusion с существующими PHP-фреймворками
Хотя Fusion создавался для Laravel, принципы работы с ним можно адаптировать и для других PHP-фреймворков. Основная задача — обеспечить трансформацию PHP-кода из Vue SFC в исполняемый код на сервере. В случае с Laravel Fusion использует:- Сервис-провайдеры для регистрации и инициализации.
- Eloquent ORM для работы с данными.
- Маршрутизацию Laravel для обработки запросов.
При работе с другими фреймворками нужно реализовать аналогичные механизмы. Например, для Symfony потребуется:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // src/Bundle/FusionBundle.php
namespace App\Bundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use App\DependencyInjection\FusionExtension;
class FusionBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->registerExtension(new FusionExtension());
}
} |
|
С точки зрения фронтенда, интеграция будет аналогичной, поскольку Vite и Vue работают независимо от серверного фреймворка.
Работа с асинхронными запросами в PHP-Vue компонентах
Одно из главных преимуществ Fusion — прозрачная работа с асинхронными запросами. Рассмотрим пример компонента поиска, который выполняет запросы к базе данных в реальном времени:
| TypeScript | 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
| <php>
use function \Fusion\{prop, sync};
use \App\Models\Product;
// Инициализация состояния
$search = prop('');
$products = prop([]);
// Синхронизируем поиск с результатами
sync(function () use (&$search, &$products) {
if (strlen($search) >= 2) {
$products = Product::where('name', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%")
->limit(20)
->get();
} else {
$products = [];
}
});
</php>
<template>
<div class="search-container">
<input
v-model="search"
placeholder="Поиск продуктов..."
class="search-input"
/>
<div v-if="search.length >= 2 && products.length === 0" class="no-results">
По запросу "{{ search }}" ничего не найдено
</div>
<div v-if="products.length > 0" class="results">
<div v-for="product in products" :key="product.id" class="product-item">
<h3>{{ product.name }}</h3>
<p>{{ product.description }}</p>
<span class="price">{{ product.price }} ₽</span>
</div>
</div>
</div>
</template> |
|
Функция sync() обеспечивает автоматическую синхронизацию между клиентом и сервером. Когда пользователь вводит текст в поле поиска, значение search изменяется, что автоматически инициирует запрос к серверу. Сервер выполняет функцию в sync(), обновляет переменную $products и возвращает новые данные клиенту. Всё это происходит без необходимости вручную писать код для отправки запросов, обработки ответов и обновления состояния компонента.
Оптимизация структуры проекта при использовании Fusion
При работе с Fusion рекомендуется следовать определенным принципам организации проекта:
1. Структура директорий
Fusion базируется на файловой маршрутизации, поэтому структура каталогов имеет важное значение:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
| resources/
└── js/
├── Pages/ # Компоненты, соответствующие маршрутам
│ ├── Index.vue # Соответствует '/'
│ ├── About.vue # Соответствует '/about'
│ └── Users/
│ ├── Index.vue # Соответствует '/users'
│ └── [Id].vue # Соответствует '/users/{id}'
├── Components/ # Переиспользуемые компоненты
│ ├── Navbar.vue
│ └── Button.vue
└── Layouts/ # Шаблоны страниц
└── Default.vue |
|
2. Разделение ответственности
Несмотря на возможность писать PHP и Vue в одном файле, рекомендуется:- Выносить сложную бизнес-логику в отдельные сервисы.
- Использовать репозитории для сложных запросов к данным.
- Создавать чистые Vue-компоненты для переиспользуемых UI-элементов.
3. Кеширование и производительность
Для улучшения производительности:- Ограничивайте объём данных, передаваемых через
prop().
- Используйте метод
readonly() для неизменяемых данных: $config = prop($appConfig)->readonly().
- Применяйте пагинацию для больших наборов данных:
$users = prop(fn () => User::paginate(15)).
4. Типизация
Используйте типизацию для обеспечения надежности:- В PHP применяйте строгую типизацию параметров и возвращаемых значений.
- В Vue рассмотрите возможность использования TypeScript.
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| <php>
expose(getUserById: function (int $id): ?\App\Models\User {
return User::find($id);
});
</php>
<script setup lang="ts">
interface User {
id: number;
name: string;
email: string;
}
const selectedUser = ref<User | null>(null);
</script> |
|
Паттерны обмена данными между серверной и клиентской частями
Fusion предоставляет несколько паттернов для организации взаимодействия между сервером и клиентом:
1. Пропсы (prop)
Основной механизм передачи данных с сервера на клиент:
| PHP | 1
2
3
4
5
6
7
8
| // Статический проп
$title = prop('Заголовок страницы');
// Динамический проп
$users = prop(fn () => User::all());
// Только для чтения
$settings = prop($appSettings)->readonly(); |
|
2. Экспорт методов (expose)
Позволяет вызывать серверные методы с клиента:
| PHP | 1
2
3
4
| expose(saveUser: function (User $user, array $data) {
$user->fill($data)->save();
return $user;
}); |
|
На клиенте:
| HTML5 | 1
2
3
| <button @click="saveUser({ user, data }).then(updatedUser => ...)">
Сохранить
</button> |
|
3. Синхронизация (sync)
Обеспечивает двунаправленную синхронизацию:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| $filter = prop('all');
$tasks = prop([]);
sync(function () use (&$filter, &$tasks) {
$query = Task::query();
if ($filter === 'completed') {
$query->where('completed', true);
} elseif ($filter === 'active') {
$query->where('completed', false);
}
$tasks = $query->get();
}); |
|
На клиенте:
| HTML5 | 1
2
3
4
5
| <select v-model="filter">
<option value="all">Все задачи</option>
<option value="active">Активные</option>
<option value="completed">Завершённые</option>
</select> |
|
Каждый из этих паттернов имеет свои преимущества и ограничения, выбор зависит от конкретного сценария использования.
Типичные сценарии использования
Fusion особенно эффективен в следующих сценариях:
1. Админ-панели и дашборды
Возможность напрямую использовать модели Eloquent в компонентах и автоматизировать работу с данными делает Fusion идеальным инструментом для создания админ-панелей.
2. Интерактивные формы с валидацией
Fusion позволяет использовать валидацию Laravel прямо в компонентах:
| TypeScript | 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
| <php>
use function \Fusion\{prop, expose};
use Illuminate\Support\Facades\Validator;
$form = prop([
'name' => '',
'email' => '',
'password' => '',
]);
$errors = prop([]);
expose(register: function (array $formData) {
$validator = Validator::make($formData, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8',
]);
if ($validator->fails()) {
return ['success' => false, 'errors' => $validator->errors()->toArray()];
}
// Создание пользователя...
return ['success' => true];
});
</php> |
|
3. Приложения с быстрым поиском и фильтрацией
Как мы видели в примере с асинхронными запросами, Fusion отлично подходит для реализации поиска в режиме реального времени.
4. Многошаговые процессы
Fusion упрощает реализацию сложных многошаговых процессов, сохраняя состояние между шагами:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <php>
use function \Fusion\{prop, expose};
$step = prop(1);
$formData = prop([
'personal' => ['name' => '', 'email' => ''],
'address' => ['city' => '', 'street' => ''],
'payment' => ['method' => '', 'details' => ''],
]);
expose(submitStep: function (int $currentStep, array $stepData) {
// Валидация текущего шага...
if ($currentStep < 3) {
return ['success' => true, 'nextStep' => $currentStep + 1];
} else {
// Финальная обработка данных...
return ['success' => true, 'completed' => true];
}
});
</php> |
|
В каждом из этих сценариев Fusion помогает значительно сократить количество кода и упростить разработку, объединяя клиентскую и серверную логику в рамках единого компонента.
Работа с аутентификацией и авторизацией в Fusion
При создании веб-приложений аутентификация и авторизация – критически важные аспекты. Fusion позволяет использовать стандартные механизмы Laravel для управления доступом прямо в компонентах:
| TypeScript | 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
| <php>
use function \Fusion\{prop, expose};
use Illuminate\Support\Facades\Auth;
// Проверяем авторизацию пользователя
$user = prop(fn () => Auth::user());
$isAdmin = prop(fn () => Auth::check() && Auth::user()->hasRole('admin'));
// Метод для входа пользователя
expose(login: function (string $email, string $password, bool $remember = false) {
$credentials = ['email' => $email, 'password' => $password];
if (Auth::attempt($credentials, $remember)) {
request()->session()->regenerate();
return ['success' => true, 'user' => Auth::user()];
}
return ['success' => false, 'message' => 'Неверные учетные данные'];
});
// Метод для выхода
expose(logout: function () {
Auth::logout();
request()->session()->invalidate();
request()->session()->regenerateToken();
return ['success' => true];
});
</php>
<template>
<div v-if="!user">
<!-- Форма входа -->
</div>
<div v-else>
<p>Привет, {{ user.name }}!</p>
<button @click="logout().then(() => window.location.reload())">Выйти</button>
<div v-if="isAdmin" class="admin-panel">
<!-- Админ-панель -->
</div>
</div>
</template> |
|
Аналогично можно реализовать политики доступа, используя возможности Gate и Policy в Laravel:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <php>
use function \Fusion\{prop};
use Illuminate\Support\Facades\Gate;
use \App\Models\Post;
$post = prop(fn () => Post::find(request()->route('id')));
$canEdit = prop(fn () => Gate::allows('update', $post));
</php>
<template>
<div v-if="post">
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<div v-if="canEdit" class="edit-controls">
<button>Редактировать</button>
</div>
</div>
</template> |
|
Интеграция с внешними API
Fusion позволяет легко интегрироваться с внешними API, инкапсулируя логику взаимодействия с ними в серверной части:
| TypeScript | 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
| <php>
use function \Fusion\{prop, expose};
use Illuminate\Support\Facades\Http;
// Инициализация состояния
$query = prop('');
$results = prop([]);
$isLoading = prop(false);
// Метод для поиска через внешний API
expose(search: function (string $searchQuery) {
$isLoading = true;
try {
$response = Http::get('https://api.example.com/search', [
'q' => $searchQuery,
'limit' => 10
]);
if ($response->successful()) {
$results = $response->json('results', []);
return ['success' => true, 'results' => $results];
}
return ['success' => false, 'error' => 'API вернул ошибку'];
} catch (\Exception $e) {
return ['success' => false, 'error' => $e->getMessage()];
} finally {
$isLoading = false;
}
});
</php>
<template>
<div class="search-container">
<input v-model="query" placeholder="Поиск..." />
<button @click="search({ searchQuery: query })
.then(response => {
if (response.success) {
results = response.results;
} else {
alert(response.error);
}
isLoading = false;
})">Искать</button>
<div v-if="isLoading" class="loading">Загрузка...</div>
<div v-else-if="results.length > 0" class="results">
<!-- Результаты поиска -->
</div>
</div>
</template> |
|
Обработка ошибок и дебаггинг в Fusion
При разработке с использованием Fusion важно понимать, как обрабатывать ошибки и отлаживать приложение. Существует несколько подходов:
1. Серверные ошибки
PHP-ошибки в блоке <php> отображаются в оверлее Vite, что упрощает их обнаружение:
| TypeScript | 1
2
3
4
| <php>
// Ошибка будет показана в оверлее Vite
$undefined_variable;
</php> |
|
2. Ошибки JavaScript
Для клиентской части используются стандартные инструменты отладки Vue:
Vue DevTools для инспекции компонентов и состояния
Консоль браузера для отлова ошибок JavaScript
3. Логирование
Fusion предлагает действие log для отладки, которое позволяет выводить информацию в консоль:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <php>
use function \Fusion\{prop};
$data = prop(['value' => 'test']);
</php>
<script setup>
import { useFusion } from '$fusion/Pages/Debug.js'
import { log } from '@fusion/vue/actions'
const { data, fusion } = useFusion(['data', 'fusion'])
// Добавляем действие log
fusion.addAction(log, { priority: 10 })
// Теперь все изменения будут логироваться
</script> |
|
4. Трассировка запросов
Для отслеживания всех запросов можно использовать действие logStack:
| TypeScript | 1
2
3
4
5
6
7
| <script setup>
import { useFusion } from '$fusion/Pages/Debug.js'
import { logStack } from '@fusion/vue/actions'
const { fusion } = useFusion(['fusion'])
fusion.addAction(logStack, { priority: 20 })
</script> |
|
Развертывание приложений на Fusion
Процесс развертывания Fusion-приложения во многом схож с развертыванием стандартного Laravel-приложения с Inertia.js, но есть некоторые особенности:
1. Генерация PHP-файлов
При разработке PHP-файлы генерируются автоматически плагином Vite. В production это нужно выполнить вручную:
| Bash | 1
| php artisan fusion:build |
|
Эта команда анализирует все Vue SFC с PHP-блоками и генерирует соответствующие PHP-классы.
2. Настройка хостинга
Убедитесь, что директория storage/fusion доступна для записи веб-сервером, так как там хранятся сгенерированные файлы и SQLite база данных.
3. Оптимизация для production
Для улучшения производительности в production рекомендуется:- Кешировать маршруты:
php artisan route:cache.
- Оптимизировать автозагрузчик:
composer install --optimize-autoloader --no-dev.
- Собрать фронтенд для production:
npm run build.
4. Миграция базы данных
Не забудьте выполнить миграции базы данных:
| Bash | 1
| php artisan migrate --force |
|
5. Конфигурация веб-сервера
Настройте веб-сервер так, чтобы все запросы, кроме запросов к существующим файлам, перенаправлялись на public/index.php, как в стандартном Laravel-приложении.
С этими настройками ваше Fusion-приложение будет готово к использованию в production-среде, обеспечивая плавное взаимодействие между PHP и Vue компонентами.
Преимущества и ограничения
Отделяя плюсы от минусов любой новой технологии, важно сохранять объективность. Fusion, как и любой инструмент, имеет свои сильные стороны и ограничения, которые нужно учитывать при выборе технологического стека. Давайте рассмотрим, в каких случаях Fusion блистает, а где может создать дополнительные сложности.
Производительность и оптимизация
В плане производительности Fusion находится примерно на том же уровне, что и стандартные Inertia-приложения. Поскольку Fusion фактически надстраивается над Inertia, базовая модель рендеринга остаётся прежней – серверный код генерирует данные, которые передаются на клиент для отрисовки с помощью Vue. Однако есть несколько нюансов:
1. Начальная загрузка – первый визит на страницу с Fusion может занимать чуть больше времени из-за дополнительной обработки PHP-блоков и генерации соответствующих классов. Этот эффект особенно заметен в режиме разработки, когда трансформация происходит на лету.
2. Кеширование трансформаций – Fusion использует хеширование PHP-кода для определения изменений, что позволяет избежать повторной трансформации неизменившихся компонентов. В production все трансформации выполняются заранее, что минимизирует задержки.
3. Размер бандла – JavaScript-шимы, генерируемые Fusion, добавляют некоторый объём к итоговому бандлу. Хотя это увеличение обычно несущественно, при большом количестве компонентов с PHP-блоками оно может стать заметным.
4. Сетевые запросы – Fusion оптимизирует взаимодействие клиента с сервером, особенно при использовании функции sync(). Вместо традиционного API с множеством эндпоинтов, Fusion использует унифицированный подход к обмену данными, что может сократить количество запросов.
При правильной реализации, Fusion-приложения могут демонстрировать отличную производительность. Особенно заметны преимущества при работе с формами и интерактивными элементами, где Fusion избавляет от необходимости создавать отдельные API-эндпоинты и дублировать логику валидации.
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // Оптимизация запросов с использованием Fusion
$search = prop('');
$results = prop([]);
sync(function () use (&$search, &$results) {
// Запрос выполняется только когда меняется значение $search
if (strlen($search) >= 3) {
$results = DB::table('products')
->where('name', 'like', "%{$search}%")
->limit(10)
->get();
} else {
$results = collect();
}
}); |
|
В этом примере запрос к базе данных выполняется только при изменении поисковой строки, а не при каждом рендеринге компонента, что экономит ресурсы сервера.
Типизация и возможные проблемы
Одним из технических вызовов при работе с Fusion является обеспечение согласованной типизации между PHP и JavaScript частями приложения. В отличие от чистого TypeScript или PHP, где системы типов самодостаточны, Fusion требует координации между двумя разными мирами. Основные проблемы с типизацией:
1. Несоответствие типов – PHP и JavaScript имеют разные системы типов. Например, PHP различает целые числа и числа с плавающей точкой, тогда как в JavaScript есть только тип Number.
2. Сериализация объектов – При передаче сложных объектов из PHP в JavaScript может происходить потеря методов и прототипов. Объекты Eloquent превращаются в простые JSON-структуры.
3. Отсутствие статического анализа – Стандартные инструменты типизации не могут проверять связи между PHP и JavaScript кодом внутри компонентов Fusion.
Для смягчения этих проблем можно:- Использовать PHP-докблоки и JSDoc для документирования типов.
- Явно указывать типы в PHP-функциях, экспортированных через
expose().
- Применять TypeScript в Vue-компонентах для строгой типизации клиентской части.
- Создавать интерфейсы TypeScript, соответствующие структурам данных в PHP.
| TypeScript | 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
| <php>
/**
* @return \App\Models\User[]
*/
$users = prop(fn () => User::all()->makeVisible(['api_token']));
/**
* @param int $id ID пользователя
* @return \App\Models\User|null
*/
expose(getUser: function (int $id) {
return User::find($id);
});
</php>
<script setup lang="ts">
interface User {
id: number;
name: string;
email: string;
api_token: string;
}
// TypeScript понимает, что users — это массив объектов User
const selectedUser = ref<User | null>(null);
// Функция для выбора пользователя
function selectUser(id: number) {
getUser({ id }).then(user => {
selectedUser.value = user as User;
});
}
</script> |
|
Такой подход позволяет получить некоторые преимущества строгой типизации, хотя и не может полностью устранить разрыв между двумя языками.
Тестирование Fusion-компонентов: стратегии и инструменты
Тестирование приложений, использующих Fusion, представляет определённые сложности из-за гибридной природы компонентов. Традиционные подходы к тестированию не всегда работают, поскольку они ориентированы либо на PHP, либо на JavaScript, но не на их комбинацию. Эффективная стратегия тестирования Fusion-приложений включает несколько уровней:
1. Модульное тестирование PHP-кода
Серверную часть компонентов можно тестировать, используя стандартные инструменты Laravel, такие как PHPUnit. Для этого нужно изолировать бизнес-логику от кода, специфичного для Fusion:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
12
13
| // Вместо непосредственного размещения логики в блоке <php>
// мы создаём отдельный сервис
class ProductService
{
public function searchProducts(string $query)
{
return Product::where('name', 'like', "%{$query}%")->get();
}
}
// В блоке <php>
$productService = new ProductService();
$results = prop(fn () => $productService->searchProducts($search)); |
|
Теперь ProductService можно тестировать независимо от Fusion:
| PHP | 1
2
3
4
5
6
7
8
9
10
11
| public function test_search_products()
{
// Создаём тестовые продукты
Product::factory()->create(['name' => 'Test Product']);
$service = new ProductService();
$results = $service->searchProducts('Test');
$this->assertCount(1, $results);
$this->assertEquals('Test Product', $results[0]->name);
} |
|
2. Модульное тестирование Vue-компонентов
Клиентскую часть можно тестировать с помощью Vue Test Utils или Testing Library, имитируя данные и функции, которые обычно предоставляются Fusion:
| JavaScript | 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
| import { mount } from '@vue/test-utils'
import ProductSearch from './ProductSearch.vue'
test('отображает результаты поиска', async () => {
// Мокаем функцию searchProducts, которая обычно предоставляется Fusion
const searchProducts = vi.fn().mockResolvedValue([
{ id: 1, name: 'Test Product' }
]);
const wrapper = mount(ProductSearch, {
global: {
provide: {
// Имитируем данные, которые бы предоставил Fusion
fusion: {
state: { search: '', results: [] },
actions: { searchProducts }
}
}
}
});
// Вводим поисковый запрос
await wrapper.find('input').setValue('Test');
await wrapper.find('button').trigger('click');
// Проверяем, что функция была вызвана
expect(searchProducts).toHaveBeenCalledWith({ query: 'Test' });
// Дожидаемся обновления компонента
await wrapper.vm.$nextTick();
// Проверяем отображение результатов
expect(wrapper.text()).toContain('Test Product');
}); |
|
3. Интеграционное тестирование
Интеграционные тесты проверяют взаимодействие между PHP и JavaScript частями. Для этого можно использовать Laravel Dusk или Cypress, которые позволяют тестировать приложение в реальном браузере:
| PHP | 1
2
3
4
5
6
7
8
9
10
| public function test_search_functionality()
{
$this->browse(function (Browser $browser) {
$browser->visit('/products')
->type('search', 'Test')
->press('Search')
->waitForText('Test Product')
->assertSee('Test Product');
});
} |
|
4. Снимки (snapshots)
Для компонентов с стабильным UI полезно использовать тесты на основе снимков, которые отлавливают неожиданные изменения в рендеринге:
| JavaScript | 1
2
3
4
5
6
7
8
9
| test('рендерит корректно', () => {
const wrapper = mount(ProductItem, {
props: {
product: { id: 1, name: 'Test Product', price: 100 }
}
});
expect(wrapper.html()).toMatchSnapshot();
}); |
|
Кейс-стади: миграция существующего проекта на Fusion
Переход на новую технологию всегда сопряжён с определёнными рисками и затратами. Рассмотрим практический пример миграции существующего Laravel+Inertia проекта на Fusion, чтобы лучше понять реальные преимущества и сложности.
Компания "ФудТек" разрабатывала систему управления рестораном на основе Laravel и Inertia.js с Vue 3. Система включала модули для управления заказами, инвентаризации, бронирования столиков и аналитики. После выхода Fusion разработчики решили постепенно мигрировать наиболее проблемные части приложения.
Этап 1: Подготовка инфраструктуры
Первым шагом была интеграция Fusion в существующий проект без изменения функциональности:
| Bash | 1
2
| composer require fusion-php/fusion
npm install @fusion-php/vue |
|
Настройка Vite и регистрация сервис-провайдера позволили использовать Fusion параллельно с существующим кодом.
Этап 2: Пилотная миграция
Для начала выбрали модуль бронирования столиков — компонент с интенсивным взаимодействием между клиентом и сервером, требующий множества проверок и валидаций. До миграции архитектура включала:- Контроллер (300+ строк).
- API-ресурсы (150+ строк).
- Запросы валидации (100+ строк).
- Vue-компоненты (500+ строк).
После миграции на Fusion вся эта функциональность уместилась в двух компонентах общим объёмом около 400 строк. Особенно заметно сократился код, связанный с валидацией и обменом данными.
Этап 3: Измерение результатов
Основные результаты:- Сокращение кодовой базы на 42% для мигрированных модулей.
- Уменьшение времени на разработку новых функций на 30%.
- Сокращение количества ошибок при валидации на 75%.
- Производительность осталась на прежнем уровне.
Этап 4: Постепенная миграция
На основе успешного пилота компания решила постепенно мигрировать остальные модули, начиная с тех, где преимущества были бы наиболее заметны:
1. Формы создания и редактирования заказов.
2. Функциональность поиска и фильтрации.
3. Панель аналитики с интерактивными фильтрами.
Для внедрения разработали паттерн "Адаптер", который позволял постепенно переводить функциональность без нарушения работы системы.
Безопасность при использовании Fusion
При использовании Fusion возникает ряд специфических вопросов безопасности:
1. Прямой доступ к моделям Eloquent
Fusion позволяет напрямую работать с моделями в PHP-блоке, что потенциально может привести к уязвимостям:
| TypeScript | 1
2
3
4
5
| <php>
expose(deleteUser: function (User $user) {
$user->delete(); // Возможно нарушение авторизации!
});
</php> |
|
Решение: Всегда проверяйте права доступа перед выполнением операций:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
| <php>
expose(deleteUser: function (User $user) {
if (Gate::denies('delete', $user)) {
abort(403);
}
$user->delete();
return true;
});
</php> |
|
2. Утечка конфиденциальных данных
При неправильном использовании prop() может произойти утечка конфиденциальных данных:
| TypeScript | 1
2
3
4
| <php>
// Опасно! Передаём всю модель User
$user = prop(fn () => Auth::user());
</php> |
|
Решение: Используйте явное указание атрибутов или ресурсы API:
| TypeScript | 1
2
3
4
5
6
7
| <php>
// Безопасно - передаём только необходимые атрибуты
$user = prop(fn () => Auth::user()->only(['id', 'name', 'email']));
// Или используем API-ресурс
$user = prop(fn () => new UserResource(Auth::user()));
</php> |
|
3. Валидация входных данных
Не забывайте валидировать все входные данные, даже если они приходят через безопасный интерфейс Fusion:
| TypeScript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <php>
expose(updateSettings: function (array $settings) {
// Обязательно валидируйте входные данные!
$validator = Validator::make($settings, [
'email' => 'email|nullable',
'notification_type' => 'in:email,sms,none',
// прочие правила
]);
if ($validator->fails()) {
return ['success' => false, 'errors' => $validator->errors()];
}
// дальнейшая обработка
});
</php> |
|
Альтернативные решения
Fusion — не единственное решение для интеграции PHP и JavaScript. Альтернативами являются:
Заключение
Рассмотрев возможности и технические аспекты Fusion, можно сделать вывод, что эта технология представляет собой значительный шаг вперёд в интеграции PHP и JavaScript. Сравнивая Fusion с другими подходами к объединению фронтенда и бэкенда, отчётливо видны его преимущества в упрощении разработки и сокращении количества кода. Если говорить о производительности, Fusion демонстрирует результаты на уровне стандартных Inertia-приложений с незначительными отличиями. Первоначальная загрузка может занимать несколько больше времени из-за дополнительных преобразований, но последующие взаимодействия выигрывают от оптимизированного обмена данными. Исследования реальных внедрений показывают сокращение кодовой базы до 40% и ускорение разработки новой функциональности примерно на треть.
В сравнении с Livewire, который полностью основан на серверном рендеринге, Fusion сохраняет все преимущества клиентского рендеринга Vue, что делает его более гибким для создания сложных интерфейсов. По сравнению с чистым Inertia.js, Fusion устраняет необходимость создания отдельных контроллеров и API-эндпоинтов, упрощая архитектуру приложения.
Перспективы развития Fusion выглядят многообещающе. Судя по планам разработчиков, в будущих версиях можно ожидать:- Поддержку React наряду с Vue.
- Расширение возможностей файловой маршрутизации.
- Улучшение типизации между PHP и JavaScript.
- Оптимизацию производительности для крупных приложений.
- Интеграцию с другими PHP-фреймворками помимо Laravel.
Для разработчиков, рассматривающих внедрение Fusion, рекомендуется следующий подход:
1. Начинать с небольших, изолированных компонентов, чтобы освоить концепции и особенности технологии.
2. Сконцентрироваться на частях приложения с интенсивным взаимодействием между клиентом и сервером.
3. Выносить сложную бизнес-логику в отдельные сервисы для упрощения тестирования.
4. Уделять особое внимание вопросам безопасности, особенно при работе с моделями данных.
5. Применять инкрементальный подход при миграции существующих проектов.
Fusion вероятно найдёт свою нишу среди команд, разрабатывающих сложные веб-приложения на Laravel с современным интерактивным интерфейсом. При правильном применении эта технология способна существенно повысить продуктивность разработки, уменьшить когнитивную нагрузку на программистов и создать более целостный процесс разработки, объединяющий серверную и клиентскую части приложения.
VUE CLI (CLI-VUE-BABEL) не собирается в работающий проект После сборки проекта, сам проект не работает (RAGE MP сервер не открывает браузер). Проблемы в... PHP-Fusion 7 Отличная CMS система, но как добавить нового администратора?
Зарегистрировался человек, но в... Есть flash меню, как его подключить к PHP-Fusion нужен скрипт подключения....
помогите пожалуйста, чет у меня не получается нифига... Работа с движком Php Fusion 7 Здравствуйте. Интересует небольшой вопрос касательно движка php fusion 7. Сразу описывать всю... Vue-router не отображает компонент по ссылке Здравствуйте, столкнулся с определенной проблемой. Для перехода использую vue-router. Страницы... Компонент Vue.js, который выводит две кнопки разного цвета с разными текстами, например, “Да”, “Нет” Подскажите как правильно сделайте компонент Vue.js, который выводит две кнопки разного цвета с... Vue cli, как маштабировать компонент с разными размерами для каждой страницы Здраствуйте, у меня есть компонент vue 2 cli, он используется на разных страницах, как я могу... Не выводится тестовый компонент Vue Я пытаюсь начать использовать Vue в проекте Laravel, но что-то идёт не так.
app.blade.php
... Как подключить во VUE компонент СВОЙ ! UI? Привет.
Хочу в компоненте VUE работать с привычными js файлами, где могу писать... Vue компонент срабатывает сам по себе? Доброго всем времени суток! Заметил что если использовать Option API и в теге script компонента,... Vue-router загружает компонент другого роута при использовании Memory mode Здравствуйте. Создал сборку vite + vue3 + vuetify3 + nodejs, для реализации SSR. При настройке... SFC: гарантированный выход за границу родительского компонента Есть некий vue-компонент, который может применяться в любом непредсказуемом окружении (т.е. внутри...
|