Integrating Single Page React Code into Existing Javascript Application

Overview

The existing javascript application is using the following

  • javascript

  • PHP v8 as its backend server code

  • Bootstrap@3.3.7

A single page is all the code in one application, and when the application is rendered in a browse all the interaction with the application is done on the single page that is rendered.

You should be familiar with React especially the creation of an app using create-react-app.

Also, familiarity with using Webpack will be helpful.

There are plenty of websites which discuss the above so please familiarise yourself if required.

Aim of the Article

The aim of the article is two-fold:-

  • Create a React app so it can be integrated into an existing javascript non-React application

  • Allow the React app to run on its own as a standalone – for testing purposes

The React app that is being built is primarily built to run inside an existing application. It will not have the usual checks and settings of system-wide variables such as checking user has logged in and what access the user has. This will be controlled by the existing application into which the React application will be placed. The existing React application will be built so that we can test it works without having to build it, place it in the existing application and then checking if it works. There are a few cheats to allow us to do this which I will discuss at the end of the article as an aside.

Get the Structure Right

In order not to duplicate code it's best to place the React code within the structure of the existing app so that it can take advantage of accessing the programs of the existing application. This is generally to do with accessing the code which queries/updates records in the database.

Existing Application

Development: localhost/base/{application code}

LIVE: live_url/{application code}

Below is a simplistic representation of the existing application code and its location.

React Application

The React application is created by using create-react-app.

The structure below shows a few of the directories and files created by create-react-app and the ones we are most interested in for our goal. Within “src” you will naturally have the application code.

index.html created by create-react-app

index.js created by create-react-app

package.json created by create-react-app

mainReact.js your React Application main program created by you.

I will not discuss too much what’s inside them as that is not the point of the article. I will just discuss what changes are required so that we can integrate the React application into our existing application.

Marry the Two

Place the React application inside the existing application code.

Run Standalone React App

With this structure, the standalone React application can be run without any issues.

Run the following command from the {reactapp} directory.

C:\{reactapp}>npm start

This will render the application in your default browser.

Run React App within Existing Application

The following is the index.js file used by the standalone React application.

Index.js used for standalone.

import React from 'react';

import ReactDOM from 'react-dom/client';

import './fonts.css';

import './index.css';

/* Bootstrap CSS */

import "bootstrap/dist/css/bootstrap.min.css";

import "./App.css";
/* MAIN REACT COMPONENT */
import App from './mainReact.js';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

    <React.StrictMode>

        <App />

    </React.StrictMode>

);

The main React component, './mainReact.js', is imported into App which is rendered where the ‘root’ element is referenced.

When building the React application, we will use the above index.js.

If we are building to integrate into an existing application, there are a few issues that we need to be aware of. Some of the libraries used in this program may already be loaded into your existing application before this code is loaded and run. In that case, there will be a clash with some unforeseen behaviour.

With that in mind, we need to sort out the above index.js so that: -

  • The standalone React application loads what it requires and runs.

  • When the React application is integrated into the existing application, there are no issues with double loading.

The solution is to have 2 index.js files, one for standalone and one for integration.

index.js used for integrating.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './fonts.css';
import './index.css';

/* Bootstrap CSS IS NOW REMOVED*/

/* import "bootstrap/dist/css/bootstrap.min.css"; */

import "./App.css";

import App from './ mainReact.js';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

    <React.StrictMode>

        <App />

    </React.StrictMode>

);

The above will now create the "build" code without loading the bootstrap css. This css will already be loaded by your existing application.

Build React Application Code

What needs to be done now is to build the React application code into a production-ready javascript script.

Remember: The build “grabs” all of your React application code and places it into a single js file.

package.json

The default package.json file is good to go, you don’t need to change anything.

Lets’ have a look at it.

{
    "name": "my-react-app",
    "version": "0.1.0",
    "private": true,
    "dependencies": {
        "@testing-library/jest-dom": "^5.16.5",
        "@testing-library/react": "^13.4.0",
        "@testing-library/user-event": "^13.5.0",
        "react": "^18.2.0",
        "react-dom": "^18.2.0",
        "react-scripts": "5.0.1",
        "web-vitals": "^2.1.4"
    },
    "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject"
    },
    "eslintConfig": {
        "extends": [
                    "react-app",
                    "react-app/jest"
        ]
    },
    "browserslist": {
        "production": [
                        ">0.2%",
                        "not dead",
                        "not op_mini all"
        ],
    "development": [
                        "last 1 chrome version",
                        "last 1 firefox version",
                        "last 1 safari version"
    ]
}

I will not go into anything apart from mentioning the following two scripts elements:-

  •     "scripts": {
                "start": "react-scripts start",
                "build": "react-scripts build",
    

cd to {reactapp} and run command

C:\{reactapp}>npm run build

The command will run "react-scripts build", which will, by default, create the production-ready code in build/static/js located in {reactapp} directory.

The build js script will look something like this:- main.f522ce34.js

You can rename it so it doesn’t look too “machine-codey” but for the sake of clarity, we will retain the name.

Add Built Code into Existing Application

As we have created a structure where the React application code lives within the existing application code, it's simple enough for an existing application program to reference the built code.

Where to locate the built code is purely down to the developer or the strategy used by your organisation.

Personally, I would just move the code from where it was built into its own directory within the existing application, so we are 100% sure where the React-built code lives.

As an example create a new directory within the existing application called {REACTCODE} and move the built code into that

Now in your existing application program, eg Program1.php add the code.

Program1.php

<?php
?>

<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body>
        <div id="root"></div>
        <script src="{REACTCODE}/main.f522ce34.js" language="javascript"         
                type="text/javascript"></script>
    </body>
</html>

The above HTML can have whatever it requires. It can include your organisation's look and feel.

The only things required for the React application to be rendered within your existing application program are:-

  • An anchor where the React application code will be rendered.

  • The actual React application code which was built.

By default, React renders to a div with id of “root” so that’s what we will use.

<div id="root"></div>

We place the React app code within the script tag at the end of the body tag.

AND THAT’S IT. When {application-code}/Program1.php gets run, the React App will appear in your browse.

ASIDE

Multiple Entry Points

A worthwhile task to undertake now would be to take the swapping of index.js out of the equation. It is going to be a pain to keep on swapping index.js whenever you want to change what you want to do with the code, ie run it as a standalone or build it for use in an existing application.

To make our life easier and prevent us from accidently running the wrong index.js and spending time investigating why our application has suddenly stopped working, we will implement multiple entry points

One entry point used for the standalone React App, and another entry point for the build.

To help us achieve our goal we will:-

  • create a new entry point used only when building the React app.

  • Introduce webpack.

  • Change package.json to use webpack.

New entry point used just for the build

Let's call the new entry point index_for_existing.js. This is the same as the index.js we used earlier when the build was done.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './fonts.css';
import './index.css';

/* Bootstrap CSS IS NOW REMOVED*/

/* import "bootstrap/dist/css/bootstrap.min.css"; */

import "./App.css";

import App from './ mainReact.js';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

    <React.StrictMode>

        <App />

    </React.StrictMode>

);

This is placed wherever you want but obviously, the best place is in the "src" directory where the existing index.js lives.

Webpack

Webpack is a module bundling system allowing many things, one of which is to control the entry point of our React application upon build, and control what it's called and where it will be saved to.

Once again there are plenty of websites that discuss the installation and then usage of webpack but I will just concentrate on the entry point and bundling.

The webpack config file is called webpack.config.js and lives at the same level as your React app base directory.

webpack.config.js

const path = require('path');

module.exports = {
    entry: {app: path.join(__dirname, 'src/index_for_existing.js')},
    output: {
              path: path.join(__dirname, 'build/static/js'),
              filename: '[name].js'
},

entry - this informs the build module to use a new index.js file as its entry point ie index_for_existing.js

app is the name of the file that will be created.

output defines the path and the filename that will be created.

Filename takes "name" from the entry so when "build" creates the bundle it will be called app.js.

We need to change package.json so that the "npm run build" command knows to use webpack.

package.json

The file is the same as before apart from two lines in the script tag

Only the script tag is shown below.

    "scripts": {
        "start": "react-scripts start",
        "build": "npm run build:app && npm run build:bundle",
        "test": "react-scripts test",
        "eject": "react-scripts eject",
        "build:bundle": "webpack --mode production"

The "build" element of the script tag now has an extra "npm run build:bundle".

It also has a new element called "build:bundle" which will use webpack and run the build in production mode. This will look in webpack.config.js file for various settings it needs to do the bundling.

AND that is it.

We can now run our standalone React app by running command

C:\{reactapp}>npm start

Which will use the index.js file in our src directory.

And when we do a build with command

C:\{reactapp}>npm run build

Package.json will use webpack settings and use index_for_existing.js as its entry point and do the build.

Accessing Existing Code

The reason we placed the React source code within the existing application was for the standalone React application to leverage some of the code used by the existing application.

I am sure there are many ways to do this, but I will explain the way I did it.

The trick is to work out which environment the React code is running in and then allow the React code to access the existing applications code accordingly.

To help achieve that we will use an environment variable file, ".env", created by the dotenv package.

Install dotenv

C:\{reactapp}>npm install dotenv --save

dotenv will be added as a dependency of your project within package.json.

    {
        "name": "myproj",
        "version": "0.1.0",
        "private": true,
        "dependencies": {
                        :
                        "dotenv": "^16.0.3",
                        :

Create .env File

.env file must be in base directory ie where package.json is.

Also, make sure it's in .gitignore as we don’t want to pass it down the line into our test or live environments.

IMPORTANT – All variables within the .env file must begin with REACT_APP_

Inside .env

REACT_APP_BASE_FOLDER=http://localhost/

Reference in React Component

Inside any React application code, the environment variable can be accessed using process object.

In the example case, REACT_APP_BASE_FOLDER is only non-blank if being run as a standalone React application.

Obviously, anything can be placed in the .env and it can be picked up using process.env.

Within mainReact.js

if (process.env.REACT_APP_BASE_FOLDER===""){
    url="Program2.php";
}
else{
    url=process.env.REACT_APP_BASE_FOLDER + "Program2.php";
}

The url can be used to access existing application code.

Within Existing Application Code

The existing application code which loads the React code will also have to have process.env otherwise application will fall over when process.env is encountered.

The easiest way is to just create a process.env object from within the existing application code. In this example, Program1.php has been used so we will change that to create the process.env object.

Program1.php

<?php
?>

<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script>
            var process = {};
            process["env"] = {};
            process.env["REACT_APP_BASE_FOLDER"] = "";
        </script>    
</head>
    <body>
        <div id="root"></div>
        <script src="{REACTCODE}/main.f522ce34.js" language="javascript"         
                type="text/javascript"></script>
    </body>
</html>

The bit added is the following

        <script>
            var process = {};
            process["env"] = {};
            process.env["REACT_APP_BASE_FOLDER"] = "";
        </script>

We are now done.

Remember: There is nothing that cannot be learnt. Be persistent and don't give up, after all, they are free and you supply the quantity.