Webpack 生态中的 webpack-dev-server 是前端开发时最常用的本地服务工具之一,它除了提供静态文件访问、热模块替换等基础能力外,还暴露了若干生命周期钩子,允许开发者在服务启动的不同阶段介入处理。devServer.before 就是其中一个非常实用的钩子,它会在服务器内部中间件挂载之前执行,适合用来注册自定义接口、模拟数据响应或进行请求拦截。理解这个钩子的触发时机与参数结构,对于搭建稳定的本地开发环境很有帮助。

devServer.before 的定位与触发时机
webpack-dev-server 内部基于 Express 构建,启动时会将一系列中间件按顺序挂载到 app 上。默认流程里,静态文件中间件(通常由 express.static 实现)会处理来自 contentBase 或 publicPath 的请求,之后才是 historyApiFallback 等逻辑。devServer.before 注册的回调函数位于这些默认中间件之前,也就是说,当浏览器发起请求时,如果 before 中定义了匹配的路由,该路由会优先响应,不会继续进入静态资源处理流程。这个特性让开发者可以像编写后端接口一样在开发服务器上定制响应。
需要注意 before 并不是一个独立运行的进程,它只是 webpack-dev-server 在调用 app.listen 之前同步或异步执行的一段初始化代码。服务还没有真正监听端口,但 app 实例已经创建完毕,因此可以放心地注册路由和中间件。由于执行时机早,before 中无法访问到已经启动的 server 对象,不过回调函数会通过参数把 server 传进来,方便读取或扩展服务器实例。
如何配置 devServer.before
在 webpack.config.js 中,devServer.before 接受一个函数,函数签名有三个参数:app、server、compiler。app 是 Express 应用实例,可以直接使用 app.use、app.get、app.post 等方法;server 是 Node.js 的 http.Server 实例,可以监听 upgrade 事件来实现 WebSocket 逻辑;compiler 是 webpack 编译器,可以通过 compiler.hooks.done 监听编译完成。
下面是一个基础配置示例,它在 before 中注册了一个返回 JSON 数据的接口:
module.exports = {
devServer: {
before(app, server, compiler) {
app.get('/api/status', function(req, res) {
res.json({ status: 'ok', time: Date.now() });
});
}
}
};
如果希望使用异步逻辑,可以在 before 函数内返回 Promise,webpack-dev-server 会等待 Promise 完成后再继续启动服务。但版本不同支持程度有差异,官方文档建议尽量保持同步执行,异步任务可以在 done 钩子中处理。
典型场景:本地 mock 与请求拦截
before 最常见的用途是搭建本地 mock 服务。前端开发时后端接口往往尚未就绪,借助 before 可以在不额外启动 Node 服务的情况下,直接在 devServer 中返回模拟数据。例如登录接口、列表接口都可以在 before 中快速注册,数据可以硬编码,也可以从本地 JSON 文件读取。
const fs = require('fs');
const path = require('path');
module.exports = {
devServer: {
before(app) {
app.get('/api/user/list', function(req, res) {
const data = JSON.parse(
fs.readFileSync(path.resolve(__dirname, 'mock/users.json'), 'utf8')
);
res.json(data);
});
app.post('/api/login', function(req, res) {
res.json({ token: 'mock-token-123' });
});
}
}
};
此外 before 还可以做请求拦截和改写。由于它位于静态资源中间件之前,可以检查请求头、URL 参数,对不符合条件的请求直接返回 401 或重定向,从而模拟登录鉴权、权限控制等行为。比如判断请求 /admin 路径时是否携带特定 cookie,没有则返回 403,这样前端就能提前发现权限相关逻辑问题。
不过 before 只适合处理开发环境逻辑,生产环境不会经过 devServer,因此涉及真实鉴权、数据持久化等能力时应依然以后端服务为准。
与 after、setupMiddlewares 的关系及版本差异
webpack-dev-server 除了 before 还提供了 after 钩子,after 在所有默认中间件之后执行,适用于对最终响应进行统一处理,比如添加响应头、记录请求日志。before 与 after 的差异在于执行顺序:before 先于静态文件处理,after 后于静态文件处理。如果一个请求同时满足 before 中的路由和静态文件路径,before 会优先命中,因此需要小心避免无意中覆盖了静态资源。
在 webpack-dev-server 4.x 版本中,before 和 after 已经被标记为废弃,推荐使用 setupMiddlewares 来直接操作中间件数组。setupMiddlewares 接收一个中间件数组并返回修改后的数组,允许在指定位置插入自定义中间件。例如:
module.exports = {
devServer: {
setupMiddlewares(middlewares, devServer) {
middlewares.unshift({
name: 'custom-api',
path: '/api',
middleware(req, res) {
res.json({ custom: true });
}
});
return middlewares;
}
}
};
虽然新写法更加直观和灵活,但不少企业项目仍在使用 webpack-dev-server 3.x 以及 before 钩子,因此理解 before 的原理和用法仍然有必要。升级时需要关注官方迁移指南,将 before 中的逻辑改写为 setupMiddlewares 中的中间件对象形式。
Webpack devServer.before中间件服务启动前修改时间:2026-09-17 02:11:23