# webpack-dev-server 高级配置
今天我们再来回顾一下 webpack-dev-server
的一些配置,主要讲两个,一个是关于请求转发的 proxy
配置,一个是针对单页应用路由跳转的 historyApiFallback
配置。
虽然我们之前都有讲到过,今天权当是再巩固一下,奥利给!!!
# proxy
:请求转发
# 测试代码
修改 index.js
,在 react
的组件加载完成的生命周期函数中去请求豆瓣的 top 250
影单,我们使用 axios
库来请求:
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import axios from 'axios';
class App extends Component {
componentDidMount() {
axios.get('https://douban.uieee.com/v2/movie/top250')
.then((res) => {
console.log(res);
})
}
render() {
return (
<div>
proxy 转发
</div>
);
}
}
ReactDom.render(<App />, document.getElementById('root'));
安装 axios
:
npm install axios -S
我们运行 npm run dev
,可以在页面上看到,成功的请求了豆瓣的影单:
我们请求豆瓣接口直接是将接口的全地址写死的,但是一般来说,我们开发环境和线上环境使用的服务器可能不是同一台,开发用的是测试服务器,线上用的是线上服务器。所以一般我们会这么写:
...
class App extends Component {
componentDidMount() {
axios.get('/movie/top250')
.then((res) => {
console.log(res);
})
}
...
}
...
但是这样写的话,我们的接口请求地址变成了 http://127.0.0.1:8080/movie/top250
,当然这样请求肯定是不能成功的,如果我们能实现当我们访问 http://127.0.0.1:8080/movie/top250
帮我们转发到 https://douban.uieee.com/v2/movie/top250
这个接口那就太完美了。
我们可以通过配置 proxy
来完成这个转发。
# 配置
我们在开发配置文件 webpack.prod.js
中 devServer
增加 proxy
配置:
...
const devConfig = {
...
devServer: {
overlay: true,
contentBase: './dist',
port: 8080,
hot: true,
proxy: {
'/movie/': {
target: 'https://douban.uieee.com/v2',
}
}
},
...
}
...
我们重新打包一下,可以发现我们接口可以正常请求了:
# 参数讲解
# pathRewrite
假如我们开发服务器上暂时还没有 top250
的数据,后端工程师暂时告诉我们可以先使用 in_theaters
这个数据进行调整开发。
一般来说我们需要去修改请求的接口链接,将 /movie/top250
改为 /movie/in_theaters
,但是有了 webpack-dev-server
之后,我们就不需要去改接口链接了。
我们可以做如下配置,配置 pathRewrite
属性,将 top250
转发到 in_theaters
上:
...
const devConfig = {
...
devServer: {
overlay: true,
contentBase: './dist',
port: 8080,
hot: true,
proxy: {
'/movie/': {
target: 'https://douban.uieee.com/v2',
pathRewrite: {
'top250': 'in_theaters'
},
}
}
},
...
}
...
我们可以接口请求了最新的正在上映的电影列表:
# secure
默认情况下,devServer
是不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。
但是有的时候我们就是要做请求转发的网址是一个 https
的网址,这个时候就需要配置 secure: false
,来完成对 https
的请求网址的转发。
proxy: {
"/movie/": {
target: "https://douban.uieee.com/v2/top250",
secure: false
}
}
# bapass
有时你不想代理所有的请求。可以基于一个函数的返回值绕过代理。在函数中你可以访问请求体、响应体和代理选项。必须返回 false
或路径,来跳过代理请求。
proxy: {
"/movie/": {
target: "https://douban.uieee.com/v2",
bypass: function(req, res, proxyOptions) {
if (req.headers.accept.indexOf("html") !== -1) {
console.log("Skipping proxy for browser request.");
return "/index.html";
}
}
}
}
上面的配置是,当你请求返回的是一个 html
文件的时候,我们就直接跳过接口请求,直接返回项目根路径下面的 index.html
。
# context
如果要将多个特定路径代理到同一目标,我们就可以使用一个或多个具有上下文属性的对象数组来完成。把这个数组放到 context
属性中去完成转发:
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}]
# index
默认情况下,我们直接去代理根目录是不能进行接口转发的,因为 webpack-dev-server
默认是不支持对根目录的接口转发的。
proxy: {
"/": {
target: "https://douban.uieee.com/v2/top250",
secure: false
}
}
我们如果想要对根目录进行转发,我们需要配置 index
为 false
或者是 ''
。
module.exports = {
...
devServer: {
index: '', // specify to enable root proxying
proxy: {
context: () => true,
target: 'http://localhost:1234'
}
}
};
# changeOrigin
有些情况下,一些网站会对 origin
做一些限制,它防止外部网站用爬虫去爬取他的一些内容,这会导致可能当我们代理了一些网站去请求数据的时候会拿不到内容。这个时候我们只要配置 changeOrigin
就行
module.exports = {
...
devServer: {
proxy: {
'/movie/': {
target: 'https://douban.uieee.com/v2',
changeOrigin: true
}
}
}
};
一般情况下,我们会一直把这个参数写着的。
# headers
我们可以在转发的时候配置请求头的信息,变更一下请求头。我们也可以修改请求 cookie
的信息等。
module.exports = {
...
devServer: {
proxy: {
'/movie/': {
target: 'https://douban.uieee.com/v2',
changeOrigin: true,
headers: {
host:'www.example.org',
cookie: 'isLogin=1' // 判断是否登录的 cookie 信息
}
}
}
}
};
更多配置,大家可以参考 更多 headers 配置。
# 更多参数
webpack-dev-server
底层使用的是 http-proxy-middleware 这个包,这个包帮我们完成各种各样丰富的配置的,如果想要学习更多配置,大家可以看看他的文档。
# historyApiFallback
:单页面路由跳转
这个配置参数能帮我们很好的解决,单页面应用的路由问题。
# 写点代码
我们新建 home.js
和 list.js
作为我们路由切换中的两个页面:
// home.js
import React, { Component } from 'react';
class Home extends Component {
render() {
return <div>首页</div>;
}
}
export default Home;
// list.js
import React, { Component } from 'react';
class List extends Component {
render() {
return <div>列表页</div>;
}
}
export default List;
我们安装 react-router-dom
来帮助我们做 react
中的路由切换:
npm install react-router-dom -S
接着我们修改入口文件 index.js
,完成上面两个页面的路由切换:
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import ReactDom from 'react-dom';
import Home from './home';
import List from './list';
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
页面。
我们打包一下,可以看到页面跑起来了:
当我们访问 http://127.0.0.1:8080/list
的时候,页面却告诉我们页面找不到:
造成这个错误的原因就是,当我们访问 http://127.0.0.1:8080/list
这个链接的时候,后端也就是 webpack-dev-server
以为我们访问的是 list
这个页面,但是我们的项目是单页应用,项目中只有一个 index.html
,并没有 list
这个页面,所以他就会提示我们页面找不到。
这个时候我们就需要在 webpack-dev-server
中配置 historyApiFallback
这个参数,我们修改开发配置文件 webpack.dev.js
:
module.exports = {
//...
devServer: {
historyApiFallback: true
}
};
重新打包一下,我们在访问一下 http://127.0.0.1:8080/list
这个页面,这个时候列表页就出来了:
配置了这个参数后,当我们服务器找不到我们访问的地址的时候,即请求 404
的时候,或者说是在服务器上的任何一个路径请求,我们的服务器都会给我们转化为对根路径(index.html
)的请求。所以他都会去引入 index.html
页面。
也就是说不管我们请求什么路径,他都会给我们返回我们根路径的代码,当我请求 http://127.0.0.1:8080/dsadasdas
实际上页面上加载的也是 index.html
的 js
:
既然请求的是我们的 index.html
的代码,那当然我们单页应用的路由可以生效啦。
# 更多 historyApiFallback
配置
他可以配置一个 rewrites
的规则,
module.exports = {
//...
devServer: {
historyApiFallback: {
rewrites: [
{ from: /abc.html/, to: '/index.html' },
]
}
}
};
上面的配置的意思是,当我们去访问 abc.html
的时候,就帮我们重定向到 index.html
中去,我们重新打包一下代码,可以看到当我们访问 http://127.0.0.1:8080/abc.html
的时候,实际上展示出来的是 index.html
:
我们回过头来想一下之前我们写成 true
,实际上意思就是不管你写什么路径,webpack-dev-server
都会帮你重定向到 index.html
。
我们还可以给 rewrites
中的 to
参数导出一个函数,自定义我们要重定向的网页内容。
module.exports = {
//...
devServer: {
historyApiFallback: {
rewrites: [
{
from: /abc.html/,
to: function(context) {
return '/bower_components' + context.parsedUrl.pathname;
}
},
]
}
}
};
一般来说我们只要配置 true
就可以解决大部分问题了,这个配置还有很多配置可选项,我们可以在用到的时候再去查阅 historyApiFallback 底层包 connect-history-api-fallback。
# 相关链接
# 示例代码
示例代码可以看这里: