Symfony 4 how to setup SPA ( single page app ) with React?

烂漫一生 提交于 2021-01-21 05:55:05

问题


I've not been able to have Symfony 4 work properly in a SPA setup.

Specifically, while I navigate using React-router links everything works as it should.

But if I try accessing any of the routes ( except home ) directly, Symfony intercepts it and, of course, throws an error for route not found.

The alternative of placing Symfony in a sub-domain and using it only as an API is not viable, as I need all the user and session management tools provided by the framework.

Of course I will need Symfony's routing for all API calls to the back-end.

I am using Symfony 4's default directory structure, only adding a directory /client at top level for all react/redux code.

The build code is placed under /public/build.

I also tried placing a .htaccess file on /public with below code, but that did not help.

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

Thanks


回答1:


A solution could be following.

The controller with route annotation, all routes will be handled by react with this annotation, no matter how many parameters the route might have:

namespace App\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

class DefaultController extends Controller
{
    /**
     * @Template("default/index.html.twig")
     * @Route("/{reactRouting}", name="index", requirements={"reactRouting"=".+"}, defaults={"reactRouting": null})
     */
    public function index()
    {
        return [];
    }
}

If you have routes that shouldn't be handled by react, your annotation could exclude them like as follows - all routes that start with api will not be handled by react:

@Route("/{reactRouting}", name="index", requirements={"reactRouting"="^(?!api).+"}, defaults={"reactRouting": null})

Twig Template, with root element:

{% extends 'base.html.twig' %}

{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('build/js/app.css') }}">
{% endblock %}

{% block body %}
    <div id="root"><div>
{% endblock %}

{% block javascripts %}
<script type="text/javascript" src="{{ asset('build/js/app.js') }}"></script>
{% endblock %}

React index file:

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route, Switch} from 'react-router-dom';

import Home from "./containers/Home";
import AboutUs from "./containers/AboutUs";


ReactDOM.render(
       <BrowserRouter>
            <Switch>
                <Route path="/" component={Home}/>
                <Route path="/about-us" component={AboutUs}/>
            </Switch>
        </BrowserRouter>,
    document.getElementById('root'));

And my encore config:

var Encore = require('@symfony/webpack-encore');

Encore
    // the project directory where compiled assets will be stored
    .setOutputPath('public/build/')
    // the public path used by the web server to access the previous directory
    .setPublicPath('/build')
    .cleanupOutputBeforeBuild()
    .enableSourceMaps(!Encore.isProduction())
    // uncomment to create hashed filenames (e.g. app.abc123.css)
    // .enableVersioning(Encore.isProduction())

    // uncomment to define the assets of the project
    // .addEntry('js/app', './assets/js/app.js')
    // .addStyleEntry('css/app', './assets/css/app.scss')

    // uncomment if you use Sass/SCSS files
    // .enableSassLoader()

    // uncomment for legacy applications that require $/jQuery as a global variable
    // .autoProvidejQuery()

    .enableReactPreset()
    .addEntry('js/app', './react/index.js')
    .configureBabel((config) => {
        config.presets.push('stage-1');
    })
;

module.exports = Encore.getWebpackConfig();



回答2:


I believe I found a possible setup.

Include the react-router routes on Symfony's routes.yaml, all pointing to the same controller that generates React's root component.

All other routes, like for API calls, would be set up normally.

//config/routes.yaml
//all routes handled by PWA(react-router) pointing to same controller
home:
   path: /
   controller: App\Controller\IndexController::index

account:
   path: /account
   controller: App\Controller\IndexController::index

If somebody knows an alternative setup, please share.



来源:https://stackoverflow.com/questions/49050757/symfony-4-how-to-setup-spa-single-page-app-with-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!