3-18 使用 Webpack Dev Middleware

1-6 使用 DevServer 中介绍过的 DevServer 是一个方便开发的小型 HTTP 服务器, DevServer 其实是基于 webpack-dev-middlewareExpressjs 实现的, 而 webpack-dev-middleware 其实是 Expressjs 的一个中间件。

也就是说,实现 DevServer 基本功能的代码大致如下:

const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');

// 从 webpack.config.js 文件中读取 Webpack 配置 
const config = require('./webpack.config.js');
// 实例化一个 Expressjs app
const app = express();

// 用读取到的 Webpack 配置实例化一个 Compiler
const compiler = webpack(config);
// 给 app 注册 webpackMiddleware 中间件
app.use(webpackMiddleware(compiler));
// 启动 HTTP 服务器,服务器监听在 3000 端口 
app.listen(3000);

从以上代码可以看出,从 webpack-dev-middleware 中导出的 webpackMiddleware 是一个函数,该函数需要接收一个 Compiler 实例。 在 3-17 通过 Node.js API 启动 Webpack 中曾介绍过 Webpack API 导出的 webpack 函数会返回一个Compiler 实例。

webpackMiddleware 函数的返回结果是一个 Expressjs 的中间件,该中间件有以下功能:

  • 接收来自 Webpack Compiler 实例输出的文件,但不会把文件输出到硬盘,而是保存在内存中;
  • 往 Expressjs app 上注册路由,拦截 HTTP 收到的请求,根据请求路径响应对应的文件内容;

通过 webpack-dev-middleware 能够将 DevServer 集成到你现有的 HTTP 服务器中,让你现有的 HTTP 服务器能返回 Webpack 构建出的内容,而不是在开发时启动多个 HTTP 服务器。 这特别适用于后端接口服务采用 Node.js 编写的项目。

Webpack Dev Middleware 支持的配置项

在 Node.js 中调用 webpack-dev-middleware 提供的 API 时,还可以给它传入一些配置项,方法如下:

// webpackMiddleware 函数的第二个参数为配置项
app.use(webpackMiddleware(compiler, {
    // webpack-dev-middleware 所有支持的配置项
    // 只有 publicPath 属性为必填,其它都是选填项

    // Webpack 输出资源绑定在 HTTP 服务器上的根目录,
    // 和 Webpack 配置中的 publicPath 含义一致 
    publicPath: '/assets/',

    // 不输出 info 类型的日志到控制台,只输出 warn 和 error 类型的日志
    noInfo: false,

    // 不输出任何类型的日志到控制台
    quiet: false,

    // 切换到懒惰模式,这意味着不监听文件变化,只会在请求到时再去编译对应的文件,
    // 这适合页面非常多的项目。
    lazy: true,

    // watchOptions
    // 只在非懒惰模式下才有效
    watchOptions: {
        aggregateTimeout: 300,
        poll: true
    },

    // 默认的 URL 路径, 默认是 'index.html'.
    index: 'index.html',

    // 自定义 HTTP 头
    headers: {'X-Custom-Header': 'yes'},

    // 给特定文件后缀的文件添加 HTTP mimeTypes ,作为文件类型映射表
    mimeTypes: {'text/html': ['phtml']},

    // 统计信息输出样式
    stats: {
        colors: true
    },

    // 自定义输出日志的展示方法
    reporter: null,

    // 开启或关闭服务端渲染
    serverSideRender: false,
}));

Webpack Dev Middleware 与模块热替换

DevServer 提供了一个方便的功能,可以做到在监听到文件发生变化时自动替换网页中的老模块,以做到实时预览。 DevServer 虽然是基于 webpack-dev-middleware 实现的,但 webpack-dev-middleware 并没有实现模块热替换功能,而是 DevServer 自己实现了该功能。

为了在使用 webpack-dev-middleware 时也能使用模块热替换功能去提升开发效率,需要额外的再接入 webpack-hot-middleware。 需要做以下修改才能实现模块热替换。

第2步:修改 webpack.config.js 文件,加入 HotModuleReplacementPlugin 插件,修改如下:

const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');

module.exports = {
  entry: [
    // 为了支持模块热替换,注入代理客户端
    'webpack-hot-middleware/client',
    // JS 执行入口文件
    './src/main.js'
  ],
  output: {
    // 把所有依赖的模块合并输出到一个 bundle.js 文件
    filename: 'bundle.js',
  },
  plugins: [
    // 为了支持模块热替换,生成 .hot-update.json 文件
    new HotModuleReplacementPlugin(),
  ],
  devtool: 'source-map',
};

该修改其实就是相当于完成了在 4-6 开启模块热替换 中提到的 webpack-dev-server --hot 的工作。

第1步:修改 HTTP 服务器代码 server.js 文件,接入 webpack-hot-middleware 中间件,修改如下:

const express = require('express');
const webpack = require('webpack');
const webpackMiddleware = require('webpack-dev-middleware');

// 从 webpack.config.js 文件中读取 Webpack 配置
const config = require('./webpack.config.js');
// 实例化一个 Expressjs app
const app = express();

// 用读取到的 Webpack 配置实例化一个 Compiler
const compiler = webpack(config);
// 给 app 注册 webpackMiddleware 中间件
app.use(webpackMiddleware(compiler));
// 为了支持模块热替换,响应用于替换老模块的资源
app.use(require('webpack-hot-middleware')(compiler));
// 把项目根目录作为静态资源目录,用于服务 HTML 文件
app.use(express.static('.'));
// 启动 HTTP 服务器,服务器监听在 3000 端口
app.listen(3000, () => {
  console.info('成功监听在 3000');
});

第3步:修改执行入口文件 main.js,加入替换逻辑,在文件末尾加入以下代码:

if (module.hot) {
  module.hot.accept();
}

第4步:安装新引入的依赖:

npm i -D webpack-dev-middleware webpack-hot-middleware express

安装成功后,通过 node ./server.js 就能启动一个类似于 DevServer 那样支持模块热替换的自定义 HTTP 服务了。

本实例提供项目完整代码

results matching ""

    No results matching ""