historyApiFallback не работает на сервере разработки Webpack

Я использую сервер разработки Webpack и browserHistory в React Router для управления URL-адресами с помощью HTML5 History API. historyapifallback-option не работает в моем веб-пакете конфигурационный файл. После обновления http://localhost:8080/users или http://localhost:8080/products я получил 404.

webpack.config.js

var webpack = require('webpack');
var merge = require('webpack-merge');

const TARGET = process.env.npm_lifecycle_event;

var common = {
    cache: true,
    debug: true,
    entry: './src/script/index.jsx',
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    output: {
        sourceMapFilename: '[file].map'
    },
    module: {
        loaders: [
            {
                test: /\.js[x]?$/,
                loader: 'babel-loader',
                exclude: /(node_modules)/
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery"
        })
    ]
};

if(TARGET === 'dev' || !TARGET) {
    module.exports = merge(common,{
        devtool: 'eval-source-map',
        devServer: {
            historyApiFallback: true
        },
        output: {
            filename: 'index.js',
            publicPath: 'http://localhost:8090/assets/'
        },
        plugins: [
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify('dev')
            })
        ]
    });
}

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Test</title>
    </head>
    <body>
        <div id="content">
            <!-- this is where the root react component will get rendered -->
        </div>
        <script src="http://localhost:8090/webpack-dev-server.js"></script>
        <script type="text/javascript" src="http://localhost:8090/assets/index.js"></script>
    </body>
</html>

index.jsx

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {Router, Route, useRouterHistory, browserHistory, Link} from 'react-router';

class Home extends Component{
  constructor(props) {
    super(props);
  }

  render() {
      return <div>
          I am home component
          <Link to="/users" activeClassName="active">Users</Link>
          <Link to="/products" activeClassName="active">Products</Link>
        </div>;
  }
}

class Users extends Component{
  constructor(props) {
    super(props);
  }

  render() {
      return <div> I am Users component </div>;
  }
}

class Products extends Component{
  constructor(props) {
    super(props);
  }

  render() {
      return <div> I am Products component </div>;
  }
}

ReactDOM.render(
    <Router history={browserHistory} onUpdate={() => window.scrollTo(0, 0)}>
        <Route path="/" component={Home}/>
        <Route path="/users" component={Users} type="users"/>
        <Route path="/products" component={Products} type="products"/>
    </Router>
    , document.getElementById('content'));

package.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.jsx",
  "scripts": {
    "start": "npm run serve | npm run dev",
    "serve": "./node_modules/.bin/http-server -p 8080",
    "dev": "webpack-dev-server -d --progress --colors --port 8090 --history-api-fallback"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "events": "^1.1.0",
    "jquery": "^2.2.3",
    "path": "^0.12.7",
    "react": "^15.0.2",
    "react-dom": "^15.0.2",
    "react-mixin": "^3.0.5",
    "react-router": "^2.4.0"
  },
  "devDependencies": {
    "babel": "^6.5.2",
    "babel-core": "^6.8.0",
    "babel-loader": "^6.2.4",
    "babel-polyfill": "^6.8.0",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "babel-register": "^6.8.0",
    "http-server": "^0.9.0",
    "webpack": "^1.13.0",
    "webpack-dev-server": "^1.14.1",
    "webpack-merge": "^0.12.0"
  }
}

Я попытался изменить devServer в своей конфигурации, но это не помогло:

devServer: {
    historyApiFallback: {
        index: 'index.html',
    }
},

devServer: {
    historyApiFallback: {
        index: 'index.js',
    }
},

devServer: {
    historyApiFallback: {
        index: 'http://localhost:8090/assets',
    }
},

devServer: {
    historyApiFallback: {
        index: 'http://localhost:8090/assets/',
    }
},

devServer: {
    historyApiFallback: {
        index: 'http://localhost:8090/assets/index.html',
    }
},

devServer: {
    historyApiFallback: {
        index: 'http://localhost:8090/assets/index.js',
    }
},

devServer: {
    historyApiFallback: {
        index: 'http://localhost:8090/assets/index.js',
    }
},
output: {
    filename: 'index.js',
            publicPath: 'http://localhost:8090/assets/'
},

person Matt    schedule 17.05.2016    source источник


Ответы (5)


Сегодня я отвечаю на тот же вопрос. пусть config в webpack.config.js: output.publicPath равняется devServer.historyApiFallback.index и указывает маршрут файла html。 моя версия webpack-dev-server - 1.10.1 и работает хорошо. http://webpack.github.io/docs/webpack-dev-server.html#the-historyapifallback-option не работает, вы должны указать маршрут файла html.

Например

module.exports = {
    entry: "./src/app/index.js",
    output: {
        path: path.resolve(__dirname, 'build'),
        publicPath: 'build',
        filename: 'bundle-main.js'
    },
    devServer: {
        historyApiFallback:{
            index:'build/index.html'
        },
    },
};

historyApiFallback.index указывает, что, когда путь URL-адреса не соответствует истинному файлу, webpack-dev-server использует конфигурацию файла в historyApiFallback.index для отображения в браузере, а не на странице 404. тогда все, что связано с вашим изменением маршрута, позволяет сделать это вашим js с помощью response-router.

person echizen    schedule 05.07.2016
comment
вывод: {publicPath: '/', путь: path.join (__ dirname, 'public'), filename: 'bundle.js'}, devServer: {historyApiFallback: true,} В моем случае путь вывода такой и здесь резервный вариант historyApi не работает, даже если я разместил historyApiFallback: {index: '/'} - person Bijay Rai; 04.04.2017
comment
@BijayRai У меня такой же конфиг, что и у вас. Как вы решили проблему? - person Anvesh Checka; 31.08.2017
comment
的 配置 省略 переведено с помощью Google Translate: Другая конфигурация опущена. - person Millar248; 09.01.2019

output: {
    ...
    publicPath: "/"
  },

Добавление общедоступного пути решило эту проблему для меня

person amit    schedule 27.11.2018
comment
У меня тоже работает - person Danon; 18.06.2021

У меня была эта проблема, и я смог ее исправить только с помощью index: '/' с webpack 4.20.2

        historyApiFallback: {
            index: '/'
        }
person jsdeveloper    schedule 16.04.2019
comment
для всех, кто использовал последний веб-пакет React +, это было единственное решение, которое помогло, указанное в теме. - person rob2d; 03.09.2019

Ссылка: https://webpack.js.org/configuration/dev-server/#devserver-historyapifallback

Это работает с любым реактивным маршрутизатором.

Вы должны добавить historyApiFallback: true

module.exports = {
    cache: true,
    entry: "./index.js",
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'public')
    },
    context: SRC,
    devServer: {
        contentBase: path.resolve(__dirname, 'public/assets'),
        stats: 'errors-only',
        open: true,
        port: 8080,
        compress: true,
        historyApiFallback: true
    },
...
}
person STEEL    schedule 21.05.2018
comment
Они уже используют это, передавая объект, в котором они пытались использовать конкретный index - person toastal; 12.11.2019

Здесь происходит очень хитрая штука!

404 может быть двумя совершенно разными объектами ниже. Вы можете открыть вкладку «Сеть» в Chrome, чтобы узнать, является ли это исходным запросом 404 или находящимися внутри него ресурсами.

Если вы не боитесь терминала, вы также можете сделать curl -v http://localhost:8081/product, чтобы увидеть фактический код ответа HTTP.

Случай 1: 404 на начальной HTML-странице

Это тот случай, когда установка с помощью historyFallbackApi неверна.

Обычно в devServer конфигах Webpack должно работать просто historyApiFallback: true. (источник) Однако, если у вас есть собственная output папка, вы должны установить свойство index для historyApiFallback на тот же путь, как рекомендовано другими ответами на этот вопрос, например jsdeveloper или echzin's.

Случай 2: 404 по активам (например, bundle.js или vendor.js)

Это довольно интересно!

В этом случае вы действительно получаете исходный HTML-код (т.е. если вы добавляете view-source: перед URL-адресом, чтобы стать view-source:http://localhost:8081/admin, вы видите свой HTML-код, и / или команда curl показывает HTML-код), но страница не работает в браузере.

Что делает historyApiFallback, что может показаться волшебством, буквально просто устанавливает req.url сервера Express как index.html файл для любого входящего запроса GET в домене. (Основные две строки в исходный код)

Однако, если путь к вашим активам является относительным (например, в исходном представлении вы видите <script src="vendor.js"></script>) И путь, по которому вы переходите, не находится на той же глубине пути, что и индекс (например, вы пытается загрузить http://localhost:8081/admin/user/12/summary, когда главный сервер находится на http://localhost:8081/admin), происходит то, что он не может найти файлы .js для вашего кода JavaScript. (в моем случае http://localhost:8081/admin/user/12/vendor.js)

введите описание изображения здесь

Обратите внимание, что любой маршрутизатор, который имеет дело с историей HTML5 здесь (реагирующий маршрутизатор или маршрутизатор vue), знает, как инициализировать внутренний путь к document.location.href при начальной загрузке. Но он не знает, где находится корень, чтобы правильно обновить путь к нему активов. (И, возможно, это даже не его работа с точки зрения ответственности.) В результате путь к ресурсам будет рассчитываться на основе пути URL, а не пути index.html! Таким образом, только для src="vendor.js" без абсолютного префикса / он пытается найти /admin/user/12/vendor.js вместо /vendor.js.

Здесь вам нужно убедиться, что output путь вашего WebPack является абсолютным путем и начинается с /, чтобы он всегда работал независимо от целевого URL. то есть всегда <script src="/vendor.js"></script> в исходном HTML.

Для этого вы должны установить output.publicPath как абсолютный путь (с доменом или без него). Вы можете проверить это с помощью техники view-source: или curl, описанной выше. :)

person Aidin    schedule 07.05.2021
comment
Это сработало для меня - person Danon; 18.06.2021