DavidDev
DavidDev

Reputation: 13363

React-router URLs don't work when refreshing or writing manually

I'm using React-router and it works fine while I'm clicking on link buttons, but when I refresh my webpage it does not load what I want.

For instance, I am in localhost/joblist and everything is fine because I arrived here pressing a link. But if I refresh the webpage I get:

Cannot GET /joblist

By default, it didn't work like this. Initially I had my URL as localhost/#/ and localhost/#/joblist and they worked perfectly fine. But I don't like this kind of URL, so trying to erase that #, I wrote:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

This problem does not happen with localhost/, this one always returns what I want.

This app is single-page, so /joblist doesn't need to ask anything to any server.

My entire router.

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

Upvotes: 1301

Views: 901536

Answers (30)

Sachin Barpanda
Sachin Barpanda

Reputation: 31

See the problem is react serve single page application so I don't think there is any way you can access your files directly if you are going to use a single react project and a single server ,

I would suggest you using react-router-dom and replacing the href tags with navigate() function and a tag with Link tag , if you want to hide your data then you have to actually make a separate react project or a public folder in your server , basically do ssr for that purpose .

Here is my sample code where I wanted to add post and some Link Tags example :

const navigate = useNavigate(); const userData = useSelector((state) => state.auth.userData);

const submit = async (data) => {
    if (post) {
        const file = data.image[0] ? await appwriteService.uploadFile(data.image[0]) : null;

        if (file) {
            appwriteService.deleteFile(post.featuredImage);
        }

        const dbPost = await appwriteService.updatePost(post.$id, {
            ...data,
            featuredImage: file ? file.$id : undefined,
        });

        if (dbPost) {
            navigate(`/post/${dbPost.$id}`);
        }
    } else {
        const file = await appwriteService.uploadFile(data.image[0]);

        if (file) {
            const fileId = file.$id;
            data.featuredImage = fileId;
            const dbPost = await appwriteService.createPost({ ...data, userId: userData.$id });

            if (dbPost) {
                navigate(`/post/${dbPost.$id}`);
            }
        }
    }
};

The Link example for checking if the user is the author

{isAuthor && (
                        <div className="absolute right-6 top-6">
                            <Link to={`/edit-post/${post.$id}`}>
                                <Button bgColor="bg-green-500" className="mr-3">
                                    Edit
                                </Button>
                            </Link>
                            <Button bgColor="bg-red-500" onClick={deletePost}>
                                Delete
                            </Button>
                        </div>
                    )}

Remember that this is an illusion we are creating for the user that it's a multi page application whereas in reality it's a single page application made in such way that it loads data like a multi page application.

Upvotes: 0

Apurv
Apurv

Reputation: 123

The three ways to solve a problem first, we edit and change access control in the .htaccess file but this is not a good option and the second is to use <HashRouter> instant of <BrowserRouter> but it will add https://example.com/#/ after the domain name.

The third best way to solve this issue is to add the below code in app.js

 app.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../httpdocs/index.html'));
 });

To add the correct path of your index.html file in the hosting panel

Upvotes: 0

ABDUL WADOOD
ABDUL WADOOD

Reputation: 59

Some deployment platforms, like GitHub Pages or Netlify, may require additional configuration for client-side routing to work correctly. IF you're encountering 404 errors for URLs, you likely need to configure Netlify to support client-side routing.

Here's how you can configure Netlify for client-side routing:

Create a _redirects file: In your React project, create a file named _redirects in the public directory (if it doesn't exist already). This file will contain redirect rules to ensure that all URLs are served the main index.html file.

/*    /index.html   200

Same with github using 404.html page

Upvotes: 1

Fego
Fego

Reputation: 175

If using serve (npm package) to serve your React app and you can't configure your .htaccess or nginx.conf file, you can set your start command for serve to be

serve dist/ -s

The -s flag tells serve that your app is an SPA and it should respond with index.html to all network calls. Then your app will work.

Credit: https://help.railway.app/project-help/f9v3gkPQRy4UShk5SnoPDH/getting-your-create-react-app-running-on-railway/qHRsgxa5n57xLp1yVgk9fP

Upvotes: 2

yogesh kumar
yogesh kumar

Reputation: 103

Solution for react-router-dom: 6

Replace BrowserRouter with HashRouter

Using HashRouter will add /# in URLs but this will solve most of the problems of refresh/reload.

Upvotes: -2

balaji gv
balaji gv

Reputation: 41

if you are using Hostringer

create a .htaccess (make sure there's no file extension like .txt) in root file of ur file manager

paste the below code

RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

refresh the website

Upvotes: 2

Shubham
Shubham

Reputation: 21

Just add this server.js in the root directory.

const express = require('express');
const path = require('path');

const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/*', function(req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(3000);
console.log('Server started on port 3000');

and change package.json

    "start": "node server.js",

Upvotes: 1

Esteban
Esteban

Reputation: 180

In case your URLs work OK locally, but you get a blank page with the error Not found when deploying your React App in Render Cloud, it is possible that you did not set up client side routing

enter image description here

Upvotes: 3

sanjarcode
sanjarcode

Reputation: 570

Use useEffect to read the URL and apply the changes you want.


For example - a page has a button that opens a slider. When the button is clicked, a query param for the slider is added to the URL and the slider is opened.

Problem - on refreshing the page with the slider opened, the loaded page does not show the opened slider, even if the query param is present.

Solution: add a useEffect that reads the "slider" query param, and runs the button handler. Add a state variable for the slider query param, and also include it in the useEffect's dependency array.

You don't need to worry about backend request, assuming there is one in the slider component.

Upvotes: 0

Md. Shafiqul Islam
Md. Shafiqul Islam

Reputation: 394

I faced same issue when i used apache(Httpd) server. I solved bellowing this way and works 100% for me.

step-1:

  • Go /etc/httpd/conf/httpd.conf / for new version go to etc/apache2/apache2.conf
  • Change the AllowOverride None to AllowOverride All.
  • Restart the apache server.

step-2:

After build make a .htaccess file into root folder.

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

Upvotes: 3

BrahimS
BrahimS

Reputation: 2663

If you are using Apache as your web server, you can insert this into your .htaccess file:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]
</IfModule>

I am using react: "^16.12.0" and react-router: "^5.1.2" This method is the Catch-all and is probably the easiest way to get you started.

Upvotes: 264

Stijn de Witt
Stijn de Witt

Reputation: 42154

Server-side vs Client-side

The first big thing to understand about this is that there are now 2 places where the URL is interpreted, whereas there used to be only 1 in 'the old days'. In the past, when life was simple, some user sent a request for http://example.com/about to the server, which inspected the path part of the URL, determined the user was requesting the about page, and then sent back that page.

With client-side routing, which is what React Router provides, things are less simple. At first, the client does not have any JavaScript code loaded yet. So the very first request will always be to the server. That will then return a page that contains the needed script tags to load React and React Router, etc. Only when those scripts have loaded does phase 2 start. In phase 2, when the user clicks on the 'About us' navigation link, for example, the URL is changed locally only to http://example.com/about (made possible by the History API), but no request to the server is made. Instead, React Router does its thing on the client-side, determines which React view to render, and renders it. Assuming your about page does not need to make any REST calls, it's done already. You have transitioned from Home to About Us without any server request having fired.

So basically when you click a link, some JavaScript runs that manipulates the URL in the address bar, without causing a page refresh, which in turn causes React Router to perform a page transition on the client-side.

But now consider what happens if you copy-paste the URL in the address bar and e-mail it to a friend. Your friend has not loaded your website yet. In other words, she is still in phase 1. No React Router is running on her machine yet. So her browser will make a server request to http://example.com/about.

And this is where your trouble starts. Until now, you could get away with just placing a static HTML at the webroot of your server. But that would give 404 errors for all other URLs when requested from the server. Those same URLs work fine on the client-side, because there React Router is doing the routing for you, but they fail on the server-side unless you make your server understand them.

Combining server- and client-side routing

If you want the http://example.com/about URL to work on both the server- and the client-side, you need to set up routes for it on both the server- and the client-side. It makes sense, right?

And this is where your choices begin. Solutions range from bypassing the problem altogether, via a catch-all route that returns the bootstrap HTML, to the full-on isomorphic approach where both the server and the client run the same JavaScript code.

Bypassing the problem altogether: Hash History

With Hash History, instead of Browser History, your URL for the about page would look something like this: http://example.com/#/about

The part after the hash (#) symbol is not sent to the server. So the server only sees http://example.com/ and sends the index page as expected. React Router will pick up the #/about part and show the correct page.

Downsides:

  • 'ugly' URLs
  • Server-side rendering is not possible with this approach. As far as search engine optimization (SEO) is concerned, your website consists of a single page with hardly any content on it.

Catch-all

With this approach, you do use the Browser History, but just set up a catch-all on the server that sends /* to index.html, effectively giving you much the same situation as with Hash History. You do have clean URLs however and you could improve upon this scheme later without having to invalidate all your user's favorites.

Downsides:

  • More complex to set up
  • Still no good SEO

Hybrid

In the hybrid approach, you expand upon the catch-all scenario by adding specific scripts for specific routes. You could make some simple PHP scripts to return the most important pages of your site with content included, so Googlebot can at least see what's on your page.

Downsides:

  • Even more complex to set up
  • Only good SEO for those routes you give the special treatment
  • Duplicating code for rendering content on server and client

Isomorphic

What if we use Node.js as our server so we can run the same JavaScript code on both ends? Now, we have all our routes defined in a single react-router configuration and we don't need to duplicate our rendering code. This is 'the holy grail' so to speak. The server sends the exact same markup as we would end up with if the page transition had happened on the client. This solution is optimal in terms of SEO.

Downsides:

  • Server must (be able to) run JavaScript. I've experimented with Java in conjunction with Nashorn, but it's not working for me. In practice, it mostly means you must use a Node.js based server.
  • Many tricky environmental issues (using window on server-side, etc.)
  • Steep learning curve

Which should I use?

Choose the one that you can get away with. Personally, I think the catch-all is simple enough to set up, so that would be my minimum. This setup allows you to improve on things over time. If you are already using Node.js as your server platform, I'd definitely investigate doing an isomorphic app. Yes, it's tough at first, but once you get the hang of it it's actually a very elegant solution to the problem.

So basically, for me, that would be the deciding factor. If my server runs on Node.js, I'd go isomorphic; otherwise, I would go for the Catch-all solution and just expand on it (Hybrid solution) as time progresses and SEO requirements demand it.

If you'd like to learn more about isomorphic (also called 'universal') rendering with React, there are some good tutorials on the subject:

Also, to get you started, I recommend looking at some starter kits. Pick one that matches your choices for the technology stack (remember, React is just the V in MVC, you need more stuff to build a full app). Start with looking at the one published by Facebook itself:

Or pick one of the many by the community. There is a nice site now that tries to index all of them:

I started with these:

Currently, I am using a homebrewed version of universal rendering that was inspired by the two starter kits above, but they are out of date now.

Good luck with your quest!

Upvotes: 1853

Efe Ariaroo
Efe Ariaroo

Reputation: 1080

In your index.html file's head, add the following:

<base href="/">
<!-- This must come before the CSS and JavaScript code -->

Then, when running with the Webpack development server, use this command.

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback is the important part

Upvotes: 57

Stevie
Stevie

Reputation: 396

Here is a frontend workaround I discovered that does not require modifying anything on the server.

Let's say your site is mysite.com and you have a React Route to mysite.com/about. In index.js, where you mount your top-level component, you can put another Router like:

ReactDOM.render(
<Router>
    <div>
        <Route exact path="/" component={Home} />
        <Route exact path="/about"
            render={(props) => <Home {...props} refreshRout={"/about"}/>}
        />
    </div>
</Router>,

I'm assuming you have the original Router located somewhere below the top-level component in the virtual DOM. You also have to catch the url in your .urls if you are using Django like:

urlpatterns = [
       path('about/', views.index),
]

This will depend on what backend you're using, however. Requesting mysite/about will get you into index.js (where you mount the top-level component) where you can use the render prop of the Route, rather than the component prop, and pass '/about' as a prop to, in this example, the Home component.

Within Home, in either componentDidMount() or the useEffect() hook, do:

useEffect() {
   //check that this.props.refreshRoute actually exists before executing the
   //following line
   this.props.history.replace(this.props.refreshRoute);
}

I've assumed your Home component is rendering something like:

<Router>
   <Route exact path="/" component={SomeComponent} />
   <Route path="/about" component={AboutComponent} />
</Router>

Credit to (Pass props to a component rendered by React Router) for how to pass props to components in Routes.

Upvotes: 0

Koushik Das
Koushik Das

Reputation: 10813

A solution in React for a JavaScript SPA with Laravel

The accepted answer is the best explanation of why such problems happen. As already explained, you have to configure both the client side and server side.

In your blade template, include the JavaScript bundled file, make sure to use URL facade like this:

<script src="{{ URL::to('js/user/spa.js') }}"></script>

In your routes, make sure to add this to the main endpoint where the blade template is. For example,

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

The above is the main endpoint for the blade template. Now add an optional route too,

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

The problem that happens is that first the blade template is loaded, then the React router. So, when you're loading '/setting-alerts', it loads the HTML content and the JavaScript code.

But when you load '/setting-alerts/about', it first loads on the server side. Since it is on the server side, there isn't anything on this location, and it returns not found. When you have that optional router, it loads that same page and React Router is also loaded, then the React loader decides which component to show.

Upvotes: 2

Kiran Joshi
Kiran Joshi

Reputation: 151

Try adding a ".htaccess" file inside the public folder with the below code.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]

Upvotes: 15

Martin Lloyd Jose
Martin Lloyd Jose

Reputation: 480

For those who are using IIS 10, this is what you should do to make this right.

Be sure that you are using browserHistory with this. As for reference, I will give the code for the routing, but this is not what matters. What matters is the next step after the component code below:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

Since the problem is IIS receives requests from client browsers, it will interpret the URL as if it is asking for a page, then returns a 404 page since there isn't any available page. Do the following:

  1. Open IIS
  2. Expand Server, and then open the Sites Folder
  3. Click the website/application
  4. Go to the Error Pages
  5. Open the 404 error status item in the list
  6. Instead of the option "Insert content from static file into the error response", change it to "Execute a URL on this site" and add "/" slash value to the URL.

And it will now work fine.

Enter image description here

Enter image description here

Upvotes: 11

Chtioui Malek
Chtioui Malek

Reputation: 11515

If you are hosting your React application on IIS, just add a web.config file containing:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Custom" existingResponse="Replace">
            <remove statusCode="404" subStatusCode="-1" />
            <error statusCode="404" path="/" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

This will tell the IIS server to return the main page to the client instead of a 404 error and there isn't any need to use the hash history.

Upvotes: 42

neeraj-dixit27
neeraj-dixit27

Reputation: 2892

If you are using Express.js or some other framework in the backend, you can add the similar configuration as below and check out the Webpack public path in the configuration. It should work fine even on reload if you are using BrowserRouter.

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});

Upvotes: 7

praveenkumar s
praveenkumar s

Reputation: 325

It’s pretty simple when you got cannot get a 403 error after refreshing a DOM component.

Just add this one line in your Webpack configuration, 'historyApiFallback: true '. This saved my whole day.

Upvotes: -2

th3morg
th3morg

Reputation: 4799

If you're hosting a React app via AWS Static S3 Hosting and CloudFront

This problem presented itself by CloudFront responding with a 403 Access Denied message, because it expected /some/other/path to exist in my S3 folder, but that path only exists internally in React's routing with React Router.

The solution was to set up a distribution Error Pages rule. Go to the CloudFront settings and choose your distribution. Next, go to the "Error Pages" tab. Click "Create Custom Error Response" and add an entry for 403 since that's the error status code we get.

Set the Response Page Path to /index.html and the status code to 200.

The end result astonishes me with its simplicity. The index page is served, but the URL is preserved in the browser, so once the React application loads, it detects the URL path and navigates to the desired route.

Error Pages 403 Rule

Upvotes: 38

Aidin
Aidin

Reputation: 1290

I used Create React App to make a website just now and had the same issue presented here.

I use BrowserRouting from the react-router-dom package. I am running on a Nginx server and adding the following to /etc/nginx/yourconfig.conf solved it for me:

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

Which corresponds to adding the following to the .htaccess in case you are running Apache:

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

This also seems to be the solution suggested by Facebook themselves and can be found here.

Upvotes: 90

Isaac Pak
Isaac Pak

Reputation: 4971

Production stack: React, React Router v4, BrowswerRouter, Express.js, Nginx

  1. User BrowserRouter for pretty URLs

    File app.js

     import { BrowserRouter as Router } from 'react-router-dom'
    
     const App = () {
       render() {
         return (
             <Router>
                // Your routes here
             </Router>
         )
       }
     }
    
  2. Add index.html to all unknown requests by using /*

    File server.js

     app.get('/*', function(req, res) {
       res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
         if (err) {
           res.status(500).send(err)
         }
       })
     })
    
  3. bundle Webpack with webpack -p

  4. run nodemon server.js or node server.js

You may want to let nginx handle this in the server block and disregard step 2:

location / {
    try_files $uri /index.html;
}

Upvotes: 18

user1847
user1847

Reputation: 3829

If you are using Create React App:

There's a great walkthrough of this issue with solutions for many major hosting platforms that you can find here on the Create React App page. For example, I use React Router v4 and Netlify for my frontend code. All it took was adding one file to my public folder ("_redirects") and one line of code in that file:

/*  /index.html  200

Now my website properly renders paths like mysite.com/pricing when entered into the browser or when someone hits refresh.

Upvotes: 45

J. Parrish
J. Parrish

Reputation: 36

I had the same problem and this solution worked for us...

Background:

We are hosting multiple applications on the same server. When we would refresh the server, it would not understand where to look for our index in the destination folder for that particular application. The above link will take you to what worked for us...

We are using:

File package.json:

"dependencies": {
  "babel-polyfill": "^6.23.0",
  "ejs": "^2.5.6",
  "express": "^4.15.2",
  "prop-types": "^15.5.6",
  "react": "^15.5.4",
  "react-dom": "^15.5.4",
  "react-redux": "^5.0.4",
  "react-router": "^3.0.2",
  "react-router-redux": "^4.0.8",
  "redux": "^3.6.0",
  "redux-persist": "^4.6.0",
  "redux-thunk": "^2.2.0",
  "webpack": "^2.4.1"
}

My webpack.config.js file:

/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/views/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    'babel-polyfill', './app/index.js'
  ],
  output: {
    path: __dirname + '/dist/your_app_name_here',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      query : {
          presets : ["env", "react", "stage-1"]
      },
      exclude: /node_modules/
    }]
  },
  plugins: [HTMLWebpackPluginConfig]
}

My index.js file:

import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import { Provider } from 'react-redux'
import { createHistory } from 'history'
import { useRouterHistory } from 'react-router'
import configureStore from './store/configureStore'
import { syncHistoryWithStore } from 'react-router-redux'
import { persistStore } from 'redux-persist'

const store = configureStore();

const browserHistory = useRouterHistory(createHistory) ({
  basename: '/your_app_name_here'
})
const history = syncHistoryWithStore(browserHistory, store)

persistStore(store, {blacklist: ['routing']}, () => {
  console.log('rehydration complete')
})
// persistStore(store).purge()

ReactDOM.render(
    <Provider store={store}>
      <div>
        <Routes history={history} />
      </div>
    </Provider>,
  document.getElementById('mount')
)

My app.js file:

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

app.get('/*', function (req, res) {
    res.render('index');
});

app.listen(8081, function () {
  console.log('MD listening on port 8081!');
});

Upvotes: 0

Paul Whipp
Paul Whipp

Reputation: 16541

I'm not using server-side rendering yet, but I hit the same problem as the OP where Link seemed to work fine most of the time, but failed when I had a parameter. I'll document my solution here to see if it helps anyone.

My main JSX content contains this:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

This works fine for the first matching link, but when the :id changes in <Link> expressions nested on that model's detail page, the URL changes in the browser bar, but the content of the page did not initially change to reflect the linked model.

The trouble was that I had used the props.params.id to set the model in componentDidMount. The component is just mounted once, so this means that the first model is the one that sticks on the page and the subsequent Links change the props, but leave the page looking unchanged.

Setting the model in the component state in both componentDidMount and in componentWillReceiveProps (where it is based on the next props) solves the problem and the page content changes to reflect the desired model.

Upvotes: 3

sree
sree

Reputation: 3193

The Webpack Dev Server has an option to enable this. Open up package.json and add --history-api-fallback. This solution worked for me.

react-router-tutorial

Upvotes: 18

jmancherje
jmancherje

Reputation: 6633

The answers here are all extremely helpful. Configuring my Webpack server to expect the routes worked for me.

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

The historyApiFallback is what fixed this issue for me. Now routing works correctly and I can refresh the page or type in the URL directly. There isn't any need to worry about workarounds on your Node.js server. This answer obviously only works if you're using Webpack.

See my answer to React-router 2.0 browserHistory doesn't work when refreshing for a more detailed reason why this is necessary.

Upvotes: 205

Joshua Dyck
Joshua Dyck

Reputation: 2173

If you're using Firebase, all you have to do is make sure you've got a rewrites property in your firebase.json file in the root of your app (in the hosting section).

For example:

{
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]
  }
}

Further reading on the subject:

Upvotes: 11

danieltan95
danieltan95

Reputation: 860

The previous answers don't solve the problem where you want to use your browser router with proxy pass, and where you can't use root.

For me the solution is pretty simple.

Say you have a URL that's pointing to some port.

location / {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
  port_in_redirect    off;
}

And now because of the browser router, sub paths are broken. However, you know what the sub paths are.

What is the solution to this? For sub path /contact

# Just copy paste.
location /contact/ {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
}

Nothing else I've tried works, but this simple fix works.

Upvotes: 0

Related Questions