symfony-react-sandbox
symfony-react-sandbox copied to clipboard
Integration with FOSJsRoutingBundle
RIght now the routes in React are hardcoded, and that is ugly. We should be able to use FosJsRoutingBundle and integrate it into Webpack.
I guess we could require in the Webpack bundles web/bundles/fosjsrouting/js/router.js
and also load the route fos_js_routing_js
with a url-loader
.
Did anyon succesfully combine the 2 yet?
Is this still in the works? Would be much easier to work with
If someone has a good idea/implementation for this...
I do it like this: in webpack.config.babel.js
const setup = {
resolve: {
alias: {
'FosRouter': path.resolve('./web/bundles/fosjsrouting/js/', 'router.js'),
'FosRoutes': path.resolve('./web/js/', 'fos_js_routes.js')
},
modules: [
path.resolve('js'),
'node_modules'
]
}
module.exports = setup;
then in react - create a component:
import 'FosRouter';
import 'FosRoutes';
const Router = window.fos && window.fos.Router;
export default Router.getInstance();
and then import this component where u need the get the route:
import Router from '../util/Router';
console.log(Router.generate('app_options'));
@luchianenco how do you get window working in SSR ? i'm using a dynamic route handling, you can saw an little exemple in react-router doc https://reacttraining.com/react-router/web/guides/server-rendering/data-loading using a array of route object sending from symfony, this array is actualy writed by hand but i'll make a manager to dynamicaly add a route from any bundle by using service (actually in syfmony 3.x we can easily call service by require them with a type requirement argument ...)
i'm using 'switchs' in my routes array to configure imbriqued routes but you can name whatever you want
here is my actual array sending
'router' => [
'routes' =>[
[
'name' => 'admin',
'path' => '/:locale/admin',
'exact' => false,
'show' => false,
'component' => 'AdminNavbar',
'switchs' => [
[
'name' => 'adminRoot',
'path' => '/:locale/admin',
'exact' => true,
'component' => 'AdminRoot',
'switchs' => []
],
[
'name' => 'adminNotFoud',
'path' => '/:locale/admin/*',
'exact' => false,
'component' => 'NotFound',
'switchs' => []
]
],
'links' => [
[
'type' => 'internal',
'path' => '/:locale/',
'name' => 'homepage',
]
],
],
[
'name' => 'homepage',
'path' => '/:locale/',
'exact' => false,
'show' => false,
'component' => 'MainNavbar',
'switchs' => [
[
'name' => 'root',
'path' => '/:locale/',
'exact' => true,
'component' => 'MainRoot',
'switchs' => []
],
[
'name' => 'main',
'path' => '/:locale/main',
'exact' => false,
'component' => 'Main',
'switchs' => [
[
'name' => 'mainTimer',
'path' => '/:locale/main/timer',
'exact' => false,
'component' => 'Timer',
'switchs' => [
[
'name' => 'mainTimerTimer',
'path' => '/:locale/main/timer/timer',
'exact' => false,
'component' => 'Timer',
'switchs' => []
]
]
],
]
],
[
'name' => 'timer',
'path' => '/:locale/timer',
'exact' => false,
'component' => 'Timer',
'switchs' => [],
],
[
'name' => 'notFound',
'path' => '/:locale/*',
'exact' => false,
'component' => 'NotFound',
'switchs' => []
]
],
'links' => [
[
'type' => 'internal',
'path' => '/:locale/admin',
'name' => 'admin',
'switchs' => [
[
'name' => 'testtest',
'path' => '/:locale/testtest',
]
]
],
],
],
],
]
this is added to a global store to let every components acces this array if necessary and there is my route component who generate the tree to be used by react router
import React from 'react'
import App from '../container/App'
import * as AllComponent from '../container/index'
import { connect } from 'react-redux'
import {
Route,
Switch,
withRouter
} from 'react-router-dom'
class Routes extends React.Component {
constructor(props){
super(props)
}
addRoute(r,i){
const Component = AllComponent[r.component]
if( typeof(Component) === 'undefined'){
if(this.props.env.devMode === true){
console.log("'" + r.component + '\' component not found ! from ' , r)
}
return false
}
return(
<Component exact={r.exact} key={i} path={r.path} >
<Switch>
{ r.switchs.map(this.addRoute.bind(this))}
</Switch>
</Component>
)
}
render() {
return (
<App>
<Switch>
{
this.props.router.routes.map(this.addRoute.bind(this))
}
</Switch>
</App>
);
}
}
const mapStateToProps = (state) => (
{
localeManager: state.localeManager,
request: state.request,
router: state.router,
env: state.env
}
)
export default withRouter(connect(mapStateToProps)(Routes))
the AllComponent is an object who let call any component with a string name (stored with route) i also added link who isnt used in route component but usefull to set up additional link for dynamic render a navbar (for exemple a link to admin from home and a link to home from admin), is up to you to add aditional info to set admin role requirement for route show or seomething else in router....
// .../container/index.js
export { default as AdminNavbar } from './AdminNavbar'
export { default as AdminRoot } from './AdminRoot'
export { default as App } from './App'
export { default as Main } from './Main'
export { default as MainNavbar } from './MainNavbar'
export { default as MainRoot } from './MainRoot'
export { default as NotFound } from './NotFound'
export { default as Timer } from './timer'
@luchianenco here is an alternative solution from @weaverryan
https://github.com/symfony/webpack-encore/issues/97#issuecomment-315757285
@acidjames this is a nice tool, but in April it was not yet published ;)