这里讲解两个devServer相关的配置案例
这里我们基于React尝试发送一个Ajax请求,这里先借助axios库来实现:
axios.get('http://www.joern-lee.com/react/api/header.json').then((res) => {
...
})
这里正常情况下访问一些服务都会遇到跨域问题,另一方面在测试环境下,有时候请求的后端地址其实是不一样的,所以在代码中把host写死的话会很不灵活。
所以通常我们在Ajax都会写一个相对路径而非绝对路径:
axios.get('/react/api/header.json')
但是如何请求到真正的地址呢?一种方法是借助本地类似charles等工具来进行转发。另一种其实可以借助devServer来进行
devServer的转发功能主要通过配置proxy字段来实现,例如我们希望将上述/react/api/xxx转发到指定地址,通过proxy就可以解决。
首先我们不使用proxy,直接访问,正常会报如下log:
GET http://localhost:8080/react/api/header.json 404
然后我们这样配置一样:
devServer:{
...
proxy:{
'/react/api':'http://wwww.joern-lee.com'
}
}
接着再通过chrome的devtools看一下请求内容,虽然请求的url仍然是localhost,但是经过转发可以获取数据了(上面的proxy地址可以填你自己可以访问的接口测试)
有时候开发阶段,后端会给你一个demo数据的接口来代替header.json,如果你直接改代码,最后上线还要改回来,我们可以通过配置proxy来解决:
proxy:{
// 如果请求了/react/api这个地址,首先会去http://www.dell-lee.com下面拿数据
// 那header.json数据时候会拿demo.json返回给你
// 这样就不用改代码测试,不需要变源代码
'/react/api':{
target:'http://wwww.joern-lee.com',
pathRewrite:{
'header.json':'demo.json'
}
}
}
针对https请求需要加一个secure参数:
proxy:{
'/react/api':{
target:'http://wwww.joern-lee.com',
secure:false
}
}
这里我们还可以拦截请求,做一些中间处理:
proxy:{
'/react/api':{
target:'http://wwww.joern-lee.com',
secure:false,
bypass:function(req,res,proxyOptions){
process();
}
}
}
希望多个路径进行同一处理:
proxy:[{
context:['/react/auth','/react/api'],
target:...
}]
有一些网站对Origin做了限制,防止外部爬虫,这里可以通过这个字段绕过限制:
changeOrigin:true
proxy是devServer的代理,只在开发环境下有效,打包上线之后这种代理就不存在了,不会有请求转发!这一点需要注意,主要方便开发环境进行
这里我们以一个React的路由为例来介绍devServer的一个案例
这里我们写一个基础的react路由:
...
class App extends Component{
render(){
return(
)
}
}
...
这里的路由会根据具体的path来决定渲染的组件,以之前的webpack配置文件打包,然后我们看一下浏览器。
正常情况下Home组件可以正常展示,但是path是list时候就不行了。
这是因为BrowserRouter路由器借助了H5 history相关的API,所以当我们在浏览器输入list时,浏览器会尝试访问服务器获取/list下的资源,但其实该路径是不存在的,所以这里也是单页面应用会遇到的一个问题
这里只需要加一个historyApiFallback参数就可以了:
devServer:{
historyApiFallback:true
}
配置的该参数之后,如果浏览器找不到界面就返回默认首页index.html
原理是当服务器发现没有list地址的时候,会偷偷把针对这个路径的请求转化到根路径的请求,你可以发现它其实加载的都是index.html的内容
该参数下面还可以配置from和to字段,来自定义转化的路径:
// 下面配置等价于默认的配置
historyApiFallback:{
rewrites:[{
from:/\.*/,
to:'/index.html'
}]
}
团队中,有时希望能够管理大家的编码习惯,使得编程风格尽可能统一,否则同一段逻辑的写法可能都不一样,不好维护。
这里就需要引入EsLint这套代码规范的约束工具
我们可以通过npm进行安装:
npm install eslint --save-dev
之后还需要配置eslint来配置具体规范,这里可以输入命令来初始化:
npx eslint --init
然后根据控制台的配置流程来帮助你生成配置文件.eslintrc.js
eslint具体的使用和配置这里就不展开说了,一般来说可以结合babel-eslint解析器,或者给你的IDE安装插件来使用
但是如果你是通过在IDE装插件才完成ESLint高亮展示,此时其他开发者没有安装该插件,那他怎么看到代码语法提示呢?
所以单纯靠插件来确保质量会有问题(独立开发就没关系了),你没办法每个人都确保安装了插件。使用命令行工具又很麻烦。
这里就可以在webpack中把esLint整合进去
这里我们可以安装一个loader来处理:
npm install eslint-loader --save-dev
然后修改webapck配置文件:
rules:[...,{
test:/\.js$/,
exclude:/node_modules/,
use:['babel-loader','eslint-loader']
}}}]
这里注意顺序,首先通过eslint-loader来规范代码,然后再进行代码转义。如果转义再检查那么就不对了
需要配置devServer一个配置,设置overlay,这样就可以在不符合规范时弹窗进行提示,这里就把两者结合起来:
devServer:{
overlay:true
}
接着存在违反eslint的代码编写时,就会在浏览器上弹出一个浮层提示异常。
即便编辑器没有插件也可以很快定义问题。
另外还有cache配置,可以介绍每一次打包时候解析文件时候损耗的速度,提高一点打包速度
公司里面使用EsLint通常不会使用eslint-loader,因为会影响打包速度。
通常在准备提交代码到git仓库的时候,通过git的一些钩子对代码进行eslint检查,执行eslint src,如果不通过规范,禁止你提交代码。
如果对打包速度影响较大,可以扩展一些其他思路,即便牺牲一些便捷性
之前的打包基本都是针对SPA应用进行,整个页面只有一个HTML文件,这主要是考虑到现在主流前端开发都是基于react,vue等的单页面应用。
但是在部分情况下,例如对老项目兼容,就可能需要处理多页面的打包了
我们新建一个首页和列表页:
....
class App extends Component{
...
home page
}
ReactDom.render( ,document.getElementById('root'));
....
class App extends Component{
...
list page
}
ReactDom.render( ,document.getElementById('root'));
基于多页面应用那么上述两个组件就不是父子关系,而是用于两个HTML文件的root节点,这里我们需要先修改配置文件以打包这两个JS文件:
module.exports = {
entry:{
main:'./src/index.js',
list:'./src/list.js'
}
}
打包完成后,dist目录下面会分别有list和main的打包文件,但是目前打包生成的html文件还是只有一个(通过两个script标签引入了组件)
这里我们希望生成多个HTML文件且各自分别引用一个JS文件,这里就可以借助前述的HtmlWebpackPlugin插件,新增一个打包产出的HTML
这里我们可以去github上面看一些这个插件文档,多配置一个Plugin:
const plugins = [{
new HtmlWebpackPlugin({
template:'src/index.html',
filename:'index.html',
chunks:['runtime','vendors','main']
}),
new HtmlWebpackPlugin({
template:'src/index.html',
filename:'list.html',
chunks:['runtime','vendors','main']
})
new CleanWebpackPlugin...
}]
上述配置了两个Html插件,用于处理多个html文件,模板html都是同一个,filename决定了打包后的文件名称,chunks决定了html引入的包文件。
然后重新打包就可以看到html正确引入了对应的JS文件
上述过程如果涉及HTML很多的话我们需要写很多new HtmlWebpackPlugin的模板代码,这里我们可以写一个解析函数,根据entry字段来生成plugin数组:
const makePlugins = (configs) =>{
const plugins = [
new CleanWebpackPlugin...
];
Object.keys(configs.entry).forEach(item => {
new HtmlWebapckPlugin({
template:'src/index.html',
filename:`${item}.html`,
chunks:['runtime','vendors',item]
})
})
}
当你需要新增一个页面,只需要改config配置文件的entry字段就可以