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/"
}
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
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};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With