Webpack Dev Server 本地开发服务

851 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

webpack-dev-server 是一个基于 Express 的本地开发服务器。它使用 webpack-dev-middleware 中间件来为通过 Webpack 打包生成的资源文件提供 Web 服务。它还有一个通过 Socket IO 连接着 webpack-dev-server 服务器的小型运行时程序。webpack-dev-server 发送关于编译状态的消息到客户端,客户端根据消息作出响应。

基本配置

webpack-dev-server 被 Webpack 作为内置插件对外提供,这样可以直接在对应的 Webpack 配置文件中通过devServer这个属性的配置来配置自己的webpack-dev-serverwebpack-dev-server 的配置文件参考webpack-devServer

// package.json
"scripts": {
    "dev": "webpack serve"
}

// webpack.config.js
const path = require('path');

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

下面对一些重要配置项进行简单说明:

  • https: true: devServer默认是通过http发送请求,如果你想使用https需要进行设置。
  • hot: true: 模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面。
  • open: true: 当启动时直接打开默认浏览器
  • compress: true: 服务开启 Gzip 压缩
  • host: '0.0.0.0': 使用0.0.0.0可以让局域网内可访问

proxy

在实际开发中,本地开发服务器是不能直接请求线上数据接口的,这是因为浏览器的同源安全策略导致的跨域问题,我们可以使用devServer.proxy来解决本地开发跨域的问题。

下面的配置是将页面访问的/api所有请求都转发到了baidu.com上:

module.exports = {
    //...
    devServer: {
        proxy: {
            '/api': 'http://baidu.com'
        }
    }
};

那么,我们请求/api/users则会被转发到http://baidu.com/api/users线上地址。

devServer.proxy的值还支持高级属性,通过高级属性我们可以做更多的事情,如上面的需求变成,将/api/users转发到 baidu.com/users, 那么配置就需要改成:

module.exports = {
    //...
    devServer: {
        proxy: {
            '/api': {
                target: 'http://baidu.com',
                pathRewrite: {'^/api': ''}
            }
        }
    }
};

如果我们需要转发的网站是支持 https 的,那么需要增加secure=false,来防止转发失败:

secure: false

又有新的需求了,这时候只能代理json接口的数据,对于html文件,还是使用打包后 dist 文件夹中文件,那么我们使用bypass(绕过)来实现这个需求:

module.exports = {
    //...
    devServer: {
        proxy: {
            '/api': {
                target: 'http://baidu.com',
                bypass(req, res, proxyOptions) {
                    // 判断请求头中的 accept 值
                    if (req.headers.accept.indexOf('html') !== -1) {
                        console.log('Skipping proxy for browser request.');
                        // 返回的是 contentBase 的路径
                        return '/index.html';
                    }
                }
            }
        }
    }
};

函数返回值:

  • 如果返回null or undefined,说明还是走正常的代理
  • 如果返回 false,将直接返回404的错误,结束代理
  • 如果返回一个路径(return '/index.html'),说明代理结束,不会走后面的代理逻辑

自定义中间件

在 webpack-dev-server 中有两个时机可以插入自己实现的中间件,分别是在devServer.beforedevServer.after两个时机,即 webpack-dev-server 加载所有内部中间件之前和之后两个时机。

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

自定义中间件在开发中常常被用来当作 mock server 使用。

mock server 现在的前端团队一般都会采取前后端分离的开发模式,这样可以做到前后端同时并行开发,而前端同学开发的时候需要依赖后端同学提供的数据接口,后端同学的数据接口没有开发完成的时候,前端不能傻傻的等着,所以这就需要一个 mock server 来根据前后端接口的约定格式伪造一些假数据,这样前端开发就可以继续下去,加快开发进度。

webpack-dev-server 提供了自定义中间件的 Hook,所以我们可以很简单的实现自己的 mock server。下面代码是在devServer.before插入一个接口/api/mock.json的接口响应:

module.exports = {
    //...
    devServer: {
        port: 9000,
        before(app, server) {
            app.get('/api/mock.json', (req, res) => {
                res.json({hello: 'world'});
            });
        }
    }
};

启动 dev server,访问 http://localhost:9000/api/mock.json就可以看到这个接口返回的数据了。