0

I'm working on a create-react-app (v2.1.8 at time of writing, shipping with react-router-dom v4.3.1) web application, and I need help understanding why it works the way it does.

My initial problem relates to the app being served by AWS S3, and is addressed by SO questions react router doesn't work in aws s3 bucket and React-router urls don't work when refreshing or writing manually:

  1. My browser got 404s in my app, when trying to fetch server-side routes. This was solved by specifying pointing S3 error.html to my app's index.html...
  2. ...but it solved the problem only halfway, as asking for /whatever/subresource to S3 will indeed return the index.html (thanks to 1. above) but will cause S3 to return a 403. My app being behind CloudFlare, I worked around following CloudFlare hack Override response status code from 404 to 200 for S3 SPA . Basically the CloudFlare worker intercepts requests, and if the requested URL matches CRA_APP_ROUTES = ['/route-a', '/route-b', '...'], I return the response (which is index.html because of S3 config described in 1.), but with a 200 response.

Here's my question:

  • I get that CRA uses React Router's browserHistory (which behind the scenes uses the HTML5 pushState history API) to get nice-looking URLs in the Single-Page App, without #/....
  • I get that the pushState history API will modify the history / URL without doing any navigation. As documented by MDN / Adding and modifying history,

    Suppose http://mozilla.org/foo.html executes the following JavaScript:

    var stateObj = { foo: "bar" };
    history.pushState(stateObj, "page 2", "bar.html");
    

    This will cause the URL bar to display http://mozilla.org/bar.html, but won't cause the browser to load bar.html or even check that bar.html exists.

  • And I get that the app "works" when served by a properly-configured Express serving index.html for any unknown paths. As documented by Serving Apps with Client-Side Routing,

    The server needs to be configured to respond to a request to /todos/42 by serving index.html. For example, we can amend our Express example above to serve index.html for any unknown paths:

     app.use(express.static(path.join(__dirname, 'build')));
    
    -app.get('/', function (req, res) {
    +app.get('/*', function (req, res) {
       res.sendFile(path.join(__dirname, 'build', 'index.html'));
     });
    
  • I get that things then work because React Router recognizes the route it's at, and renders things appropriately.

But why in the first place make the network request at all? Why fetch resources that all land to index.html & associated JS, which my browser already has?! Can a CRA be configured to A. get nice browserHistory routing, and B. be fully client-side and not make network requests when performing client-side routing & re-rendering? (Which is wasteful since S3 isn't doing any Server-Side Rendering, and will return data the client already has). Am I missing anything?

Thanks.

Ronan Jouchet
  • 1,303
  • 1
  • 15
  • 28

1 Answers1

0

You will need service worker.

Service worker can provide your app offline support, but the users will have to visit your site once in order to install the service worker.

The create-react-app comes with a default service worker called workbox turned off.

Joseph
  • 3,974
  • 7
  • 34
  • 67
  • Hmmm thanks, but Service Workers feel orthogonal to my concern. I don't need my app to have any kind of offline support, as it depends strongly on the network for backend calls pretty much all the time. Investing time into setting up Service Workers feels (in this case) useless work solving a problem I don't have and adding complexity (caching strategy, etc). I only want to avoid network calls on client-side routing. – Ronan Jouchet Mar 09 '19 at 20:54