参考链接

webpack-dev-serverwebpack 提供实时重载的开发服务器,它仅适用于开发环境。

它使用 webpack-dev-middleware 对 webpack 相关资源进行快速内存访问。

起步

首先,安装模块

1
npm install webpack-dev-server --save-dev

Note: 虽然你可以进行全局安装,但我们推荐你工程本地安装。webpack-dev-server 将始终使用本地的安装而非全局。

使用

以下是两种推荐的使用方法:

使用命令行

webpack.config.js 所在的目录中,运行

1
node_modules/.bin/webpack-dev-server

NPM Scripts

可在 package.json 中进行如下简单定义:

1
2
3
"scripts": {
"start:dev": "webpack-dev-server"
}

在终端中运行

1
npm run start:dev

devServer: object

devServer 这组选项会被 webpack-dev-server 获取,下面是一个简单例子:

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

var path = require('path');

module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000
}
};

devServer.after: function (app, server)

此选项提供自定义中间件,在其他中间件执行完毕后执行。

1
2
3
4
5
6
7
8
9
10
// webpack.config.js

module.exports = {
//...
devServer: {
after: function(app, server) {
// do fancy stuff
}
}
};

devServer.allowedHosts: array

你可以在这个选项中列出 devServer 的白名单

1
2
3
4
5
6
7
8
9
10
11
12
13
// webpack.config.js

module.exports = {
//...
devServer: {
allowedHosts: [
'host.com',
'subdomain.host.com',
'subdomain2.host.com',
'host2.com'
]
}
};

模仿 djangoALLOWED_HOSTS,以 . 开头的的字段相当于通配符子域名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// webpack.config.js

module.exports = {
//...
devServer: {
// this achieves the same effect as the first example
// with the bonus of not having to update your config
// if new subdomains need to access the dev server
allowedHosts: [
'.host.com',
'host2.com'
]
}
};

在命令行中可通过 --allowed-hosts 使用此选项

1
2
3
webpack-dev-server --entry /entry/file \
--output-path /output/path \
--allowed-hosts .host.com,host2.com

devServer.before: function (app, server)

此选项提供自定义中间件,在其他中间件执行前执行。

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

module.exports = {
//...
devServer: {
before: function(app, server) {
app.get('/some/path', function(req, res) {
res.json({ custom: 'response' });
});
}
}
};

devServer.bonjour: boolean

此选项在启动时通过 ZeroConf 网络广播服务器。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
bonjour: true
}
};

通过命令行使用

1
webpack-dev-server --bonjour

devServer.clientLogLevel: string

string: 'none' | 'info' | 'error' | 'warning'

使用内联模式时,DevTools 中的控制台将显示此消息;例如在重新加载之前,错误抛出之前,模块热替换启用时。默认设置为 info

devServer.clientLogLevel 可能过于冗长,可以通过设置为 none 来关闭日志。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
clientLogLevel: 'none'
}
};

在命令行中使用

1
webpack-dev-server --client-log-level none

devServer.color: boolean

仅适用于命令行,在控制台中启用/禁用颜色。

1
webpack-dev-server --color

devServer.compress: boolean

启用 gzip 压缩

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
compress: true
}
};

通过命令行使用

1
webpack-dev-server --compress

devServer.contentBase: mixed

boolean: false string [string] number

告诉服务器从何处提供内容。只有在你希望提供静态文件时才需要这样做。devServer.publicPath 将用于决定 bundle 从何处提供服务,并具有优先权。

建议使用绝对路径。

默认使用当前工作目录来提供内容。若要禁用 contentBase,将其设置为 false

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
contentBase: path.join(__dirname, 'public')
}
};

也可以从多个目录提供服务:

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
contentBase: [path.join(__dirname, 'public'), path.join(__dirname, 'assets')]
}
};

通过命令行使用

1
webpack-dev-server --content-base /path/to/content/dir

devServer.disableHostCheck: boolean

设置为 true 时,此选项将绕过主机检查。不推荐这么做,因为不检查主机的应用很容易受到 DNS重新绑定攻击

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
disableHostCheck: true
}
};

通过命令行使用

1
webpack-dev-server --disable-host-check

devServer.filename: string

此选项允许你在惰性模式下减少编译。在惰性模式下,默认每个请求都会导致一个新的编译。使用 filename,在某个特定文件被请求时才发生编译。

output.filename 被设置为 bundle.jsdevServer.filename 则会进行如下设置:

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

module.exports = {
//...
output: {
filename: 'bundle.js'
},
devServer: {
lazy: true,
filename: 'bundle.js'
}
};

这样,它只在 /bundle.js 被请求时编译 bundle。

在非惰性模式下,filename 没有作用。

devServer.headers: object

对所有响应添加 headers

1
2
3
4
5
6
7
8
9
10
// webpack.config.js

module.exports = {
//...
devServer: {
headers: {
'X-Custom-Foo': 'bar'
}
}
};

devServer.historyApiFallback: mixed

boolean object

使用 HTML5 History API 时,index.html 页面可能代替任何 404 响应。默认情况下 devServer.historyApiFallback 被禁用。通过如下设置启用:

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
historyApiFallback: true
}
};

可通过 rewrites 选项进一步控制其表现:

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
//...
devServer: {
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' }
]
}
}
};

若在路径中使用点(与 Angular 相同),可能需要使用 disableDotRule

1
2
3
4
5
6
7
8
module.exports = {
//...
devServer: {
historyApiFallback: {
disableDotRule: true
}
}
};

通过命令行使用

1
webpack-dev-server --history-api-fallback

更多信息参见 connect-history-api-fallback

devServer.host: string

指定要使用的主机。默认为 localhost。如果你希望你的服务器可以从外部访问,可以这么指定:

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
host: '0.0.0.0'
}
};

通过命令行使用

1
webpack-dev-server --host 0.0.0.0

devServer.hot: boolean

启用 webpack 的 模块热替换 功能。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
hot: true
}
};

完全开启 HMR 需要 webpack.HotModuleReplacementPlugin。若 webpackwebpack-dev-server 启动时使用 --hot 选项,就会自动加载此插件,因此你可能不需要将它添加到 webpack.config.js。更多信息参见 HMR concepts page

devServer.hotOnly: boolean

启用热模块替换,在构建失败时不刷新界面。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
hotOnly: true
}
};

通过命令行使用

1
webpack-dev-server --hot-only

devServer.https: mixed

boolean object

默认情况下,dev-server 将通过 HTTP 提供服务。它可以通过 HTTP/2 和 HTTPS 提供服务:

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
https: true
}
};

使用上述配置,你可以使用自签名证书,

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

module.exports = {
//...
devServer: {
https: {
key: fs.readFileSync('/path/to/server.key'),
cert: fs.readFileSync('/path/to/server.crt'),
ca: fs.readFileSync('/path/to/ca.pem'),
}
}
};

此对象直接传递到 Node.js HTTPS 模块,更多信息参见 HTTPS documentation

通过命令行使用

1
webpack-dev-server --https

要通过命令行传递证书,使用如下选项

1
webpack-dev-server --https --key /path/to/server.key --cert /path/to/server.crt --cacert /path/to/ca.pem

devServer.index: string

index 文件

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
index: 'index.html'
}
};

devServer.info: boolean

命令行信息输出。默认启用。

1
webpack-dev-server --info=false

devServer.inline: boolean

切换 devServer 的两种不同模式。默认情况下,应用将启用内联模式。这意味着将在 bundle 中插入一个脚本来处理实时重载,构建消息将出现在浏览器控制台。

可以使用 iframe 模式,该模式在一个通知栏下使用一个包含构建消息的 <iframe>。切换到 iframe 模式:

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
inline: false
}
};

通过命令行使用

1
webpack-dev-server --inline=false

建议使用内联模式进行模块热替换,因为它包含来自 websocket 的 HMR 触发器。可以使用轮询模式作为替代,但需要额外的入口点,webpack/hot/poll?1000

devServer.lazy: boolean

devServer.lazy 启用时,devServer 只在收到请求时编译 bundle。这意味着 webpack 不会监视任何文件修改。我们称之为惰性模式。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
lazy: true
}
};

通过命令行使用

1
webpack-dev-server --lazy

使用惰性模式时,watchOptions 将不起作用

通过命令行使用时,请确保内联模式被禁用

devServer.noInfo: boolean

告诉 devServer 抑制 webpack 包信息之类的信息。错误和警告仍然会显示。devServer.noInfo 默认禁用。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
noInfo: true
}
};

devServer.open: mixed

boolean string

告诉 devServer 在启动后打开浏览器。默认禁用。

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
open: true
}
};

如果没有提供浏览器(如上面代码所示),将使用模式浏览器。可通过传递浏览器名称去指定不同的浏览器:

1
2
3
4
5
6
module.exports = {
//...
devServer: {
open: 'Google Chrome'
}
};

通过命令行使用

1
webpack-dev-server --open

指定浏览器

1
2
3
4
5
6
7
8
// webpack.config.js

module.exports = {
//...
devServer: {
open: 'Chrome'
}
};

通过命令行使用

1
webpack-dev-server --open 'Chrome'

浏览器应用名依赖于平台。不要在可重用模块中硬编码它。例如,Google Chrome 在 macOS 上是 'Chrome',在 Linux 上是 'google-chrome',在 Windows 上是 'chrome'

devServer.openPage: [string]

指定打开浏览器时要导航到的页面。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
openPage: '/different/page'
}
};

通过命令行使用

1
webpack-dev-server --open-page "/different/page"

devServer.overlay: mixed

boolean object: { boolean errors, boolean warnings }

当存在编译器错误或警告时,在浏览器中全屏覆盖。默认禁用。如果只想展示编译错误,如下设置:

1
2
3
4
5
6
module.exports = {
//...
devServer: {
overlay: true
}
};

如果想显示警告和错误,如下设置:

1
2
3
4
5
6
7
8
9
module.exports = {
//...
devServer: {
overlay: {
warnings: true,
errors: true
}
}
};

devServer.pfx: string

通过命令行使用时,指定 SSL .pfx 文件路径。若在选项中使用,它应该是 .pfx 文件的字节流。 ??

1
2
3
4
5
6
module.exports = {
//...
devServer: {
pfx: '/path/to/file.pfx'
}
};

通过命令行使用

1
webpack-dev-server --pfx /path/to/file.pfx

devServer.pfxPassphrase: string

SSL .pfx 文件密码

1
2
3
4
5
6
module.exports = {
//...
devServer: {
pfxPassphrase: 'passphrase'
}
};

通过命令行使用

1
webpack-dev-server --pfx-passphrase passphrase

devServer.port: number

指定监听请求的端口号:

module.exports = {
//…
devServer: {
port: 8080
}
};

通过命令行使用

1
webpack-dev-server --port 8080

devServer.proxy: mixed

object [object, function]

当你有一个独立的 API 后端服务器,并且希望在同域中发送 API 请求时,代理一些 URL 非常有用。

devServer 使用 http-proxy-middleware。查看其 文档 了解更多高级用法。http-proxy-middleware 的一些功能并不需要 target key,例如 router,但你仍然需要在这里配置一个 target key,否则 webpack-dev-server 不会将它传递给 http-proxy-middleware

例如,后端服务为 localhost:3000,可作如下设置:

1
2
3
4
5
6
7
8
module.exports = {
//...
devServer: {
proxy: {
'/api': 'http://localhost:3000'
}
}
};

/api/users 的请求将代理到 http://localhost:3000/api/users

如果不想 /api 被传递,需要重写路径:

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {'^/api' : ''}
}
}
}
};

缺省情况下,运行在 HTTPS 上且证书无效的后端服务器将不被接受。如果你需要它生效,可以进行如下修改:

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
secure: false
}
}
}
};

有时候你不想代理所有的东西,可以根据函数的返回值绕过代理。

在该函数中,你可以访问请求、响应和代理选项。它必须返回 false 或服务路径,而不是继续代理请求。

例如,对于浏览器请求,你想要提供 HTML 页面,但对于 API 请求,你想要代理它。你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
bypass: function(req, res, proxyOptions) {
if (req.headers.accept.indexOf('html') !== -1) {
console.log('Skipping proxy for browser request.');
return '/index.html';
}
}
}
}
}
};

如果你想代理多个特定路径到同一目标:

1
2
3
4
5
6
7
8
9
module.exports = {
//...
devServer: {
proxy: [{
context: ['/auth', '/api'],
target: 'http://localhost:3000',
}]
}
};

默认情况下,根路径请求不会被代理。要启用根路径代理,devServer.index 选项应该制定一个伪值:

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
//...
devServer: {
index: '', // specify to enable root proxying
host: '...',
contentBase: '...',
proxy: {
context: () => true,
target: 'http://localhost:1234'
}
}
};

默认情况下,代理时 host header 中的 origin 会被保留,你可以将 changeOrigin 设置为 true 去覆盖此行为。它在某些情况下很有用,例如 name-based virtual hosted sites

1
2
3
4
5
6
7
8
9
module.exports = {
//...
devServer: {
proxy: {
'/api': 'http://localhost:3000',
changeOrigin: true
}
}
};

devServer.progress: string

输出运行进度到控制台

1
webpack-dev-server --progress

devServer.public: string

使用内联模式并代理 devServer 时,内联客户端脚本并不总是知道要连接到哪里。它将根据 window.location 猜测服务器的 URL,如果失败,你需要使用这个。

例如,devServer 由 nginx 代理,在 myapp.test 上可用。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
public: 'myapp.test:80'
}
};

通过命令行使用

1
webpack-dev-server --public myapp.test:80

devServer.publicPath: string

绑定的文件将在此路径下的浏览器中可用。

假设服务器在 http://localhost:8080 下运行,output.filename 设置为 bundle.js。默认的 devServer.publicPath/,bundle 的地址为 http://localhost:8080/bundle.js

修改 devServer.publicPath 指定特定目录:

1
2
3
4
5
6
module.exports = {
//...
devServer: {
publicPath: '/assets/'
}
};

此时 bundle 的有效访问地址为 http://localhost:8080/assets/bundle.js

确保 devServer.publicPath 总是以 / 结束

也可以使用完整的 URL。这对于模块热替换是必要的。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
publicPath: 'http://localhost:8080/assets/'
}
};

此时 bundle 的有效访问地址为 http://localhost:8080/assets/bundle.js

建议将 devServer.publicPathoutput.publicPath 作相同的设置。

devServer.quiet: boolean

devServer.quiet 启用时,除初始启动信息外,什么都不会写入控制台。这也意味着来自 webpack 的错误或警告是不可见的。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
quiet: true
}
};

通过命令行使用

1
webpack-dev-server --quiet

devServer.socket: string

要监听的 Unix socket

1
2
3
4
5
6
module.exports = {
//...
devServer: {
socket: 'socket'
}
};

通过命令行使用

1
webpack-dev-server --socket socket

devServer.staticOptions

可以为 contentBase 中的静态文件配置高级选项。相关选项参见 Express documentation

1
2
3
4
5
6
7
8
module.exports = {
//...
devServer: {
staticOptions: {
redirect: false
}
}
};

devServer.contentBase 为字符串时选项才会生效

devServer.stats: mixed

string: 'none' | 'errors-only' | 'minimal' | 'normal' | 'verbose' object

此选项允许你精确地控制显示哪些 bundle 信息。如果你想要某些 bundle 信息而非所有,这是个不错的中间地带。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
stats: 'errors-only'
}
};

更多信息参见 stats documentation

quiet 或 noInfo 模式下该选项无效

devServer.stdin: boolean

在 stdin 结束时关闭服务器

1
webpack-dev-server --stdin

devServer.useLocalIp: boolean

此选项允许浏览器使用本地 IP 打开。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
useLocalIp: true
}
};

通过命令行使用

1
webpack-dev-server --useLocalIp

devServer.watchContentBase: boolean

告诉 devServer 观察 devServer.contentBase 选项提供的文件。默认禁用。弃用时,文件更改将触发重新加载整个界面。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
watchContentBase: true
}
};

通过命令行使用

1
webpack-dev-server --watch-content-base

devServer.watchOptions: object

观察文件相关的控件选项。

webpack 使用文件系统获得文件更改的通知。在某些情况下,这是行不通的。例如,在使用网络文件系统(NFS)时。Vagrant 在这方面也有很多问题。这些情况下,使用轮询。

1
2
3
4
5
6
7
8
module.exports = {
//...
devServer: {
watchOptions: {
poll: true
}
}
};

如果这对文件系统来说太重,可以将其改为整数,以毫秒为间隔单位。

更多选项参见 WatchOptions

devServer.writeToDisk: mixed

boolean: false function (filePath)

告诉 devServer 将生成的资源输出的磁盘。

1
2
3
4
5
6
module.exports = {
//...
devServer: {
writeToDisk: true
}
};

devServer.writeToDisk 提供一个函数用于过滤。该函数遵循与 Array#filter 相同的前提,其中返回布尔值告诉是否应该将文件写入磁盘。

1
2
3
4
5
6
7
8
module.exports = {
//...
devServer: {
writeToDisk: (filePath) => {
return /superman\.css$/.test(filePath);
}
}
};