webpack高级概念,webpack-dev-server解决单页面应用路由问题(手动搭建webpack,不是用脚手架,404找不到页面,一)(系列十五)

目前比较主流的框架如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"
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>html template</title>
  </head>
  <body>
    <div id='root'></div>
  </body>
</html>


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页面(后端的一个list页面)。所以它会提示你:Cannot GET /list (页面不存在)

我们可以使用webpackDevServer中的 historyApiFallback 配置来解决此问题:打开webpack官网。 https://webpack.js.org/configuration/dev-server#devserverhistoryapifallback

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


historyApiFallback: true 代表在使用单页面应用的时候,需要设置此参数,代表如果访问除根路径以外的地址,最终都会转向去请求根路径。

他的原理是后端服务器如果发现并没有这个/list地址。就会偷摸的转化成根路径的请求,所以不管请求什么地址,都会请求index.html,里面有main.js,也就是我们的业务代码,这里面的路由就能正常的生效。
此时再执行打包:

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对应的服务器上做它的一些配置,再进行访问。

原文链接:https://blog.csdn.net/riona_cheng/article/details/100660065

原文地址:https://www.cnblogs.com/fsg6/p/14494065.html