IT story

webpack-dev-server가 반응 라우터의 진입 점을 허용하도록 허용하는 방법

hot-time 2020. 8. 3. 17:37
반응형

webpack-dev-server가 반응 라우터의 진입 점을 허용하도록 허용하는 방법


반응 라우터와 함께 개발에서 webpack-dev-server를 사용하는 앱을 만들고 있습니다.

webpack-dev-server는 한 곳에서 공개 엔트리 포인트를 가질 것이라는 가정하에 (예 : "/"), 반응 라우터는 무제한의 엔트리 포인트를 허용한다고 가정합니다.

webpack-dev-server의 이점, 특히 생산성을 높이는 핫 리로딩 기능의 이점을 원하지만 여전히 반응 라우터에 설정된 경로를로드 할 수 있기를 원합니다.

함께 작동하도록 어떻게 구현할 수 있습니까? 이를 허용하는 방식으로 webpack-dev-server 앞에서 Express 서버를 실행할 수 있습니까?


이것을 달성하기 위해 프록시를 설정했습니다.

자산 경로를 제외한 모든 경로에서 index.html을 제공하는 일반 고속 웹 서버가 있습니다. 자산 인 경우 요청은 web-dev-server로 프록시됩니다.

반응 핫 엔트리 포인트는 여전히 웹팩 개발 서버를 직접 가리 키므로 핫 리로딩은 여전히 ​​작동합니다.

8081에서 webpack-dev-server를, 8080에서 프록시를 실행한다고 가정 해 봅시다. server.js 파일은 다음과 같습니다.

"use strict";
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./make-webpack-config')('dev');

var express = require('express');
var proxy = require('proxy-middleware');
var url = require('url');

## --------your proxy----------------------
var app = express();
## proxy the request for static assets
app.use('/assets', proxy(url.parse('http://localhost:8081/assets')));

app.get('/*', function(req, res) {
    res.sendFile(__dirname + '/index.html');
});


# -----your-webpack-dev-server------------------
var server = new WebpackDevServer(webpack(config), {
    contentBase: __dirname,
    hot: true,
    quiet: false,
    noInfo: false,
    publicPath: "/assets/",

    stats: { colors: true }
});

## run the two servers
server.listen(8081, "localhost", function() {});
app.listen(8080);

이제 webpack 설정에서 진입 점을 다음과 같이 만드십시오.

 entry: [
     './src/main.js',
     'webpack/hot/dev-server',
     'webpack-dev-server/client?http://localhost:8081'
 ]

핫 리로드를 위해 8081로 직접 전화하십시오.

또한 output.publicPath옵션에 절대 URL을 전달해야합니다 .

 output: {
     publicPath: "http://localhost:8081/assets/",
     // ...
 }

당신은 설정해야합니다 historyApiFallbackWebpackDevServer일이 마찬가지한다. 다음은 작은 예입니다 (목적에 맞게 조정).

var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');

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


var port = 4000;
var ip = '0.0.0.0';
new WebpackDevServer(webpack(config), {
    publicPath: config.output.publicPath,
    historyApiFallback: true,
}).listen(port, ip, function (err) {
    if(err) {
        return console.log(err);
    }

    console.log('Listening at ' + ip + ':' + port);
});

For anyone else that may still be looking for this answer. I put together a simple proxy bypass which achieves this without much hassle and the config goes into the webpack.config.js

I am sure there are much more elegant ways to test for local content using regex, but this works for my needs.

devServer: {
  proxy: { 
    '/**': {  //catch all requests
      target: '/index.html',  //default target
      secure: false,
      bypass: function(req, res, opt){
        //your custom code to check for any exceptions
        //console.log('bypass check', {req: req, res:res, opt: opt});
        if(req.path.indexOf('/img/') !== -1 || req.path.indexOf('/public/') !== -1){
          return '/'
        }

        if (req.headers.accept.indexOf('html') !== -1) {
          return '/index.html';
        }
      }
    }
  }
} 

If you're running webpack-dev-server using CLI, you can configure it through webpack.config.js passing devServer object:

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js"
  },
  devServer: {
    historyApiFallback: true
  }
}

This will redirect to index.html everytime it 404 is encountered.

NOTE: If you're using publicPath, you'll need to pass it to devServer too:

module.exports = {
  entry: "index.js",
  output: {
    filename: "bundle.js",
    publicPath: "admin/dashboard"
  },
  devServer: {
    historyApiFallback: {
      index: "admin/dashboard"
    }
  }
}

You can verify that everything is setup correctly by looking at the first few lines of the output (the part with "404s will fallback to: path").

enter image description here


For a more recent answer, the current version of webpack (4.1.1) you can just set this in your webpack.config.js like such:

const webpack = require('webpack');

module.exports = {
    entry: [
      'react-hot-loader/patch',
      './src/index.js'
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ['style-loader','css-loader']
            }
        ]
    },
    resolve: {
      extensions: ['*', '.js', '.jsx']  
    },
    output: {
      path: __dirname + '/dist',
      publicPath: '/',
      filename: 'bundle.js'
    },
    plugins: [
      new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
      contentBase: './dist',
      hot: true,
      historyApiFallback: true
    }
  };

The important part is historyApiFallback: true. No need to run a custom server, just use the cli:

"scripts": {
    "start": "webpack-dev-server --config ./webpack.config.js --mode development"
  },

I'd like to add to the answer for the case when you run an isomorphic app (i.e. rendering React component server-side.)

In this case you probably also want to automatically reload the server when you change one of your React components. You do this with the piping package. All you have to do is install it and add require("piping")({hook: true}) somewhere in the beginning of you server.js. That's it. The server will restart after you change any component used by it.

This rises another problem though - if you run webpack server from the same process as your express server (as in the accepted answer above), the webpack server will also restart and will recompile your bundle every time. To avoid this you should run your main server and webpack server in different processes so that piping would restart only your express server and won't touch webpack. You can do this with concurrently package. You can find an example of this in react-isomorphic-starterkit. In the package.json he has:

"scripts": {
    ...
    "watch": "node ./node_modules/concurrently/src/main.js --kill-others 'npm run watch-client' 'npm run start'"
  },

which runs both servers simultaneously but in separate processes.


historyApiFallback can also be an object instead of a Boolean, containing the routes.

historyApiFallback: navData && {
  rewrites: [
      { from: /route-1-regex/, to: 'route-1-example.html' }
  ]
}

May be not in all cases, but seems the publicPath: '/' option in the devServer is easiest solution to fix deep routes issue, see: https://github.com/ReactTraining/react-router/issues/676


This worked for me: just simply add the webpack middlewares first and the app.get('*'... index.html resolver later,

so express will first check if the request matches one of the routes provided by webpack (like: /dist/bundle.js or /__webpack_hmr_) and if not, then it will move to the index.html with the * resolver.

ie:

app.use(require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
}))
app.use(require('webpack-hot-middleware')(compiler))
app.get('*', function(req, res) {
  sendSomeHtml(res)
})

참고URL : https://stackoverflow.com/questions/26203725/how-to-allow-for-webpack-dev-server-to-allow-entry-points-from-react-router

반응형