1

I was using a simple script before to start a React app but I need to reload, rebuild, and restart everything manually this way which is tedious. Now I am trying to set up webpack-dev-server to do that for me. Somehow just starting the webpack-dev-server by ./node_modules/.bin/webpack-dev-server --inline --hot is just serving files statically from the topmost folder instead of launching the app. Previously I used the following script to start the app (it is working good):

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('nodetest1:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);

The webpack.config.js looks the following way:

var path = require('path');

module.exports = {
  entry: {
    app: ['babel-polyfill', './views/index.js']
    //vendor: ["react","react-dom"]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './public')
  },
  devtool: "#eval-source-map",
  module: {
       rules: [{
           test: /\.jsx?$/,
           exclude: /node_modules/,
           use: {
               loader: 'babel-loader?cacheDirectory=true',
           }
       },
       {
         test: /\.css$/,
         loader: "style-loader!css-loader"
        },
        {
        test: /\.(jpe?g|gif|png|svg)$/i,
        use: [
        {
          loader: 'url-loader',
          options: {
            limit: 10000
          }
        }
      ]
        }]
  },
  node: {
    fs: 'empty'
  },
  resolve: {
    extensions: ['.js', '.jsx']
  },
      externals: {
        fs: '{}',
        tls: '{}',
        net: '{}',
        dns: '{}',
        readline: '{}'
      }
};

Upon starting the app with the ./node_modules/.bin/webpack-dev-server --inline --hot I see the following output:

enter image description here

Any suggestions would be greatly appreciated.

Update

I changed name of the file which is an entry point from app.html to index.html in the public folder and also changed the command to start the app to ./node_modules/.bin/webpack-dev-server --content-base public --inline --hot and the app started but the requests to the node server result in 404 errors, the server is not processing requests somehow. I guess that can be because app.js script was not run and so all the middleware was not set up, but I am not sure how to pre-run it or package into the bundle.js. I have two layers though: app.js runs and presents the login page and then redirects to the actual app if the login is successful (it is not needed for the development of course).

Update

I tried using nodemon: How to auto-reload files in Node.js?

By doing the following: nodemon ./bin/www where www is the server script. It is not watching for my changes at all. When I change some of .jsx files, no reloading happens.

Update

I tried to change the entry point in webpack.config.js from:

entry: {
    app: ['babel-polyfill', './views/index.js']
    //vendor: ["react","react-dom"]
  },

to:

entry: {
    app: ['babel-polyfill', './app.js']
    //vendor: ["react","react-dom"]
  },

But in this case when building the app it is giving me the error:

enter image description here

Following the advice here: https://github.com/webpack/webpack/issues/2142

I set target: node in the webpack.config.js. It started giving me another error:

enter image description here

I found the following solution: https://github.com/babel/babel/issues/5268

But after running npm install --save babel-standalone the error remained.

Update

I was able to fix the error by adding .json to the extensions: https://github.com/discordjs/discord.js/issues/2656

Now webpack compiled the project successfully and without any errors, however, when I started it with ./node_modules/.bin/webpack-dev-server --content-base public --inline --hot in the browsers' console I see the error: Uncaught ReferenceError: require is not defined and nothing loads.

Update

I was trying to follow: https://hackernoon.com/full-stack-web-application-using-react-node-js-express-and-webpack-97dbd5b9d708

And it is running fine but when I change the React files, the app is not reloaded. Also babel set ups there messed up my project completely, so I can not build the project now.

Nikita Vlasenko
  • 4,004
  • 7
  • 47
  • 87
  • Help to understand please, previously you had a script that started a node.js server. But what was that `../app.js` that you used? How did you serve react.js app? How was it prebuilt? Also, what do you mean by 'webpack-dev-server is just serving files statically from the topmost folder instead of launching the app.'? DevServer builds the client app and serves the generated static files at the specified (or default `8080`) port. So what do you mean by 'launching the app' and what exactly are you trying to achieve with devServer? – GProst Mar 25 '19 at 23:04
  • app.js is `required` in the server `./bin/www`. The latter starts the server with `http.createServer(app)`. By `webpack-dev-server is just serving files statically from the topmost folder instead of launching the app.` I mean that I see root folder file structure and the app is not started. The main goal is to reload the app when I change files, so that not to do manual rebuild and launch. – Nikita Vlasenko Mar 25 '19 at 23:08
  • ah, I think now I got what you meant, thanks – GProst Mar 25 '19 at 23:10
  • `I have two layers though` - how did you recompile the bundle previously? Manually ran `webpack` command? Just trying to get the full picture – GProst Mar 25 '19 at 23:19
  • Yep, First I run `npm run webpack`, then `node ./bin/www` – Nikita Vlasenko Mar 25 '19 at 23:32

1 Answers1

4
  1. Somehow just starting the webpack-dev-server by ./node_modules/.bin/webpack-dev-server --inline --hot is just serving files statically from the topmost folder instead of launching the app.

    As you guessed correctly this was due to you had app.html instead of index.html and devServer didn't know which file to load by default. You can solve it as you did by renaming the file or you can set the following option in webpack.config.js: devServer: {index: 'app.html'} - see this for details. But I'd personally rename it as you did.

  2. the app started but the requests to the node server result in 404 errors

    This could be for 2 reasons. First, your server wasn't up, you had to start it as you started it before (node ./bin/www) since devServer just serves static client assets and it doesn't have any of your server logic. Second, even after you start it you will probably have 404 errors as well. This depends on how you specified URLs. If you specified them as an absolute path (like http://localhost:3000/my-endpoint/path) then they should hit your main server normally but if you specified them as a relative path (/my-endpoint/path) then they will be sent to http://localhost:8080/my-endpoint/path (i.e. devServer host/port instead of your main server). To solve this you can specify proxy settings in your webpack.config:

    devServer: {
      proxy: [{
        context: ['/my-endpoint'], // endpoints which you want to proxy
        target: 'http://localhost:3000' // your main server address
      }]
    }
    

    See this for details.

Well, other errors you had because you started to bundle your sever (target: node) instead of your client app as you correctly started to do at first. When you successfully bundled your server app of course you couldn't open it in a browser, since it is Node.js code (browser doesn't have require method for example, hence the error)

EDIT:

Missed a comment about --content-base public. Yes, you also have to specify the folder that you want devServer to serve if you have some prebuilt assets like app.html of yours. Another option is to use html-webpack-plugin which will generate index.html dynamically by webpack so devServer knows where to take it from (from the memory where devServer keeps all generated assets).

GProst
  • 9,229
  • 3
  • 25
  • 47
  • I set it up, it is running without any issues shown in the console/node terminal but the React app is not reloading when I modify files – Nikita Vlasenko Mar 26 '19 at 00:40
  • I tried it with `nodemon` and just with `node` and neither of them work – Nikita Vlasenko Mar 26 '19 at 00:49
  • 1
    If you run `nodemon ./bin/www` it will watch your server files, not client, so it won't rebuild the bundle. So devServer compiled files successfully? Can you see in that webpack-dev-server rebuilds files when they're changed in the termincal? Are you sure you open the app at the devServer URL and not your main server? I mean if you have your main server running for instance on `localhost:3000` and devServer is running on `localhost:8080` then the app will reload only if you open the latest url. – GProst Mar 26 '19 at 01:07
  • 1
    ah... damn... you use `--hot` and this is hot module replacement. Sorry, didn't pay attention. So there won't be page reloads. Try removing `--hot` option. Actually hot module replacement even nicer than page reload, but more tricky. It will update the client code even without the page reload. But you should read about it first, how to configure etc, probably will require some additional configs, hard to say. But yeah `react-hot-loader` is what you should use in this case with react – GProst Mar 26 '19 at 01:12
  • 1
    Ok, fixed it! The issue was that I did not follow your advice, but left `devServer` configuration from the link: https://hackernoon.com/full-stack-web-application-using-react-node-js-express-and-webpack-97dbd5b9d708. Thank a lot! – Nikita Vlasenko Mar 26 '19 at 01:16