devServer
publicPath
output.publicPath
output中的path的作用是告知webpack之后的输出目录, 比如静态资源的js、css等输出到哪里,常见的会设置为dist、build文件夹等;
output中还有一个publicPath属性,该属性是指定index.html文件打包引用的一个基本公共路径,
实际的资源路径为域名 拼接上 output.publicPath 拼接上 资源路径
publicPath的默认值是一个空字符串,所以我们打包后引入js文件时,路径是 bundle.js,实际路径就变为了域名+ ’‘+bundle.js
,此时浏览器会自动在bundle.js前边加上/
,变成例如http://www.example/bundle.js
在开发中,我们也将其设置为 / ,路径是 /bundle.js,这样可以放置某些浏览器可能没法为我们自动添加/
但是,如果设置了publicPath为/
,那么在本地直接打开html文件来运行会存在问题,
因为本地访问的路径是file:///Users/example/xxxx/xxx/webpack-demo/dist/index.html
, 此时bundle.js的路径为/bundle.js
进行路径拼接后就会变为file:///bundle.js
,此时就会因为找不到bundle.js而报错
所以如果需要在本地打开进行调试的时候,可以会将publicPath
设置为./
,此时对应的路径会转换为./bundle.js
,可以根据相对路径去查找资源。
devServer.devMiddleware.publicPath
devServer.devMiddleware.publicPath
其实就是webpack-dev-server
在V3版本中的devServer.publicPath
, 详情见迁移说明
该属性设置的是搭建本地服务的时候,express
中各个资源请求路由
的公共路径,默认值是/
这个属性实际修改的是devServer本地开启的express
的路由映射
例如:
devServer.devMiddleware.publicPath的值为/
的时候
请求/bundle.js
-> 匹配路由/bundle.js
-> 返回资源
当设置值为/abc
的时候,路由会全部添加前缀/abc
/bundle.js
->/abc/bundle.js
->返回原来/bundle.js所对应的路由资源
注意: 默认情况下output.publicPath
的值是空字符串,所以此时在页面中所有打包后资源请求的路径都是类似于bundle.js
的路径
所以是无法准确匹配对应路由,所以资源都是404,为了让打包后的资源的请求路径和路由的路径一致,需要修改output.publicPath
的值和devServer.devMiddleware.publicPath
的值保持一致
因此: 建议 devServer.devMiddleware.publicPath 与 output.publicPath所配置的路径应该时刻保持相同
contentBase
devServer中contentBase用来设置打包后的资源,又依赖于其他的一些资源的路径
此时contentBase
就可以用来设置这些静态资源的基准路径
比如在index.html中,我们需要依赖一个 abc.js 文件,这个文件我们存放在 public文件 中
在index.html中,我们应该如何去引入这个文件呢?
-
在
index.html
引入代码是这样的:<script src="./abc.js"></script>
-
此时如果没有
contentBase
,是无法在webpack-dev-server提供的服务中找到对应资源因为默认情况下,如果它发现是相对路径的时候,是以项目根目录去进行查找
-
此时可以设置
contentBase
为contentBase: path.resolve(__dirname, './public')
ps: contentBase的值虽然可以设置为相对路径,但是推荐设置为
绝对路径
此时devServer就会以public为相对路径查找的基准路径
当然这么做是仅仅是针对于devServer,如果位于生产环境,依旧需要使用copyWebpackPluign
将相关资源进行复制
watchContentBase
默认情况下,静态资源的修改,是不会触发devServer的HMR,因为静态资源并不是一个模块
所以可以设置watchContentBase
的值为true,此时当静态资源发生更新的时候,
devServer会自动刷新对应的页面,从而更新界面
proxy
proxy的目的设置代理来解决跨域访问的问题, 是我们开发中非常常用的一个配置选项
比如我们的一个api请求是 http://localhost:8888 但是本地启动服务器的域名是 http://localhost:8000 这个时候发送网络请求就会出现跨域的问题
那么我们可以将请求先发送到一个代理服务器,代理服务器帮助我们进行请求的转发,因为跨域是浏览器端限制,所以代理服务器和API服务器没有跨域的问题,就可以解决我们的 跨域问题了
devServer: {
proxy: {
"/api": { // 请求路径前缀
// /api/moment会被代理到 https://www.example.com/api/moment;
target: 'https://www.example.com', // 表示的是代理到的目标地址
changeOrigin: true, // 默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为
secure: false, // 默认情况下,将不接受在 HTTPS 上运行且证书无效的后端服务器。 如果需要可以关闭校验
pathRewrite: { // 重写路由
// /api/moment ====> https://www.example.com/api/moment
// 但是实际接口为 https://www.example.com/moment
"^/api": ''
}
}
}
}
如果没有任何的设置,可以简写为
module.exports = {
//...
devServer: {
proxy: {
'/api': 'https://www.example.com',
},
},
};
如果想将某个特定路径代理到同一目标,则可以使用一个或多个context
属性的对象的数组
module.exports = {
//...
devServer: {
proxy: [
{
context: ['/auth', '/api'],
target: 'https://www.example.com',
},
],
},
};
historyApiFallback
historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在history路由模式下,进行路由跳转之后,进行页面刷新 时,返回404的错误
因为在SPA中的路由是前端路由,直接刷新的时候,后台是不存在对应路由的,因此会报404错误
当使用HTML5历史API时,所有的404
请求都响应index.html
的内容。 将devServer.historyApiFallback
设为true
开启
module.exports = {
//...
devServer: {
historyApiFallback: true,
},
};
通过传递对象,可以使用配置选项rewrites
,设置不同路由的默认跳转路径
module.exports = {
//...
devServer: {
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' },
],
},
},
};
historyApiFallback: {
index: '/', // 默认返回的资源是index.html, 可以使用index属性修改默认返回的资源
disableDotRule: true
// disableDotRule 选项可以在路径匹配的时候忽略路径中的点
// 有路由 /:param
// disableDotRule为 false
// https://www.example.com/foo.html ===> 404
// disableDotRule为 true
// https://www.example.com/foo.html ===> 匹配成功 param的值为 foo.html
}
其它配置选项
选项 | 功能 |
---|---|
hot | 实时监听文件的修改,在文件内容发生改变的时候,自动去刷新界面以显示最新的内容 默认值是true 可以设置的值有true和'only' 设置为’only‘的时候,会关闭自动检测文件内容的改变 |
host | 设置主机地址 默认值是localhost,如果希望其他地方也可以访问,可以设置为 0.0.0.0 |
port | 设置监听的端口,默认情况下是8080 |
open | 是否打开浏览器 默认值是false,设置为true会打开浏览器 |
compress | 是否为静态文件开启gzip compression 会在响应头中添加 content-encoding: gzip 浏览器接收到gzip格式文件后会自动对gzip文件进行解压缩操作 默认值是false,可以设置为true |
localhost 和 0.0.0.0 的区别:
-
localhost:本质上是一个域名,通常情况下会被解析成127.0.0.1
-
127.0.0.1:回环地址(Loop Back Address),表达的意思其实是我们主机自己发出去的包,直接被自己接收
- 正常的数据库包经常 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层
- 而回环地址,是在网络层直接就被获取到了,是不会经常数据链路层和物理层的
- 比如我们监听 127.0.0.1时,在同一个网段下的主机中,通过ip地址是不能访问的;
-
0.0.0.0:监听IPV4上所有的地址,再根据端口找到不同的应用程序;
- 比如我们监听 0.0.0.0时,在同一个网段下的主机中,通过ip地址是可以访问的
resolve
resolve用于设置模块如何被解析:
在开发中我们会有各种各样的模块依赖,这些模块可能来自于自己编写的代码,也可能来自第三方库,resolve可以帮助webpack从每个 require/import 语句中,找到需要引入到合适的模块代码
webpack能解析三种文件路径:
路径 | 解析 |
---|---|
绝对路径 | 由于已经获得文件的绝对路径,因此不需要再做进一步解析 |
相对路径 | 在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录 在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径 |
模块路径 | 在 resolve.modules中指定的所有目录检索模块 (默认值是 ['node_modules'],所以默认会从node_modules中查找文件) 也可以通过设置别名的方式来替换模块的查找路径规则 |
webpack查找模块的规则:
如果是一个文件:
- 如果文件具有扩展名,则直接打包文件
- 否则,将使用 resolve.extensions选项作为文件扩展名解析
如果是一个文件夹:
会在文件夹中根据 resolve.mainFiles配置选项中指定的文件顺序查
- resolve.mainFiles的默认值是 ['index']
resolve: {
// 配置后缀名的时候,新的配置会覆盖默认的配置,所以需要加上默认的配置
// 每一个文件的后缀名应该以点来开头
extensions: ['.js', '.json', '.ts'],
alias: {
// alias的值推荐设置为绝对路径,因为我们无法确定实际是在那个目录层级来使用别名
'@': path.resolve(__dirname, './src'),
'utils': path.resolve(__dirname, './src/utils')
}
}