2

I have a React app that is being served by a simple Express server. The React app is being webpack'd into a directory called dist in my root directory (where the server.js file is located as well). The dist folder includes the index.html entry point, main.min.js JavaScript bundle, and all other static assets (css, images, etc).

If I visit the root directory of the site, localhost:3000/ for example, the index.html gets served, it loads the JS bundle and finds all other assets fine. The app, using react-router, navigates fine through button clicks and a link that brings me to localhost:3000/feature works fine.

However, if I manually go into the address bar and type in localhost:3000/feature, the server gives the index.html as expected, but also serves index.html in place of main.min.js. This is because the wildcard route in the express server is mapped to return index.html. This is how I've seen it done in some articles, but I'm not sure if this case has been considered.

Here's a snippet of the relevant server code:

app.use(express.static(path.join(__dirname)));
app.get('*', function response(req, res) {
    res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});

This is what defines the server routing. Is there a better way to do this that will allow manual address changes?

Here's my file structure if it helps:

|-root
  |-server.js
  |-webpack.config.js
  |-dist/
    |-main.min.js
    |-index.html
    |-a2cea76fae187add3c974dcacf446eab.jpg
    |-...etc

Contents of index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div id="root"><!-- React app --></div>
    <script src="dist/main-631cea2c7e308b1dfb26.min.js"></script>
</body>
</html>
Alan Thomas
  • 1,006
  • 2
  • 14
  • 31
  • probably you need [this](https://github.com/ReactTraining/react-router/blob/master/docs/guides/ServerRendering.md) – devellopah Jan 11 '17 at 21:33
  • @IslamIbakaev is this the only solution? I'd like to avoid server-side rendering (for now) if I can. – Alan Thomas Jan 11 '17 at 21:45
  • i don't know other solutions where i want express match routes i set with react-router without actually doing "server-side react" – devellopah Jan 11 '17 at 21:57
  • but if there is other solution it would be very strange that i even have not heard about it... – devellopah Jan 11 '17 at 21:58
  • Can you add the content of `index.html`? The inconsistency serving the minified js file is a bit weird. – Vier Jan 11 '17 at 22:04
  • @Vier added. The name of the bundle file gets injected during webpack build by HtmlWebpackPlugin. – Alan Thomas Jan 11 '17 at 22:12

1 Answers1

2

It's because you're referencing your script using a relative path.

For example when on http://localhost:3000/feature the browser will resolve the script to http://localhost:3000/feature/dist/main-631cea2c7e308b1dfb26.min.js which of course doesn't exist, hence the express.static middleware is letting the request fall through to the next middleware.

You therefore need to define it as a root relative path, e.g.

<script src="/dist/main-631cea2c7e308b1dfb26.min.js"></script>
Community
  • 1
  • 1
Richard Scarrott
  • 6,638
  • 1
  • 35
  • 46
  • 1
    @Alan Thomas -- Additionally you probably should avoid serving `__dirname` with `express.static` otherwise the server code and webpack config will be accessible from a browser -- you might be better off serving `path.join(__dirname, 'dist')` and changing your script reference to just `/main-631cea2c7e308b1dfb26.min.js`. – Richard Scarrott Jan 11 '17 at 22:34
  • Relative path is the issue. If you're using webpack, you can use the HtmlWebpackPlugin to inject the chunk script tag into you html file. This will set the explicit path by default `plugins: [ new HtmlWebpackPlugin({ template: 'views/index.html', inject: 'body', filename: 'index.html' }) ]` – bsyk Jan 12 '17 at 06:59
  • @riscarrott Referencing the script using a relative path seems to work though. I've made a basic app to test this. https://react-express-alanqthomas.c9users.io/. Source: https://ide.c9.io/alanqthomas/react-express. This is using relative pathing and works as intended. – Alan Thomas Jan 15 '17 at 05:00
  • @riscarrott might have to login and run it yourself - it should be public. I think the VM spins down after a few minutes of inactivity. – Alan Thomas Jan 17 '17 at 16:37