webpack-dev-server解决单页面应用路由问题

目前比较主流的框架如Vue、React等,都是单页面应用的框架。一般我们在使用它们的时候,会使用官方脚手架来创建项目,所以我们不必关心单页面应用路由是如何实现的,因为脚手架中已经帮我们做好了配置。在具体项目开发中,我们只需要做相应的路由配置即可。

那么在实际项目中,手动搭建项目的前提下,我们需要如何解决单页面应用的路由问题呢???

看个?:
目录结构:

|--demo
	|--src
		|--index.html
		|--index.js
		|--home.js
		|--list.js
	|--node_modules
	|--.babelrc
	|--package-lock.json
	|--package.json
	|--webpack.config.js

webpack.config.js中的配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8081,
    hot: true,
    hotOnly: true
  },
  module: { 
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      exclude: /node_modules/
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

.babelrc配置:

{
  "presets": [
    [
      "@babel/preset-env", {
        "targets": {
          "chrome": "67"
        },
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ]
}

package.json中scripts配置:

"scripts": {
    "start": "webpack-dev-server"
}

src/index.js:

import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom'; // 引入路由模块
import ReactDom from 'react-dom';
import Home from './home.js';
import List from './list.js';

// 这里设置的路由,根据用户的请求,来决定展示什么
class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <Route path='/' exact component={ Home } />
          <Route path='/list' component={ List } />
        </div>
      </BrowserRouter> 
    )
  }
} 

ReactDom.render(<App />, document.getElementById('root'));

期望效果:

  • 当用户访问根路径时,会访问home组件的内容
  • 当用户访问/list路径时,会访问list组件的内容

src/home.js:

import React, { Component } from 'react';

class Home extends Component { 
  render() {
    return <div>HomePage</div>
  }
} 

export default Home;

src/list.js:

import React, { Component } from 'react';

class List extends Component {
  render() {
    return <div>ListPage</div>
  }
} 

export default List;

注: 记得通过npm包管理工具一一安装上方所有配置项中的依赖、插件以及第三方库。

执行打包:

npm run start

唤起浏览器localhost:8081服务:

当访问"/list"路由时,我们期望出现ListPage的内容,但是实际情况如下:

注: 当我们去访问localhost:8081/list这个地址的时候,webpackDevServer会默认为你要访问服务器上的一个list页面。但我们的项目中只有一个index.html页面,并不存在list页面。所以它会提示你:Cannot GET /list (页面不存在)

我们可以使用webpackDevServer中的 historyApiFallback 配置来解决此问题:

devServer: {
    contentBase: './dist',
    open: true,
    port: 8081,
    hot: true,
    hotOnly: true,
    historyApiFallback: true // 在使用单页面应用的时候,需要设置此参数,代表如果访问除根路径以外的地址,最终都会转向去请求根路径。
},
  • historyApiFallback: true 代表在使用单页面应用的时候,需要设置此参数,代表如果访问除根路径以外的地址,最终都会转向去请求根路径。

此时再执行打包:

npm  run  start

浏览器显示正常:

打开控制台网络项:

从 “/list” 路由请求的响应信息我们可以看出,当访问localhost:8081/list地址时,最终访问的仍然是index.html页面。到此,单页面应用路由问题已完美解决。
所以,当我们在使用单页面应用时,记得一定要在devServer中配置historyApiFallback: true配置项。

historyApiFallback 的详细配置

historyApiFallback: {
      rewrites: [
        { from: /abc.html/, to: '/index.html' }
      ]
}
  • rewrites 中的配置代表:当我访问locahost:8081/abc.html时,devServer会自动帮我们转向访问index.html页面。
    • from 指访问的地址
    • to 指devServer最终帮我们转向的地址

所以上面例子中的 historyApiFallback:true 也就等价于:

historyApiFallback: {
      rewrites: [
        { 
        	from: /\.*/,  // 访问任何地址
        	to: '/index.html'  // 都转向index.html页面(根路径页面)
        }
      ]
}

一般的项目中,当我们做单页面应用,配置单页面路由时,设置 historyApiFallback:true;即可解决。

注: historyApiFallback只是在我们的开发环境中(本地)有效,一旦代码上线,就会再次出现访问页面找不到的问题。这时就需要后端小伙伴配合,仿照webpack-dev-server的配置,在nginx或apache对应的服务器上做它的一些配置,再进行访问。??

发布了54 篇原创文章 · 获赞 22 · 访问量 7240

猜你喜欢

转载自blog.csdn.net/Riona_cheng/article/details/100660065