我尝试像这样为我的应用程序设置嵌套路由
/
->主页/about
->关于页面/protected
->受保护的默认页面/protected/page1
->受保护的页面1 它在codeandbox(https://codesandbox.io/s/react-router-nested-route-utqy7)中正常工作React 16.8.1 React Router 4.3.1
但是,当我使用webpack-dev-server(3.7.1)进行设置时,它只能到达/
,而无法到达其余路由。
我的文件结构就像
├── package.json
├── src
│ ├── index.jsx
│ └── index.html
├── webpack
│ ├── paths.js
│ ├── webpack.common.js
│ └── webpack.dev.js
└── webpack.config.js
paths.js
const path = require('path');
module.exports = {
outputPath: path.resolve(__dirname, '../', 'build'),
entryPath: path.resolve(__dirname, '../', 'src/index.jsx'),
templatePath: path.resolve(__dirname, '../', 'src/index.html'),
};
webpack.common.js
const webpack = require('webpack');
const convert = require('koa-connect');
const history = require('connect-history-api-fallback');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const commonPaths = require('./paths');
module.exports = {
entry: commonPaths.entryPath,
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /(node_modules)/,
},
],
},
serve: {
add: app => {
app.use(convert(history()));
},
content: commonPaths.entryPath,
dev: {
publicPath: commonPaths.outputPath,
},
open: true,
},
resolve: {
modules: ['src', 'node_modules'],
extensions: ['*', '.js', '.jsx', '.css', '.scss'],
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
template: commonPaths.templatePath,
}),
new ScriptExtHtmlWebpackPlugin({
defaultAttribute: 'async',
}),
],
};
webpack.dev.js
const webpack = require('webpack');
const commonPaths = require('./paths');
module.exports = {
mode: 'development',
output: {
filename: '[name].js',
path: commonPaths.outputPath,
chunkFilename: '[name].js',
},
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
'style-loader',
{
loader: 'css-loader',
},
'sass-loader',
],
},
],
},
devServer: {
contentBase: commonPaths.outputPath,
compress: true,
hot: true,
},
plugins: [new webpack.HotModuleReplacementPlugin()],
};
webpack.config.js
const webpackMerge = require('webpack-merge');
const common = require('./webpack/webpack.common');
const devConfig = require(`./webpack/webpack.dev.js`);
module.exports = webpackMerge(common, devConfig);
index.jsx
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";
const Homepage = () => (
<div>
<h1>Home Page</h1>
</div>
);
const AboutPage = () => (
<div>
<h1>About</h1>
</div>
);
const Protected = () => (
<div>
<h1>Protected default page</h1>
</div>
);
const ProtectedPage1 = () => (
<div>
<h1>ProtectedPage1</h1>
</div>
);
render(
<BrowserRouter>
<div>
<Route path="/" component={Homepage} exact />
<Route path="/about" component={AboutPage} />
<Route
path="/protected"
render={({ match: { url } }) => (
<div>
<Route path={`${url}/`} component={Protected} exact />
<Route path={`${url}/page1`} component={ProtectedPage1} />
</div>
)}
/>
</div>
</BrowserRouter>,
document.getElementById('app')
);
我认为某些路径在我的配置中不正确,我只是无法弄清楚哪里出了错。
答案 0 :(得分:1)
我遇到了问题中描述的相同问题(webpack-dev-server不提供嵌套路由,顶级路由正常工作)。可悲的是,historyApiFallback: true
和publicPath: '/'
都没有工作。实际上,问题出在index.html
内部,更确切地说是<script src="bundle.js"></script>
内部。更改为
<script src="/bundle.js"></script> <!-- do include slash before the file name -->
足以结束痛苦。
答案 1 :(得分:0)
我终于弄清楚了webpack-dev-server无法提供嵌套路由的原因。
作为单页应用程序,当您访问React应用程序的/somepath
时,它实际上会回退到/
并将路径名传递给react路由器。 React Router将使用浏览器的历史记录API导航到/somepath
。
由于某些未知原因,webpack-dev-server默认情况下不会启用此“回退到历史API”行为。
因此,我们需要将historyApiFallback: true,
添加到webpack配置的devServer
中。
现在,所有顶级路由(如/somepath
都可以使用,但对于嵌套路由(如/somepath/morepath
)来说,这还不够。
使用默认的webpack-dev-server设置,已编译的html模板将指向捆绑的js,例如<script type="text/javascript" src="main.js"></script>
。请注意src="main.js"
,它假定main.js
与index.html
在同一路径下。该假设对顶级路径/somepath
是正确的,但对于嵌套路由/somepath/morepath
,此假设将导致html文件像main.js
一样访问/somepath/main.js
。
因此,我们最终寻找一种方法来为html文件访问绑定的js指定一个特定位置。并且,这是publicPath
的工作。将publicPath: '/',
添加到webpack配置的输出块中。它会告诉html始终访问main.js
文件夹中的/
,并且已编译的html将是<script type="text/javascript" src="/main.js"></script>
。这正是我们想要的。
答案 2 :(得分:0)
尝试添加:
<base href="/" />
到您的<head>
的{{1}}标签。这样,它将始终寻找index.html
包,即使是嵌套路由也是如此。
答案 3 :(得分:0)
基本上包装,您的反应应用使用<HashRouter>
而不是<BrowserRouter>
可以正常运行,而无需进行任何Webpack配置修改,如果您不想使用HashRouter,则可以自由使用historyApiFallback:在Web中为true在webpack.config文件的底部打包dev服务器配置
like so
const config = {
........
devServer: {
compress: true,
port: 3000,
https: false,
historyApiFallback:true
}
}
答案 4 :(得分:0)
要在您的webpack.config.js文件中总结@Bing Lu的答案:
module.exports = () => ({
mode: 'development',
entry: ...,
...,
output: {
...
publicPath: '/' // <- this is the important line along with historyApiFallback = true in the dev server config
},
...,
devServer: {
contentBase: path.join(__dirname, 'dist'),
historyApiFallback: true,
compress: true,
...
},
})