Как разрешить webpack-dev-серверу разрешать точки входа от реактивного маршрутизатора

Я создаю приложение, которое использует webpack-dev-сервер в разработке вместе с реакционным маршрутизатором.

Похоже, что webpack-dev-сервер построен на основе предположения, что у вас будет открытая точка входа в одном месте (например, "/" ), тогда как "реактивный маршрутизатор" допускает неограниченное количество точек входа.

Я хочу использовать преимущества webpack-dev-сервера, особенно горячую перезагрузку, которая отлично подходит для производительности, но я все же хочу иметь возможность загружать маршруты, установленные в маршрутизаторе реакции.

Как можно реализовать его так, чтобы они работали вместе? Не могли бы вы запустить экспресс-сервер перед webpack-dev-сервером таким образом, чтобы это разрешить?

Ответ 1

Я установил прокси для этого:

У вас есть обычный экспресс-сервер, который обслуживает index.html на любом маршруте, за исключением того, что это маршрут ресурса. если это актив, запрос проксируется на веб-dev-сервере

ваши ответные горячие точки входа по-прежнему будут отображаться непосредственно на сервере webpack dev, поэтому горячая перезагрузка все равно работает.

Предположим, вы запустили webpack-dev-сервер на 8081 и ваш прокси-сервер на 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 для hotreload

также убедитесь, что вы передаете абсолютный URL-адрес опции output.publicPath:

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

Ответ 2

Вы должны установить historyApiFallback of WebpackDevServer как истинный для этого. Вот небольшой пример (настройка для ваших целей):

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);
});

Ответ 3

Для всех, кто еще может найти этот ответ. Я собрал простой прокси-прокси, который достигает этого без особых хлопот, и конфигурация переходит в файл webpack.config.js

Я уверен, что есть гораздо более элегантные способы тестирования локального контента с использованием регулярного выражения, но это работает для моих нужд.

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';
        }
      }
    }
  }
} 

Ответ 4

Если вы используете webpack-dev-сервер с использованием CLI, вы можете настроить его через webpack.config.js, передавая объект devServer:

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

Ответ 5

Я хотел бы добавить ответ на случай, когда вы запускаете изоморфное приложение (т.е. рендеринг на стороне сервера).

В этом случае вы, вероятно, также захотите автоматически перезагрузить сервер при изменении одной из ваших компонентов React. Вы делаете это с помощью пакета piping. Все, что вам нужно сделать, это установить его и добавить require("piping")({hook: true}) где-то в начале сервера server.js. Это. Сервер будет перезагружен после изменения любого используемого им компонента.

Это еще одна проблема: если вы запустите сервер webpack из того же процесса, что и ваш экспресс-сервер (как в принятом ответе выше), сервер webpack также перезагрузится и будет перекомпилировать ваш пакет каждый раз. Чтобы этого избежать, вы должны запускать главный сервер и сервер веб-пакетов в разных процессах, чтобы трубопроводы перезапускали только ваш экспресс-сервер и не касались веб-пакета. Вы можете сделать это с помощью пакета concurrently. Вы можете найти пример этого в react-isomorphic-starterkit. В пакете .json он имеет:

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

который запускает оба сервера одновременно, но в отдельных процессах.

Ответ 6

historyApiFallback также может быть объектом, а не булевым, содержащим маршруты.

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

Ответ 7

Может быть не во всех случаях, но кажется, что опция publicPath: '/' в devServer - это самое простое решение для исправления проблемы с глубокими маршрутами, см.: https://github.com/ReactTraining/react-router/issues/676

Ответ 8

Это сработало для меня: просто добавьте сначала webpack middlewares и app.get('*'... index.html resolver позже,

поэтому выражение сначала проверит, соответствует ли запрос одному из маршрутов, предоставляемых webpack (например: /dist/bundle.js или /__webpack_hmr_), а если нет, то он переместится в index.html с помощью распознавателя *.

т

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)
})