我们希望可以做到,当文件发生变化时,可以自动的完成 编译 和 展示;
为了完成自动编译,webpack提供了几种可选的方式:
webpack给我们提供了watch 模式。
在该模式下,webpack依赖图中的所有文件,只要有一个发生了更新,那么代码将被重新编译;
我们不需要手动去运行 npm run build指令了。
注意:它只是会自动编译打包,要在浏览器实时查看还得配合 live-server 打开 html。
如何开启 watch 呢?两种方式:
watch: true;
--watch
的标识;我们可以在 npm 脚本中添加标识,因为 scripts 中的脚本,实际就是用 npm run 的方式帮你在命令行执行了后面的命令。这里的 webpack 也一样,在命令行执行,本质靠的还是 webpack-cli,包括 --watch 这种属性配置也是靠的 cli 添加到配置文件中。
{
"scripts": {
"build": "webpack --watch"
},
}
如果我们想不借助 live-server 的情况下,实现 live reloading(实时重新加载)的功能,我们可以使用 webpack-dev-server。
它将开启一个 express 服务器,所以浏览器打开,就和打开一般的网站一样,会先下载 index.html,然后再从 index.html 中去下载其他的文件。
事实上 webpack-dev-server 在编译之后不会写入任何输出文件。而是将 bundle 文件保留在内存中
安装:npm i webpack-dev-server -D
使用:webpack serve
启动一下就行,通常我们也是加入 npm 脚本中使用
"serve": "webpack serve --config webpack.config.js"
![image.png](https://img-blog.csdnimg.cn/img_convert/837a142e0f97f384517e44336321762c.png#clientId=ua2e6ddea-1eb8-4&errorMessage=unknown error&from=paste&height=142&id=u3e7b03df&name=image.png&originHeight=222&originWidth=1055&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42403&status=error&style=none&taskId=ud0771a41-16ac-4b79-bfad-aaff037763f&title=&width=675.2)
webpack-dev-server 服务查找文件的路径是:
http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename]
output: {
filename: "js/bundle.js",
path: path.resolve(__dirname, "./dist"),
publicPath: "hhh"
}
默认主机和端口是 localhost:8080,如果按如上配置 output,则请求 js 的 url 就是
http://127.0.0.1:8080/hhh/js/bundle.js
如果我们想要配置一下本地开发服务器,可以在 wepback 配置对象的顶层选项devServer
中配置。当然里面已经有很多已经默认配置了。
另外还可以添加一个顶层选项 target 标识打包的产物使用环境。target: "web"|"node"
devServer 中可以配置很多属性,contentBase 就是其中之一。
contentBase:表示 dev server 将告知浏览器那些 webpack 没有打包的文件在哪个目录,这样浏览器就可以直接去那个目录里面获取文件,而不是在打包好的包里面下载。
比如 favorite.ico ,生产环境肯定是要复制到打包的文件夹,但是开发阶段又不需要复制,就可以指定 ./public 为contentBase 来方便浏览器加载该图标。
有些额外的文件很大,这样不需要打包,就提升了开发打包效率。
然而它已经被弃用了。
提示信息中已经标出了所有 devServer 能进行配置的选项,当然很多选项都有默认配置。
现在想要达到上面 contentBase 一样的效果,需要使用 static
选项指定静态文件目录。目录下的文件相当于被添加到打包的出口目录中。
module.exports = {
devServer: {
static: "./img"
}
}
<img src="./1.png" alt="">
打开浏览器查看,会发现图片 1.png 是链接到本地 img 文件夹的,没有被打包。
host设置主机地址:
正常的数据库包发送路径是 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层 ;
而回环地址,是在网络层直接就被获取到了,不会到数据链路层和物理层的;
所以哪怕在同一个网段下的主机中,别人开启本地服务器,我们也不能通过 127.0.0.1 去访问到别人的服务器。因为请求压根不会被网卡发送出去,这也是把 127.0.0.1 叫本地主机的原因。
0.0.0.0:监听IPV4上所有的地址,再根据端口找到不同的应用程序;
比如我们开启 0.0.0.0 的服务,在同一个网段下的主机中,别人可以通过 0.0.0.0 访问到我的服务器。因为它是个广播地址,请求会发给网段下的所有主机。
port:设置监听的端口,默认情况下是8080
open:是否打开浏览器:
compress 是否为静态文件开启 gzip compression:
注意:有些端口在浏览器的黑名单里,比如:6666。这些端口不能设置。
什么是HMR呢?
HMR通过如下几种方式,来提高开发的速度:
如何使用HMR呢?
默认情况下,webpack-dev-server 已经支持 HMR,并且默认开启;**devServer: { hot: true }**
在不开启 HMR 的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是live reloading
;
但是你会发现,当我们修改了某一个模块的代码时,依然是刷新的整个页面:
这是因为我们需要去指定哪些模块发生更新时,进行HMR;
if (module.hot) {
module.hot.accept("./js/element.js", () => {
console.log("element模块发生更新了");
})
}
有一个问题:在开发其他项目时,我们是否需要经常手动去写入 module.hot.accpet相关的API呢?
比如开发Vue、React项目,我们修改了组件,希望进行热更新,这个时候应该如何去操作呢?
事实上社区已经针对这些有很成熟的解决方案了:
比如vue开发中,我们使用vue-loader,此loader支持vue组件的HMR,提供开箱即用的体验;
比如react开发中,有React Hot Loader,实时调整react组件(目前React官方已经弃用了,改成使用react-refresh)
那么HMR的原理是什么呢?如何可以做到只更新一个模块中的内容呢?
HMR Socket Server,是一个socket的长连接:
proxy 是我们开发中非常常用的一个配置选项,它的目的设置代理来解决跨域访问的问题:
跨域
在 devServer 中设置一个占位符,占位符代替请求的目标服务器地址。
比如本机 webpack 启动的服务源是http://localhost/8080
,现在想要去请求目标源是http://192.163.0.66:12345
,api 是/get
。
fetch("http://192.163.0.66:12345")
.then(response => response.json())
.then(result => console.log(result))
显然这必定发生跨域,因为端口号不一样。这时我们就要使用代理,具体做法就是让占位符代替目标源:
fetch("/api/get") // ‘/api’ 为占位符
.then(response => response.json())
.then(result => console.log(result))
但是现在有个问题,我们依然请求不到数据。因为占位符它不会被删除,会被加入到实际请求服务器数据的 url中。
现在的请求架构是,浏览器请求 --> 代理服务器请求 --> 真正的服务器。
我们查看请求头 url,一直是http://localhost/8080/api/get
没有发生跨域,但是代理服务器发送给真正服务器的请求中也带上了占位符 /api,可实际上真实服务器上并没有对应的资源,所以就会返回 404。
这时就**必须重写代理服务器的请求 url,删除占位符。 ****pathRewrite: { "^/api-hy": "" }**
changeOrigin 可以修改代理请求中的 headers 中的 host 属性,修改为 target 对应的目标请求源。
代理服务器向真实服务器发送请求,因为服务器又没有同源策略,所以任何请求源都可以随便发。比如 webpack 启动的代理服务器向真实服务器发送请求的源就是http://localhost:3000
。
但是真实服务器那边可能会做限制,比如防范爬虫之类的,校验请求头的 url,必须和真实服务器的源一致。则可以将 changeOrigin 设置为 true 即可修改。如上述图所示。
汇总:
devServer: {
proxy: {
"/api-hy": { // 占位符
target: "http://192.163.0.66/12345",
pathRewrite: {
"^/api-hy": ""
},
secure: false,
changeOrigin: true
}
}
}
}
historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在路由跳转之后,进行页面刷新
时,返回404的错误。
因为刷新就是拿着地址栏上的 url 向服务器发送一次请求,但是当前这个路由在 SPA 页面中都是前端设置的,服务器这个 url 对应的资源,所以就会 404。
historyApiFallback 两种取值:
如果设置为true,那么在刷新时,返回404错误时,会自动返回 index.html 的内容;
可以配置from来匹配路径,决定要跳转到哪一个页面;
事实上devServer中实现historyApiFallback功能是通过connect-history-api-fallback库的:
可以查看 connect-history-api-fallback文档