问题
Sample repo demonstrating the issue is here.
I'm trying to set up webpack dev server so that:
- Requests to
/
are served bypublic/landing.html
(a static landing page) - Requests to anything else are served by my React app
Using create-react-app
, and based on webpack-dev-server's options, I've set up my webpackDevServer.config.js as follows:
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
rewrites: [
// shows views/landing.html as the landing page
{ from: /^\/$/, to: 'landing.html' },
// shows views/subpage.html for all routes starting with /subpage
{ from: /^\/subpage/, to: 'subpage.html' },
// shows views/404.html on all other pages
{ from: /./, to: '404.html' },
],
},
And when I start webpack here's what I see:
- Requests to
/subpage
are routed correctly tosubpage.html
- Requests to
/foo
are routed correctly to404.html
. Eventually, these would be handled by my React app. - Requests to
/
are routed incorrectly to my React app.
How can I get landing.html
to respond to requests at /
?
回答1:
I ended up opening a bug request with webpack-dev-middleware
and discovered it was not a bug but a failure of configuration.
Specifically, the issue is using HtmlWebpackPlugin
alongside historyApiFallback
. I believe plugins are processed before the regex matching, and HtmlWebpackPlugin
's default file output is index.html
; this means that out of the box, /
will always be routed to the HtmlWebpackPlugin
output file.
The solution to this is to set a custom filename in HtmlWebpackPlugin
, which allows you to control the matching again. Here's a sample repo demonstrating the fix and here's the webpack config:
module.exports = {
context: __dirname,
entry: [
'./app.js',
],
output: {
path: __dirname + "/dist",
filename: "bundle.js"
},
devServer: {
publicPath: "/",
// contentBase: "./public",
// hot: true,
historyApiFallback: {
// disableDotRule: true,
rewrites: [
{ from: /^\/$/, to: '/public/index.html' },
{ from: /^\/foo/, to: '/public/foo.html' },
{ from: /(.*)/, to: '/test.html' },
],
}
},
plugins: [
new HtmlWebpackPlugin({
title: "Html Webpack html",
hash: true,
filename: 'test.html',
template: 'public/plugin.html',
}),
],
};
回答2:
Two thoughts come to mind:
- What you want to do is not possible with Webpack Dev Server (as far as I'm aware)
- And, once
npm run build
is run and deployed the deployed app would not follow the same rules as configured in Webpack Dev Server
Even if I'm mistaken on #1, #2 seems like a bigger issue if you ever plan to deploy the app. This leads me to recommend an alternate setup which will work on dev and production (or wherever it's deployed).
A few options:
- setup the app as a single-page app (SPA) and use React Router to serve the static routes (
/
and/subpage
) and wildcards (everything else) - setup node (or another server) to serve the static routes (
/
and/subpage
) and wildcards (everything else)
An Attempt
In an attempt to setup the routes I was able to achieve this setup:
- Display
landing.html
when/
is requested - Display
subpage.html
when/subpage
is requested - Display the React App at a specific path, like
app.html
To do this make the following changes:
Move
/public/index.html
to/public/app.html
mv ./public/index.html ./public/app.html
In
/config/webpackDevServer.config.js
, updatehistoryApiFallback
to:historyApiFallback: { // Paths with dots should still use the history fallback. // See https://github.com/facebookincubator/create-react-app/issues/387. disableDotRule: true, rewrites: [ // shows views/landing.html as the landing page { from: /^\/$/, to: "landing.html" }, // shows views/subpage.html for all routes starting with /subpage { from: /^\/subpage/, to: "subpage.html" }, // shows views/app.html on all other pages // but doesn't work for routes other than app.html { from: /./, to: "app.html" } ] }
In
/config/paths.js
updateappHTML
to:appHtml: resolveApp("public/app.html")
In
/config/webpack.config.dev.js, update
plugins` to include:new HtmlWebpackPlugin({ filename: "app.html", inject: true, template: paths.appHtml })
Requesting a random URL, like localhost:3000/foo
will return a blank page but contains the HTML from the app.html
page without the bundled <script>
tags injected. So maybe you can find a solution to this final hurdle.
来源:https://stackoverflow.com/questions/47273319/matching-root-route-in-webpack-dev-servers-historyapifallback