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>
6
  • probably you need this Commented Jan 11, 2017 at 21:33
  • @IslamIbakaev is this the only solution? I'd like to avoid server-side rendering (for now) if I can. Commented Jan 11, 2017 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" Commented Jan 11, 2017 at 21:57
  • but if there is other solution it would be very strange that i even have not heard about it... Commented Jan 11, 2017 at 21:58
  • Can you add the content of index.html? The inconsistency serving the minified js file is a bit weird. Commented Jan 11, 2017 at 22:04

1 Answer 1

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>
Sign up to request clarification or add additional context in comments.

4 Comments

@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.
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' }) ]
@riscarrott Referencing the script using a relative path seems to work though. I've made a basic app to test this. react-express-alanqthomas.c9users.io. Source: ide.c9.io/alanqthomas/react-express. This is using relative pathing and works as intended.
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.