Node.js API

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

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

安装(Installation)

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

  1. npm install --save-dev webpack

然后在 Node.js 脚本中 require webpack module:

  1. const webpack = require('webpack');

或者如果你喜欢 ES2015:

  1. import webpack from 'webpack';

webpack()

导入的 webpack 函数需要传入一个 webpack 配置对象,当同时传入回调函数时就会执行 webpack compiler:

  1. const webpack = require("webpack");
  2. webpack({
  3. // 配置对象
  4. }, (err, stats) => {
  5. if (err || stats.hasErrors()) {
  6. // 在这里处理错误
  7. }
  8. // 处理完成
  9. });

编译错误err 对象内,而是需要使用 stats.hasErrors() 单独处理,你可以在指南的 错误处理 部分查阅到更多细节。err 对象只会包含 webpack 相关的问题,比如配置错误等。

你可以向 webpack 函数提供一个由配置选项对象构成的数组。更多详细信息,请查看 MultiCompiler 章节。

Compiler 实例(Compiler Instance)

如果你不向 webpack 执行函数传入回调函数,就会得到一个 webpack Compiler 实例。你可以通过它手动触发 webpack 执行器,或者是让它执行构建并监听变更。和 CLI API 很类似。Compiler 实例提供了以下方法:

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

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

Compiler 实例上的 hooks 属性,用于将一个插件,注册到 Compiler 的生命周期中的所有钩子事件上。webpack 使用 [WebpackOptionsDefaulter] (https://github.com/webpack/webpack/blob/master/lib/WebpackOptionsDefaulter.js) 和 WebpackOptionsApply 这两个工具,通过所有内置插件,来配置 Compiler 实例。

run 方法用于触发所有编译时工作。完成之后,执行给定的 callback 函数。最终记录下来的概括信息(stats)和错误(errors),应该在这个 callback 函数中获取。

这个 API 一次只支持一个并发编译。当使用 run 时,会等待它完成后,然后才能再次调用 runwatch。当使用 watch 时,调用 close,等待它完成后,然后才能再次调用 runwatch。多个并发编译会损坏输出文件。

执行(run)

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

  1. const webpack = require("webpack");
  2. const compiler = webpack({
  3. // 配置对象
  4. });
  5. compiler.run((err, stats) => {
  6. // ...
  7. });

监听(watching)

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

  1. watch(watchOptions, callback);
  1. const webpack = require("webpack");
  2. const compiler = webpack({
  3. // 配置对象
  4. });
  5. const watching = compiler.watch({
  6. // watchOptions 示例
  7. aggregateTimeout: 300,
  8. poll: undefined
  9. }, (err, stats) => {
  10. // 在这里打印 watch/build 结果...
  11. console.log(stats);
  12. });

Watching 配置选项的细节可以在 这里 查阅。

文件系统不正确的问题,可能会对单次修改触发多次构建。因此,在上面的示例中,一次修改可能会多次触发 console.log 语句。用户应该预知此行为,并且可能需要检查 stats.hash 来查看文件哈希是否确实变更。-

关闭 Watching(Close Watching)

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

  1. watching.close(() => {
  2. console.log('Watching Ended.');
  3. });

不允许在当前监听器已经关闭或失效前再次监听或执行。

作废 Watching(Invalidate Watching)

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

  1. watching.invalidate();

Stats 对象(Stats Object)

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

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

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

当使用 MultiCompiler 时,会返回一个 MultiStats 实例,它实现与 stats 相同的接口,也就是下面描述的方法。

stats 对象暴露了以下方法:

stats.hasErrors()

可以用来检查编译期是否有错误,返回 truefalse

stats.hasWarnings()

可以用来检查编译期是否有警告,返回 truefalse

stats.toJson(options)

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

  1. stats.toJson("minimal"); // 更多选项如: "verbose" 等.
  1. stats.toJson({
  2. assets: false,
  3. hash: true
  4. });

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

这里有一个该函数输出的 示例

stats.toString(options)

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

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

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

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

  1. const webpack = require("webpack");
  2. webpack({
  3. // 配置对象
  4. }, (err, stats) => {
  5. if (err) {
  6. console.error(err);
  7. return;
  8. }
  9. console.log(stats.toString({
  10. chunks: false, // 使构建过程更静默无输出
  11. colors: true // 在控制台展示颜色
  12. }));
  13. });

MultiCompiler

MultiCompiler 模块可以让 webpack 在单个 compiler 中执行多个配置。如果传给 webpack 的 Node.js API 的 options 参数,是一个由配置对象构成的数组,则 webpack 会应用单独 compiler,并且在每次 compiler 执行结束时,都会调用 callback 方法。

  1. var webpack = require('webpack');
  2. webpack([
  3. { entry: './index1.js', output: { filename: 'bundle1.js' } },
  4. { entry: './index2.js', output: { filename: 'bundle2.js' } }
  5. ], (err, stats) => {
  6. process.stdout.write(stats.toString() + "\n");
  7. })

多个配置对象在执行时,不会并行执行。每个配置都只会在前一个处理结束后,才进行处理。想要并行处理,你可以使用第三方解决方案,例如 parallel-webpack

错误处理(error handling)

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

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

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

  1. const webpack = require("webpack");
  2. webpack({
  3. // 配置对象
  4. }, (err, stats) => {
  5. if (err) {
  6. console.error(err.stack || err);
  7. if (err.details) {
  8. console.error(err.details);
  9. }
  10. return;
  11. }
  12. const info = stats.toJson();
  13. if (stats.hasErrors()) {
  14. console.error(info.errors);
  15. }
  16. if (stats.hasWarnings()) {
  17. console.warn(info.warnings);
  18. }
  19. // 记录结果...
  20. });

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

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

  1. const MemoryFS = require('memory-fs');
  2. const webpack = require('webpack');
  3. const fs = new MemoryFS();
  4. const compiler = webpack({ /* options*/ });
  5. compiler.outputFileSystem = fs;
  6. compiler.run((err, stats) => {
  7. // 之后读取输出:
  8. const content = fs.readFileSync('...');
  9. });

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

你指定的输出文件系统需要兼容 Node 自身的 fs 模块接口,接口需要提供 mkdirpjoin 工具方法。


贡献人员

byzyk byzyk rynclark rynclark sallar sallar