DEVELOPMENT by Pedro Resende
DEVELOPMENT by Pedro Resende
DEVELOPMENT by Pedro Resende

Symfony with React.js frontend Integration

The Internet brave new World

Post by Pedro Resende on the 29 of October of 2016 at 20:22

Tags: React.jsMVCSymfonyReactWebpackAzure

For the last three months, I've been working for a customer doing a migration from Wordpress to a custom solutions with React.js + Azure Microservices.

I have to say that at the beginning, React.js seemed to be a bit strange, however, today, I believe it's a perfect candidate to integrate with Symfony.

I'll explain a possible integration, this is only and example, if any of you believe there is a better approach, please leave a comment.

Let's start by installing Symfony

$ symfony new reactintegration

Now that we have a symfony installation, let's begin with the part of react.js integration

$ cd reactintegration
$ npm init .

Now that we have a npm project at the root of our Symfony installation, lets install the needed packages

$ npm install --save react react-dom babel-loader babel-core babel-preset-es2015 babel-preset-react react-hot-loader react-router webpack jquery
Let's start by creating a babel presets for react and ES2015. This will allow to write ES2015 and React.js JSX into current javascript
$ vi .babelrc

Add to the file

{
    "presets" : ["es2015", "react"]
}

Edit package.js file and add the following on the "scripts" section

  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch",
  },

Now, lets create our webpack.config.js

$ vi webpack.config.js

Add the following inside

var webpack = require('webpack');
var path = require('path');

var BUILD_DIR = path.resolve(__dirname, 'web');
var APP_DIR = path.resolve(__dirname, 'react');
var config = {
    entry: [
        APP_DIR + '/app.jsx',
    ],
    output: {
        path: BUILD_DIR,
        filename: 'app.bundle.js',
    },
    module: {
        loaders: [{
            test: require.resolve("jquery"),
            loader: "imports?jQuery=jquery"
        }, {
            test: /.jsx?$/,
            loader: 'babel-loader',
            exclude: /node_modules/,
            query: {
              presets: ['es2015', 'react']
            }
        }, {
            test: /\.css$/,
            loaders: ['style', 'css', 'less']
        }]
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify('production')
            }
        }),
    ],
};

module.exports = config;

Now, lets create our React.js source

$ mkdir react

$ vi app.jsx

I'll add some demonstration code, that will allow you to see this example in action

import React from 'react';

import {render} from 'react-dom';

import {
    Router,
    Route,
    IndexRoute,
    Link,
    browserHistory,
    Redirect,
    IndexRedirect
} from 'react-router';

var Homepage = React.createClass({
    render: function() {
        return (
            HEllo World
        )
    }
});


var Homepage2 = React.createClass({
    render: function() {
        return (
            HEllo World2
        )
    }
});

var Homepage404 = React.createClass({
    render: function() {
        return (
            404
        )
    }
});

render((
        <Router history={browserHistory}>
            <Route path="/">
                <IndexRoute component={Homepage}/>
                <Route path="hi" component={Homepage2}/>
                <Route path="*" component={Homepage404}/>
            </Route>
        </Router>
), document.getElementById('app'));
We're almost there, now we all need to do is add the app.bundle.js to our Symfony part
$ vi app/Resources/default/index.html.twig

Replace all the content with

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

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

{% block javascripts %}
    <script src={{ asset('app.bundle.js') }} type="text/javascript"></script>
{% endblock %}
Let's prepare our Controller to deal with React.js
$ vi src/AppBundle/Controller/DefaultController.php

Replace the all the content with

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class DefaultController extends Controller
{
    /**
     * @Route("/api/{slug}", name="API")
     */
    public function apiAction(Request $request, $slug = null)
    {
        // replace this example code with whatever you need
        // Symfony Backend integration
    }

    /**
     * @Route("/", name="homepage")
     * @Route("/{slug}", name="homepage2")
     */
    public function indexAction(Request $request, $slug = null)
    {
        // replace this example code with whatever you need
        return $this->render('default/index.html.twig', [
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
        ]);
    }
}

Now, eveytime you access to "/" our "/{slug}" it will used react-router, the "/api/{slug}" it will use Symfony

To end, we need to "compile" react.js into our app.bundle.js, to do that run the following command

$ npm run watch

This way, everytime you make a change to app.jsx it will re-create a new app.bundle.js file

Now start symfony's server by running

$ php bin/console server:run

and access with your browser to 

http://localhost:8080/

You'll see "HEllo World", if you try to access "/lsakdjjksda" you'll be reddirect to the 404 React.js route but if you access to "/api/" the response will be from symfony.

That is it, please let me know if you propose a different approach, the code is available at this link.

© 2014-2025 DEVELOPMENT byPedro Resende