Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React build not working without adding index.html in URL [AWS S3 and Cloudfront deployment]

I am working with React JS application using Hash Routing. On local environment app is working fine.

e.g. https://stackoverflow.com/posts/ should be the URL of application but it is not working and I have to use https://stackoverflow.com/posts/index.html to make it working.

After deployment, I found that it is downloading with name "download" empty file instead of serving index.html file preset in build file. For running build on server I am using S3 and CloudFront architecture.

Now, I am in a situation where I cannot be able to figure out whether HASH routing is behaving wrong or something wrong with AWS deployment.

Code snippet with React JS

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './redux/store';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { HashRouter } from 'react-router-dom/cjs/react-router-dom';

ReactDOM.render(
 <Provider store={store}>
    <HashRouter>
      <App />
    </HashRouter>
  </Provider>

  document.getElementById('root')
);

Partial package.json content

{
  "name": "loremipsum",
  "version": "0.1.0",
  "private": true,
  "homepage": "/loremipsum/"
}
like image 906
Vikash Dhiman Avatar asked Sep 07 '25 08:09

Vikash Dhiman


2 Answers

Are you required to deploy on a subdirectory? If yes, you will have to change the contents of your package.json file to force assets to be served relative to index.html file.

{
  "name": "loremipsum",
  "version": "0.1.0",
  "private": true,
  "homepage": ".",
  "scripts": {
    "build": "react-scripts build",
    "build-prd": "PUBLIC_URL=http://www.foo/relativepath react-scripts build"
    // ...
  }
}

With this, we'll be able to move our app's hosted in http://www.foo to http://www.foo/relativepath or even https://www.foo/bar1/bar2/ without the need for rebuilds.

You will also have to override the PUBLIC_URL to include the domain and subdirectory where you'd like to host your file

like image 168
Allan Chua Avatar answered Sep 09 '25 03:09

Allan Chua


Sonetimes the development processing of static content (eg webpack dev server) and the deployed system (eg cloudfront) behave a little differently.

The way to control this in AWS is to use a lambda edge function that controls how paths are interpreted and the default document served. My blog post provides a summary, and this code shows one way of dealing with subpaths:

import {Context} from 'aws-lambda';

const handler = async (event: any, context: Context) => {

    const request = event.Records[0].cf.request;
    const requestUri = request.uri.toLowerCase();

    const extensions = [
        '.html',
        '.js',
        '.css',
        '.ico',
    ];

    const knownExtension = extensions.find((ext) => {
        return requestUri.endsWith(`${ext}`);
    });

    if (knownExtension) {
        return request;
    }

    const demoAppBasePath = '/demoapp/';
    if (requestUri.startsWith(demoAppBasePath)) {
        
        request.uri = `${demoAppBasePath}index.html`;
        return request;

    } else {

        request.uri = '/index.html';
        return request;
    };
};

export {handler};
like image 32
Gary Archer Avatar answered Sep 09 '25 03:09

Gary Archer