Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need a proxy on an express.js server in order to get webpack hot reloading server functionality combined with react-routing

Optional info: I'm trying to make this project built with marty.js and webpack dev server allow entry points from react-router so that it works in more than just the \ path.

Thus, I'm studying THIS stack overflow answer all day long and I fail to understand the logic behind the following code and why this answer works.

retozi answered:

I set up a proxy to achieve this:

You have a regular express webserver that serves the index.html on any > route, except if its an asset route. if it is an asset, the request gets proxied to the web-dev-server

your react hot entrypoints will still point directly at the webpack dev server, so hot reloading still works.

Let's assume you run webpack-dev-server on 8081 and your proxy at 8080.

My code looks like this now, but in order to make it work I will later on need to implement marty-express. In order to implement that I must first understand retonzis answer.

express.js file

requirements

    'use strict';
    var express = require('express');
    var path = require('path');
    var logger = require('morgan');
    var bodyParser = require('body-parser');
    var config = require('../config.json');
    var webpack = require('webpack');
    var WebpackDevServer = require('webpack-dev-server');
    var proxy = require('proxy-middleware');
    var url = require('url');

proxy

    var app = express(); //our express instance

    // -------- my proxy----------------------


    app.use('/assets', proxy(url.parse('http://localhost:8081/assets')));//but why do we need a proxy? This line really confuses me.

marty-express **

I plan to use that right after I understand this example, I just HOPE it passes react-routes into express.**

    //app.use(require('marty-express')({
    //    routes: require('../routes'),
    //    application: require('../application').Application
    //}));

express stuff

    app.get('/*', function(req, res) {
        res.sendFile(__dirname + '/index.html');
    });//if I got this straight this line just tells express to server my index.html file to all routes. My guess is this will be removed when I implement [marty-express][4].

the 2 servers webpack-dev-server and express

        //----- my-webpack-dev-server------------------
    var webpackServer = new WebpackDevServer(webpack(require('../../webpack.config')), {
        contentBase: __dirname,
        hot: true,
        quiet: false,
        noInfo: false,
        publicPath: '/assets/',
        stats: { colors: true }
    });

    //run webpack hot reload server on port 8081
    webpackServer.listen(8081, 'localhost', function() {});

    //run express server on port 8080
    app.listen(8080);

Could someone be kind enough to explain to me this consept like I came down from planet Mars yesterday?

I fail to understand 2 things:

  1. Why we need a proxy
  2. How to pass react-routes into express so that it serves them on each route when asked. (pehaps marty-express helps us with that task, but my guess is we could do that manually without it)

Bah... Help me get out of this Documentation scarcity HELL!!! and please be generous in your answer.. Remember, I just came from Mars yesterday.

Thank you..!

like image 565
SudoPlz Avatar asked Sep 28 '22 11:09

SudoPlz


1 Answers

You don't, but it's tricky. So the first requirement is that you have a configurable asset root. This also pays off if you need a CDN in the future. Let's say this is in an envvar ASSET_URL which is available both when running your webpack dev server and your express server.

You need the usual webpack dev server, plus the CORS header. This lets your main express server just point to the webpack dev server in the script/link tags.

ASSET_URL is like: http://localhost:8081

Webpack

var config = require('./webpack.config');

var port = '8081', hostname = 'localhost';

if (process.env.ASSETS_URL) {
    var assetUrlParts = url.parse(process.env.ASSETS_URL);
    port = assetUrlParts.port;
    hostname = assetUrlParts.hostname;
}

new WebpackDevServer(webpack(serverConfig), {
  publicPath: serverConfig.output.publicPath,
  hot: true,
  headers: { "Access-Control-Allow-Origin": "*" }
}).listen(port, 'localhost', function (err, result) {
  if (err) {
    console.log(err);
    process.exit(1);
  }

  console.log('Listening at ' + url.format({port: port, hostname: hostname, protocol: 'http:'}));
});

Then in your webpack config file you have most of the same junk.

var port = '8081', hostname = 'localhost';

if (process.env.ASSETS_URL) {
    var assetUrlParts = url.parse(process.env.ASSETS_URL);
    port = assetUrlParts.port;
    hostname = assetUrlParts.hostname;
}

...

  entry: [
    'webpack-dev-server/client?' + url.format({port: port, hostname: hostname, protocol: 'http:'}),
    'webpack/hot/only-dev-server',
    ...

  output: {
    path: __dirname + '/public/',
    filename: 'bundle.js',
    publicPath: process.env.ASSETS_URL || '/public/'

Express Server

The only special thing here is you need to somehow get process.env.ASSETS_URL into the locals of your templates.

<head>
    <link rel="stylesheet" href="{{ assetsUrl }}/main.css">
</head>
<body>
    ...
    <script type="text/javascript" src="{{ assetsUrl }}/bundle.js"></script
</body>
like image 106
Brigand Avatar answered Oct 02 '22 15:10

Brigand