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