阅读(3952) (0)

Webpack:Node 接口

2023-05-09 11:06:19 更新

Webpack 提供了 Node.js API,可以在 Node.js 运行时下直接使用。

当你需要自定义构建或开发流程时,Node.js API 非常有用,因为此时所有的报告和错误处理都必须自行实现,webpack 仅仅负责编译的部分。所以 stats 配置选项不会在 webpack() 调用中生效。

安装(Installation)

开始使用 webpack 的 Node.js API 之前,首先你需要安装 webpack:

npm install --save-dev webpack

在 Node.js 文件中,引入 webpack 模块:

const webpack = require('webpack');

或者如果你更喜欢 ES2015:

import webpack from 'webpack';

webpack()

导入的 webpack 函数会将 配置对象 传给 webpack,如果同时传入回调函数会在 webpack compiler 运行时被执行:

const webpack = require('webpack');

webpack({}, (err, stats) => {
  if (err || stats.hasErrors()) {
    // ...
  }
  // 处理完成
});

Compiler 实例(Compiler Instance)

如果你不向 webpack 传入可执行的回调函数, 它会返回一个 webpack Compiler 实例。 你可以通过手动执行它或者为它的构建时添加一个监听器, 就像 CLI 类似。Compiler 实例提供了以下方法:

  • .run(callback)
  • .watch(watchOptions, handler)

通常情况下,仅会创建一个主要 Compiler 实例, 虽然可以创建一些子 compiler 来代理到特定任务。 Compiler 基本上只是执行最低限度的功能,以维持生命周期运行的功能。 它将所有的加载、打包和写入工作, 都委托到注册过的插件上。

Compiler 实例上的 hooks 属性,用于将一个插件注册 到 Compiler 的生命周期中的所有钩子事件上。webpack 使用 WebpackOptionsDefaulter 和 WebpackOptionsApply 来配置 Compiler 实例以及所有内置插件。

使用 run 方法启动所有编译工作。 完成之后,执行传入的的 callback 函数。 最终记录下来的概括信息(stats)和错误(errors),都应在这个 callback 函数中获取。

执行(Run)

调用 Compiler 实例的 run 方法跟上文提到的 快速执行方法很类似:

const webpack = require('webpack');

const compiler = webpack({
  // ...
});

compiler.run((err, stats) => {
  // ...

  compiler.close((closeErr) => {
    // ...
  });
});

监听(Watching)

调用 watch 方法会触发 webpack 执行,但之后会监听变更(很像 CLI 命令: webpack --watch), 一旦 webpack 检测到文件变更,就会重新执行编译。 该方法返回一个 Watching 实例。

watch(watchOptions, callback);
const webpack = require('webpack');

const compiler = webpack({
  // ...
});

const watching = compiler.watch(
  {
    // 示例
    aggregateTimeout: 300,
    poll: undefined,
  },
  (err, stats) => {
    // 这里打印 watch/build 结果...
    console.log(stats);
  }
);

关闭 Watching (Close Watching)

watch 方法返回一个 Watching 实例,该实例会暴露一个 .close(callback) 方法。 调用该方法将会结束监听:

watching.close((closeErr) => {
  console.log('Watching Ended.');
});

Invalidate Watching

使用 watching.invalidate,你可以手动使当前编译循环(compiling round)无效, 而不会停止监听进程(process):

watching.invalidate();

Stats 对象(Stats Object)

stats 对象会被作为 webpack() 回调函数的第二个参数传递, 可以通过它获取到代码编译过程中的有用信息, 包括:

  • 错误和警告(如果有的话)
  • 计时信息
  • module 和 chunk 信息

webpack CLI 正是基于这些信息在控制台 展示友好的格式输出。

stats 对象暴露了以下方法:

stats.hasErrors()

可以用来检查编译期是否有错误, 返回值为 true 或 false。

stats.hasWarnings()

可以用来检查编译期是否有警告, 返回值为 true 或 false。

stats.toJson(options)

以 JSON 对象形式返回编译信息。 options 可以是一个字符串(预设值)或是颗粒化控制的对象:

stats.toJson('minimal');
stats.toJson({
  assets: false,
  hash: true,
});

所有可用的配置选项和预设值都可查询 stats 文档。

stats.toString(options)

以格式化的字符串形式返回描述编译信息 (类似 CLI 的输出)。

配置对象与 stats.toJson(options) 一致,除了额外增加的一个选项:

stats.toString({
  // 增加控制台颜色开关
  colors: true,
});

下面是 stats.toString() 用法的示例:

const webpack = require('webpack');

webpack(
  {
    // ...
  },
  (err, stats) => {
    if (err) {
      console.error(err);
      return;
    }

    console.log(
      stats.toString({
        chunks: false, // 使构建过程更静默无输出
        colors: true,  // 在控制台展示颜色
      })
    );
  }
);

MultiCompiler

MultiCompiler 模块可以让 webpack 同时执行多个配置。 如果传给 webpack 的 Node.js API 的 options 参数, 该参数由是由多个配置对象构成的数组,webpack 会相应地创建多个 compiler 实例, 并且在所有 compiler 执行完毕后调用 callback 方法。

var webpack = require('webpack');

webpack(
  [
    { entry: './index1.js', output: { filename: 'bundle1.js' } },
    { entry: './index2.js', output: { filename: 'bundle2.js' } },
  ],
  (err, stats) => {
    process.stdout.write(stats.toString() + '\n');
  }
);

错误处理(Error Handling)

完备的错误处理中需要考虑以下三种类型的错误:

  • 致命的 wepback 错误(配置出错等)
  • 编译错误(缺失的 module,语法错误等)
  • 编译警告

下面是一个覆盖这些场景的示例:

const webpack = require('webpack');

webpack(
  {
    // ...
  },
  (err, stats) => {
    if (err) {
      console.error(err.stack || err);
      if (err.details) {
        console.error(err.details);
      }
      return;
    }

    const info = stats.toJson();

    if (stats.hasErrors()) {
      console.error(info.errors);
    }

    if (stats.hasWarnings()) {
      console.warn(info.warnings);
    }

    // Log result...
  }
);

自定义文件系统(Custom File Systems)

默认情况下,webpack 使用普通文件系统来读取文件并将文件写入磁盘。 但是,还可以使用不同类型的文件系统(内存(memory), webDAV 等)来更改输入或输出行为。 为了实现这一点, 可以改变 inputFileSystem 或 outputFileSystem。 例如,可以使用 memfs 替换默认的 outputFileSystem, 以将文件写入到内存中, 而不是写入到磁盘:

const { createFsFromVolume, Volume } = require('memfs');
const webpack = require('webpack');

const fs = createFsFromVolume(new Volume());
const compiler = webpack({
  /* options */
});

compiler.outputFileSystem = fs;
compiler.run((err, stats) => {
  // 之后读取输出:
  const content = fs.readFileSync('...');
  compiler.close((closeErr) => {
    // ...
  });
});

值得一提的是,被 webpack-dev-server 及众多其他包依赖的 webpack-dev-middleware 就是通过这种方式, 将你的文件神秘地隐藏起来,但却仍然可以用它们为浏览器提供服务!