manyou / inertia-bundle
Symfony 对 Inertia.js 的适配器
Requires
- php: ^7.3|^8
- ext-json: *
- symfony/config: ^4.4|^5.1.7|^6.0|^7.0
- symfony/dependency-injection: ^4.4|^5.1.7|^6.0|^7.0
- symfony/http-client: ^4.4|^5.1.7|^6.1|^7.0
- symfony/http-kernel: ^4.4|^5.1.7|^6.0|^7.0
- twig/twig: ^2.12|^3.0
Requires (Dev)
- mockery/mockery: ^1.2
- symfony/phpunit-bridge: ^4.4|^5.1.7|^6.0|^7.0
- symfony/property-access: ^5.1|^6.0|^7.0
- symfony/serializer: ^5.1|^6.0|^7.0
- symfony/var-dumper: ^4.4|^5.1.7|^6.0|^7.0
README
这是一个基于 inertia-laravel 的 Inertia.js 服务器端适配器,但适用于 Symfony 5 和 6。
警告
寻找新的所有者
由于我不再使用 Symfony 或 PHP,我在寻找想接管这个项目开发的人。目前该项目未维护。
安装
首先,确保您已经安装了 twig、encore 和 serializer 食谱
composer require twig encore symfony/serializer-pack
使用 Composer 安装
composer require rompetomp/inertia-bundle
yarn add @inertiajs/inertia
设置根模板
使用 Inertia 的第一步是创建一个根模板。我们建议使用 app.html.twig
。此模板应包括您的资产,以及 inertia(page)
函数
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> {% block stylesheets %} {{ encore_entry_link_tags('app') }} {% endblock %} {{ inertiaHead(page) }} </head> <body> {{ inertia(page) }} {% block javascripts %} {{ encore_entry_script_tags('app') }} {% endblock %} </body> </html>
inertia(page)
函数是一个创建基础 div
的辅助函数。它包括一个包含初始页面信息的 data-page
属性。它看起来像这样
<div id="app" data-page="<?php echo htmlspecialchars(json_encode($page)); ?>"></div>
如果您想使用不同的根视图,可以通过创建一个 config/packages/rompetomp_inertia.yaml
文件并包括此配置来更改它
rompetomp_inertia: root_view: 'name.html.twig'
设置前端适配器
在此处找到您想要使用的任何前端适配器 https://github.com/inertiajs。README 中使用了 Laravel 的 Webpack Mix。将其转换为 Webpack Encore 不会很困难,只需遵循此处的文档:https://symfony.com.cn/doc/current/frontend.html。
Webpack Encore 示例
对于 Vue
yarn add @inertiajs/inertia-vue
const Encore = require('@symfony/webpack-encore') const path = require('path') if (!Encore.isRuntimeEnvironmentConfigured()) { Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev') } Encore .setOutputPath('public/build/') .setPublicPath('/build') .enableVueLoader() .addAliases({ vue$: 'vue/dist/vue.runtime.esm.js', '@': path.resolve('assets/js') }) .addEntry('app', './assets/js/app.js') .splitEntryChunks() .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .disableSingleRuntimeChunk() .configureBabel(() => {}, { useBuiltIns: 'usage', corejs: 3 }) .enableSassLoader() module.exports = Encore.getWebpackConfig()
//assets/app.js import { createInertiaApp } from '@inertiajs/inertia-vue' import Vue from "vue"; createInertiaApp({ resolve: name => require(`./Pages/${name}`), setup({ el, app, props }) { new Vue({ render: h => h(app, props), }).$mount(el) }, })
对于 React
const Encore = require('@symfony/webpack-encore') const path = require('path') if (!Encore.isRuntimeEnvironmentConfigured()) { Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev') } Encore .setOutputPath('public/build/') .setPublicPath('/build') .enableReactPreset() .addAliases({ '@': path.resolve('assets/js') }) .addEntry('app', './assets/js/app.js') .splitEntryChunks() .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .disableSingleRuntimeChunk() .configureBabel(() => {}, { useBuiltIns: 'usage', corejs: 3 }) .enableSassLoader() module.exports = Encore.getWebpackConfig()
对于 Svelte
const Encore = require('@symfony/webpack-encore') const path = require('path') if (!Encore.isRuntimeEnvironmentConfigured()) { Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev') } Encore .setOutputPath('public/build/') .setPublicPath('/build') .addLoader({ test: /\.(svelte)$/, use: { loader: 'svelte-loader', options: { emitCss: true, hotReload: true, }, }, }) .addAliases({ '@': path.resolve('assets/js') }) .addEntry('app', './assets/js/app.js') .splitEntryChunks() .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .disableSingleRuntimeChunk() .configureBabel(() => {}, { useBuiltIns: 'usage', corejs: 3 }) .enableSassLoader() const config = Encore.getWebpackConfig() config.resolve.mainFields = ['svelte', 'browser', 'module', 'main'] config.resolve.extensions = ['.wasm', '.mjs', '.js', '.json', '.jsx', '.vue', '.ts', '.tsx', '.svelte'] module.exports = config
制作 Inertia 响应
要制作 Inertia 响应,在控制器中注入 Rompetomp\InertiaBundle\Service\InertiaInterface $inertia
类型提示,并使用该服务上的 render 函数
<?php namespace App\Controller; use Rompetomp\InertiaBundle\Service\InertiaInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class DashboardController extends AbstractController { public function index(InertiaInterface $inertia) { return $inertia->render('Dashboard', ['prop' => 'propValue']); } }
共享数据
要与其他所有组件共享数据,请使用 $inertia->share($key, $data)
。这可以在 EventSubscriber 中完成
<?php namespace App\EventSubscriber; use Rompetomp\InertiaBundle\Service\InertiaInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\KernelEvents; class InertiaSubscriber implements EventSubscriberInterface { /** @var \Rompetomp\InertiaBundle\Service\InertiaInterface */ protected $inertia; /** * AppSubscriber constructor. * * @param \Rompetomp\InertiaBundle\Service\InertiaInterface $inertia */ public function __construct(InertiaInterface $inertia) { $this->inertia = $inertia; } public static function getSubscribedEvents() { return [ KernelEvents::CONTROLLER => 'onControllerEvent', ]; } public function onControllerEvent($event) { $this->inertia->share( 'Auth::user', [ 'name' => 'Hannes', // Synchronously 'posts' => function () { return [1 => 'Post']; } ] ); } }
视图数据
如果您想将数据传递给根模板,可以通过将第三个参数传递给 render 函数来实现
return $inertia->render('Dashboard', ['prop' => 'propValue'], ['title' => 'Page Title']);
您也可以使用 viewData
函数传递这些数据,就像传递给 share
函数的数据一样
$this->inertia->viewData('title', 'Page Title');
您可以在布局文件中的 viewData
变量下访问这些数据。
资产版本化
与 Laravel 一样,您也可以通过调用来传递版本到 Inertia 服务
$inertia->version($version);
懒加载属性
当使用部分重载时,在服务器端使用懒数据评估更有效。
要使用懒数据,您需要使用 Rompetomp\InertiaBundle\Service\Inertia::lazy
示例用法
<?php namespace App\Controller; use Rompetomp\InertiaBundle\Service\InertiaInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class DashboardController extends AbstractController { public function index(InertiaInterface $inertia) { return $inertia->render('Dashboard', [ // using array 'usingArray' => $inertia->lazy(['SomeClass', 'someMethod']), // using string 'usingString' => $inertia->lazy('SomeClass::someMethod'), // using callable 'usingCallable' => $inertia->lazy(function () { return [...]; }), ]); } }
lazy
方法可以接受可调用对象、数组和字符串。当使用字符串或数组时,服务将尝试检查它是否是容器中的现有服务;如果不是,它将直接调用该函数
服务器端渲染
对于前端配置,只需遵循文档 https://inertia.laravel.net.cn/server-side-rendering#setting-up-ssr
设置 Encore / webpack
要正常运行 webpack,请安装 webpack-node-externals
npm install webpack-node-externals
接下来,我们将创建一个名为 webpack.ssr.config.js
的新文件。这与您的 webpack.config.js
几乎相同。请记住您需要保留这两个配置文件。
touch webpack.ssr.mix.js
以下是一个示例文件,用于 webpack.ssr.config.js
const Encore = require('@symfony/webpack-encore') const webpackNodeExternals = require('webpack-node-externals') const path = require('path') if (!Encore.isRuntimeEnvironmentConfigured()) { Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev') } Encore .setOutputPath('public/build-ssr/') .setPublicPath('/build-ssr') .enableVueLoader(() => {}, { version: 3 }) .addEntry('ssr', './assets/ssr.js') .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .enableSassLoader() const config = Encore.getWebpackConfig(); config.target = 'node'; config.externals = [webpackNodeExternals()]; module.exports = config
启用 SSR
要启用 SSR,您需要在您的包配置文件中添加配置 config/packages/rompetomp_inertia.yaml
rompetomp_inertia: ssr: enabled: true url: 'http://127.0.0.1:13714/render'
构建您的应用
您现在有两个构建过程需要运行——一个用于客户端包,另一个用于服务器端包
encore build encore build -- -c ./webpack.ssr.config.js
SSR 的构建文件夹将位于 public/build-ssr/ssr.js
。您可以通过更改输出路径(setOutputPath)在您的 ./webpack.ssr.config.js
中更改此路径
运行 Node.js 服务
要运行 SSR 服务,您需要通过 node 运行它。
node public/build-ssr/ssr.js
它将可在 http://127.0.0.1:13714
上访问,这里的路径需要放在我们的 ssr.url
中
使用此捆绑包的项目
- Ping CRM on Symfony - 官方的 Inertia.js 示例应用,移植到 Symfony
- Symfony + Inertia + Vuejs 模板 - 使用 Symfony、Webpack/Encore、Inertia 和 Vuejs 的 Github 模板仓库
- Symfony + Vite + Inertia + Vuejs 模板 - 使用 Symfony、Vite、Inertia 和 Vuejs 的 Github 模板仓库