How to use index.php as the index file with create-react-app

Recently I came across a scenario with a react app, where I had to use index.php as the index file instead of the usual index.html file due to some legacy configuration bootstrapping. Webpack by default, does not understand how to deal with php files and at the same time, did not want to lose the live reload capabilities that comes with webpack.

Let us see how this can be solved.

So we start with creating a react app using create-react-app

We will be ejecting out of create-react-app for simplification, but you can still try out non ejecting ways to modify webpack configuration.

HtmlWebpackPlugin is a webpack plugin that is used under the hoods to generate the index.html file in create-react-app. It has a bunch of other functionality built in. Check out at https://github.com/jantimon/html-webpack-plugin

In create-react-app, public/index.html is used as the template for Html webpack plugin.

HtmlWebpackPlugin uses this template index file, injects a scripts tag referencing webpack bundle( that gets generated during webpack build) and outputs an index.html and assets. It also hashes the bundle etc.

When running with webpack-dev-server, index.html and bundles are not written to disk but served from memory. Webpack dev server also injects piece of code into the bundle that is responsible for live reloading.

So Let’s try to use a index.php file as template index file.

Let us move the index.html from public directory to srcdir and rename it to index.php and modify appHtml value in config/paths.js file.

Running yarn start. we get the following error

We see that the index.php file gets generated and also with a hash. This is because webpack config does not know how to treat this type of file extension. So the default file-loader kicks in which treats it as a file and browser downloads.

Let’s add an exception to not treat this a file loader. Am adding a php extension to be excluded by the file-loader

At this point, we see that it actually runs fine. But we don’t have any php code there and since there is valid html and webpack dev server in memory index file is all fine

Let’s add some php code in the index.php.

After it live reloads, it seems to be still working but php code does not get executed.

Let’s try to get the php code executed. Before that we need a php runtime. I have setup a docker for apache php.

Dockerfile looks like

and docker-compose.yml file looks like

docker-compose up will bring up the apache server running on port 80

As we said before, when running with webpack-dev-server, the generated index file is in memory. This is a problem because this memory cant be shared with the apache-php server.

So we use a webpack plugin called html-webpack-harddisk-plugin to share it with the apache-php server through the disk.

and make the following changes.

  • We tell it to write always to disk.
  • Configure the output path in HtmlWebpackHardDiskPlugin. The default is dist . We will change it to public when running in development mode and build when running in production mode.

The next thing is we use a proxy to send the index.php request from webpack-dev-server to the apache-php server (to get php part of the code executed)

Setting up proxy is quite straight forward with create-react-app and documented at https://create-react-app.dev/docs/proxying-api-requests-in-development/

Create a file called setupProxy.js in src

Let us add some code in App.js to display the message from php land in the javascript land.

Nowyarn start again. You will see this screen

Click on index.php and we can see that php code gets executed and we see the message from the php land. Any changes to javascript should still reload the changes.

You can find the project at https://github.com/agenthunt/cra-apache-php-index-demo

Updated: 2021–03–13

Solving Problems. Making Software Better. Intrigued by Elegant Solutions. https://twitter.com/agent_hunt

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store