60frames / webpack-hot-server-middleware

:fire: Hot reload webpack bundles on the server
MIT License
324 stars 50 forks source link

listen EADDRINUSE: address already in use :::8080 #123

Open BillySwaggyKidy opened 2 years ago

BillySwaggyKidy commented 2 years ago

Capture Hello, I am working on an Isomorphic Web App on webpack 5 and your module is just the thing I need to enable HMR on the backend. I am running node on the bundle-server.js after the build However when I tried your example and add some parameters, I got this error:

Error: listen EADDRINUSE: address already in use :::8080 at Server.setupListenHandle [as _listen2] (node:net:1372:16) at listenInCluster (node:net:1420:12) at Server.listen (node:net:1508:7) at Function.listen (C:\Dev\isomorphic-react-redux-router-app\node_modules\express\lib\application.js:635:24) at eval (webpack://isomorphic-react-redux-router-app/./app/serverside/server.js?:89:8) at Object../app/serverside/server.js (C:\Dev\isomorphic-react-redux-router-app\build\dev\server\build\dev\server\bundle-server.js:51:1) at __webpack_require__ (C:\Dev\isomorphic-react-redux-router-app\build\dev\server\build\dev\server\bundle-server.js:327:41) at C:\Dev\isomorphic-react-redux-router-app\build\dev\server\build\dev\server\bundle-server.js:392:37 at Object. (C:\Dev\isomorphic-react-redux-router-app\build\dev\server\build\dev\server\bundle-server.js:395:12) at Module._compile (node:internal/modules/cjs/loader:1105:14)

Here are my code (server.js):

const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackHotServerMiddleware = require('webpack-hot-server-middleware');

const config = require('../../webpack.conf.dev.js');
const compiler = webpack(config);
server.use(webpackDevMiddleware(compiler, {
    serverSideRender: true,
}));
server.use(webpackHotMiddleware(compiler.compilers.find(compiler => compiler.name === 'client')));
server.use(webpackHotMiddleware(compiler.compilers.find(compiler => compiler.name === 'client')));
server.use(webpackHotServerMiddleware(compiler,{
    serverRendererOptions: {
        foo: 'Bar'
    },
    chunkName: 'bundle-server'
}));

My dev webpack config (webpack.conf.dev.js:

// this file contains 2 webpack configurations for the development mode, one for the client and one for the server
const path = require('path');
require("core-js/stable");
require("regenerator-runtime/runtime");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const nodeExternals = require('webpack-node-externals');
let webpack = require('webpack');

module.exports = [ 
  {
    name: 'client',
    mode: 'development', // we set this configuration for the developpement
    devtool: 'inline-source-map',
    stats: {warnings:false},
    target:'web',
    entry: {
      // we take the following file:
      // - core-js a Modular standard library for JavaScript
      // - regenerator-runtime/runtime a Standalone runtime for Regenerator-compiled generator and async functions.
      // - and the client.jsx file for the clientside of the app
      // to a js file bundle-app
      'bundle-app': ['webpack-hot-middleware/client?reload=true','core-js','regenerator-runtime/runtime','./app/clientside/client.jsx']
    },
    output: {
      path: path.join(__dirname, '/build/dev'), // we put the bundle-app file to the dev folder of the build folder of the project
      filename: '[name].js', // each output file will have the js extension so does the bundle-app file
      publicPath: '/',
    },
    plugins: [
      // we use HtmlWebpackPlugin to generate and index.html based on the index.html from the html folder, into the server folder
      // we also for developpement don't want to minify the html
      // it will also include the bundle-app.js <script> to the head
      new HtmlWebpackPlugin({
        filename: 'server/index.html',
        template: 'app/html/index.html',
        minify: false
      }),
      new webpack.HotModuleReplacementPlugin()
    ],
    module: {
      rules: [
      {
        // for every jpg, png, svg, jpg,jpeg, gif file we will pull those into the app by using the seet/ressource build-in feature by webpack5
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        // for every type of fonts extension, we will pull those into the app by using the seet/ressource build-in feature by webpack5
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        // for every css file on developpement mode we will use the css-loader to convert the css to js and the style-loader to inject them in the dom of the app
        test: /\.css$/i,
        exclude: /node_modules/,
        use: ["style-loader","css-loader"],
      },
      {
        // every js and jsx (React extension) files, will be load by a babel-loader witch his paramters are stated in the .babelrc file
        test: /\.(jsx|js)$/,
        include: path.resolve(__dirname, '/'),
        exclude: /node_modules/,
        use: [{
          loader: 'babel-loader',
        }]
      }
      ]
    },
  },
  {
    name: 'server',
    mode: 'development',
    target: 'node',
    dependencies: ['client'],
    stats: {warnings:false},
    // we exclude dependency from the node.js environnement to be present in the user's environnement
    externals: [nodeExternals()],
    entry: {
      // we take the following file:
      // - core-js a Modular standard library for JavaScript
      // - regenerator-runtime/runtime a Standalone runtime for Regenerator-compiled generator and async functions.
      // - and the server.js file for the serverside of the app
      // to a js file bundle-server in a server folder
        'bundle-server': ['core-js','regenerator-runtime/runtime','./app/serverside/server.js'],
    },
    output: {
      path: path.join(__dirname, '/build/dev/server'), // we put the bundle-server file to the dev folder of the build folder of the project
      filename: '[name].js', // each output file will have the js extension so does the bundle-app file
      publicPath: '/',
      libraryTarget: 'commonjs2',
    },
    module: {
        rules: [
          {
            // for every jpg, png, svg, jpg,jpeg, gif file we will pull those into the app by using the seet/ressource build-in feature by webpack5
            test: /\.(png|svg|jpg|jpeg|gif)$/i,
            type: 'asset/resource',
          },
          {
            // for every type of fonts extension, we will pull those into the app by using the seet/ressource build-in feature by webpack5
            test: /\.(woff|woff2|eot|ttf|otf)$/i,
            type: 'asset/resource',
          },
          {
            // every js and jsx (React extension) files, will be load by a babel-loader witch his paramters are stated in the .babelrc file
            test: /\.(jsx|js)$/,
            include: path.resolve(__dirname, '/'),
            exclude: /node_modules/,
            use: [{
              loader: 'babel-loader',
            }]
          }
        ]
    }
  }
]

I think it might be a problem with webpack-dev-middleware and webpack-hot-server-middleware conflict, there are in a loop. The script run and the server is starting and we run again the script to create another server but the port is already taken.

Please send some help, I have been stuck for days. Otherwise, your module is great!

komlevv commented 1 year ago

@BillySwaggyKidy webpack server compiler should handle just the file with serverRenderer(as entry), not the file running Express. Check out the examples folder

BillySwaggyKidy commented 1 year ago

But what if I want to implement some express routers on my backend? Your exemple explain the possibility to use a custom serverRenderer function to render the App component but don't seem to explain about the custom routes for express. I can only render a component but I cannot create a real custom express server that handle get and post request with your example.