如果你想学到更多实用前端知识。
可以关注我的公众号:【前端驿站Lite】,一个不止分享前端的地方 ᕦ( •̀∀•́)ᕤ
阅读收获
阅读完本篇文章,你将会有以下收获:
- webpack-dev-middleware 是什么、如何进行工作的。
- webpack-dev-server 是什么、如何进行工作的、实现原理是什么。
- webpack-dev-server 常用配置项static、hot、proxy重点解读。
- webpack-dev-server 如何使用、其他常用配置项设置。
前言
我们使用webpack打包时,每次修改代码后,都需要重新打包,然后刷新浏览器才能看到效果,这样的开发体验是非常不友好的。
所以我们需要一个工具,能够实现代码修改后自动打包,自动刷新浏览器,从而提高我们的开发效率。
这也就是我们本文章的主角 webpack-dev-server。
watch模式
开始之前,我们需要了解一下启动webpack的 watch 模式,watch 模式可以实现对文件的实时监听,监听到文件变化后,会重新编译打包,将产物输出到磁盘中。
# webpack 启动时增加 `watch`参数
npx webpack --watch
webpack-dev-middleware
学习webpack-dev-server之前,我们还需要了解一下webpack-dev-middleware
是什么?
webpack-dev-middleware
是一个容器(wrapper),它会将 webpack 编译后的文件存储到内存中,然后在用户访问 express 服务时,将内存中对应的资源输出返回。
那webpack-dev-middleware如何进行工作的呢?
- webpack-dev-server会用webpack进行实时编译,再用webpack-dev-middleware 将webpack编译后文件会输出到内存中。可以将webpack-dev-middleware看作一个内存型的文件系统,目录与内存中的产物会形成映射关系。
- 当我们访问express服务时,express会将请求转发给webpack-dev-middleware,webpack-dev-middleware会根据映射关系,找到对应的文件,再将文件内容返回给express。
webpack-dev-server
我们了解了webpack-dev-middleware之后,就可以很轻松的理解webpack-dev-server了。
webpack-dev-server是 webpack 官方推出的一款开发工具,这款工具可以实现代码修改后自动编译
、自动打包
,自动刷新浏览器
的功能。
webpack-dev-server 会将打包后的产物放入内存中,这样就大大提升了 构建速度
与 访问速度
,同时也不会有磁盘的 IO 开销,延长硬盘使用寿命。
因为前面我们已经对webpack-dev-middleware有了了解,所以我们可以很轻松的理解webpack-dev-server的工作原理了。
// webpack有以下配置
output: {
filename: 'bundle.js',
},
- 当我们使用webpack正常打包的时,会将产物生成到配置项
output.path
指定的目录下,比如我们指定的是dist目录,那么打包后的产物就会生成到dist目录下。 - devServer也会将打包产物输出的一个类型
output.path
的目录下,所以我们可以通过http://localhost:8080/bundle.js
来访问打包后的产物。
webpack-dev-server实现原理
有了前面的铺垫,我们就可以很轻松的理解webpack-dev-server的实现原理了。
webpack-dev-server的实现原理,实际就使用 webpack-dev-middleware
中间件来处理 webpack
的打包资源,并且和 express
服务器进行关联。
同时提供一个 socket 服务,将 webpack 编译打包的各个阶段的状态信息告知给客户端,通知网页调用reload
接口刷新页面,从而实现实时重新加载(live reloading)和模块热替换(hot module replacement)功能。
webpack-dev-server配置项
在学习使用webpack-dev-server之前,我们需要讲解几个不好理解的配置项。
static
该配置项用来提供静态资源,默认为public
目录。
假设我们的目录结构如下:
├── css
│ ├── a.css
├── assets
│ ├── b.jpg
├── src
│ └── index.js
├── package.json
└── webpack.config.js
1. 不指定publicPath (默认publicPath为/
),此时我们可以直接访问静态资源,如下:
static: ['assets', 'css'],
// 或
static: {
directory: path.join(__dirname, 'assets'),
},
// 或
static: [
{
directory: path.join(__dirname, 'assets'),
},
{
directory: path.join(__dirname, 'css'),
},
],
这样我们就可以在开发环境下,直接去访问我们配置的静态资源了,如下:
http://localhost:8080/b.jpg
http://localhost:8080/a.css
2. 我们也可以指定publicPath
static: [
{
directory: path.join(__dirname, 'css'),
publicPath: '/css',
},
{
directory: path.join(__dirname, 'assets'),
publicPath: '/assets',
},
],
此时,我们需要拼上publicPath
才能访问到静态资源,如下:
http://localhost:8080/css/a.css
http://localhost:8080/assets/b.jpg
hot
配置hot为true
,开启模块热替换功能。
什么是模块热替换呢?
官方解释,模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。
主要是通过以下几种方式,来显著加快开发速度:
- 保留在完全重新加载页面期间丢失的应用程序状态。
- 只更新变更内容,以节省宝贵的开发时间。
- 在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。
总之,它可以提升我们开发效率,如果不开启,我们每次修改代码,页面都会进行整体刷新,降低我们的开发效率。
proxy
我们项目开发中,经常会遇到跨域的问题,我们可以使用代理的方式来解决跨域问题。
客户端请求->同源服务端A,服务端A->请求服务端B,将响应数据,由服务端A响应给页面
proxy就是使用http-proxy-middleware
这个http代理中间件, 在本地起一个代理服务器,将请求转发到目标服务器上,从而解决跨域问题。
proxy: {
"/bili": { // 以 /bili 开头的请求,会转发到下面的 target 配置
target: "https://api.bilibili.com", // 目标服务器
pathRewrite: {"^/bili" : ""}, // 重写路径
secure: false, // https接口,需要配置这个参数
},
'/api': {
target: 'http://82.25.101.11:8000',
changeOrigin: true, // 将请求头中的host 配置为 target
},
}
接下来,我们的请求就会变成这样:
/bili/user
=>https://api.bilibili.com/user
/api/user
=>http://82.25.101.11:8000/api/user
那为什么要更改请求头中的host呢?
大家都知道,一台服务器上可以部署多个项目,当我们发送请求时,DNS 会将域名解析为 IP 地址,此时,也就确定了我们目标服务器,那如何确定我们要访问的是哪个项目呢?这就需要用到 host 字段了。
请求头中Host用来指定请求的 域名/ip地址
和端口号
,通常用于指定服务器的地址,端口号可以省略,省略时默认为80端口。
此时我们将host指定为a.com
就会访问到淘宝服务了。
所以如果一台服务器上部署多个项目时,我们需要更改请求头中的host,来指定我们要访问的项目。
一台服务器只有一个项目时,我们可以不用更改请求头中的host,因为DNS解析后,就确定了我们要访问的项目。
但为了以后用起来方便,就统一将这个配置项changeOrigin
设置为true。
webpack-dev-server的使用
知其然,知其所以然,接下来,我们看一下webpack-dev-server如何使用吧。
1. 首先我们需要安装webpack-dev-server
npm install webpack-dev-server --save-dev
2.我们需要修改webpack.config.js配置文件,增加devServer配置项
module.exports = {
// ...
devServer: {
// 将public设为静态资源目录
static: {
directory: path.join(__dirname, 'public'),
},
// 开启服务器时,浏览器自动打开页面,也可以配置为['/my-page']打开指定页面
open: true,
// 开启 gzip 压缩
compress: true,
// 自定义端口号,也可以设置为 auto
port: 9000,
// 客户端配置
client: {
// 当出现编译错误或警告时,在浏览器中显示全屏覆盖。
overlay: {
// 日志级别为errors时,浏览器中全屏显示错误信息
errors: true,
// 日志级别为warnings时,不去全屏覆盖,只在控制台中展示
warnings: false,
},
},
// 为所有响应添加 headers:
headers: {
"X-Custom-Foo": "bar"
},
// 默认情况下dev-server使用http协议,通过配置可以支持https,
https: true,
// 注意:默认使用自签名证书,也可以配置自己的证书
// https: {
// ca: './path/to/server.pem',
// pfx: './path/to/server.pfx',
// key: './path/to/server.key',
// cert: './path/to/server.crt',
// passphrase: 'webpack-dev-server',
// requestCert: true,
// },
// 开启热模块替换
hot: true,
// 配置代理
proxy: {
"/bili": { // 以 /bili 开头的请求,会转发到下面的 target 配置
target: "https://api.bilibili.com", // 目标服务器
pathRewrite: {"^/bili" : ""}, // 重写路径
secure: false, // https接口,需要配置这个参数
},
'/api': {
target: 'http://82.25.101.11:8000',
changeOrigin: true, // 将请求头中的host 配置为 target
},
}
}}
3. 在 package.json 中增加启动命令
{
"scripts": {
"start": "webpack serve"
}
}
完结撒花,你又进步了一点点。
ᕦ( •̀∀•́)ᕤ