首页 > 解决方案 > 在构建时执行 NormalModule,加载器构建完成后,保存到 json 文件

问题描述

我正在编写一个插件,对于特定模块,它将尝试执行在构建时生成的模块,以便将结果保存到 json 文件中。

为此,我正在利用compilation.hooks.succeedModule,它接收NormalModule已经构建的对象。然后我试图评估替换 webpack 变量的源代码,例如__webpack_public_path__.

虽然它有点工作,但这种方法感觉非常错误。就像我错过了什么。

有没有一种很好的方法可以在构建时从具有对变量的基本访问权限的 NormalModule 对象执行模块,例如__webpack_public_path__?也许 Webpack 提供了一种更好的方法来做这些事情?

标签: javascriptnode.jswebpack

解决方案


好的,是的,听起来你可以用另一种方式解决这个问题,我已经做过类似的事情,我需要更改模块输出、将内容写入磁盘、触发副作用等。听起来你想要加载器而不是插件. ( https://www.npmjs.com/package/webpack-run-loaderrun-loader )执行它加载和导出的模块或返回结果。

您可以编写一个自定义加载程序,您可以将其链接到responsive-loader, 和之后运行run-loader,它从接收 JSONrun-loader并将其写入您想要它的磁盘(作为副作用),然后返回一个空字符串,以便没有任何内容添加到建造。最终结果是,在您的应用程序中需要此模块会(通过responsive-loader)创建您的图像文件,并将 JSON 写入您需要它的磁盘(通过您的自定义加载程序)。或者,您可以跳过run-loader并在您的自定义加载器中使用正则表达式从responsive-loader. 对项目依赖项生成的代码使用正则表达式似乎很脆弱,但只要您锁定了依赖项版本,它在实践中就可以正常工作,并且在概念上比添加run-loader到管道要简单一些。

如果你正在编写 webpack 插件,我想你也很乐意编写加载器,但如果不是,它们非常简单——只是一个函数,它接受来自之前加载器的源代码并返回代码,然后做任何你想做的事情想要介于两者之间。文档对 API 来说还不错,但是查看一些已发布加载器的源代码也很有帮助。它可能看起来粗略(只是从记忆中吐出)像:

// img-info-logging-loader.js
// regex version, expects source arg to be output of responsive-loader
import * as fs from 'fs';

export const imgInfoLoggingLoader = (source) => {
  const jsonFinderRegex = /someregexto(match)onsource/;
  const desiredJSON = source;
  const matchArr = jsonFinderRegex.exec(desiredJSON);
  if (!matchArr[1]) {
    throw new ReferenceError('json output not found in loader source.');
  } else {
    const imgConfigJsonString = matchArr[1];

    // you would write a fn to generate a filename based on the 
    // source, or based on the module's filename, which is available
    // via the webpack loader api
    const fileNameToWrite = getFileNameTowrite(); 

    try {
      // async might be preferable depending on your webpack 
      // performance needs
      fs.writeFileSync(fileNameToWrite, imgConfigJsonString); 
    } catch (err) {
      throw new Error(`error writing ${fileNameToWrite}`);
    }
  }

  // what the loader inserts into your JS asset: empty string
  return ''; 
}

编辑:由于根据您的评论,您希望输出一个包含所有图像信息的单个 JSON 对象,因此您需要一种稍微不同的方法来使用插件(这是我所知道的最优雅的方法,那里可能是其他人)。据我所知,当 webpack 完成加载模块时,插件是“做某事”的唯一方法。

  1. responsive-loader如上所述,您仍然需要一个自定义加载器,该加载器从 的输出中提取 JSON 。但是,它不会将每个都写入磁盘。相反,您的加载器将调用以下模块上的方法:
  2. 您还编写了json-collector.js一个小节点模块,用于保存您正在构建的 JSON 对象。这一点很尴尬,因为它与加载程序是分开的,但加载程序需要它。不过,这个收集器模块很简单,如果您想更简洁,可以将其转换为更通用的模块,并将其视为适当的独立节点依赖项。它只是一个具有添加 JSON 数据的方法的对象,该方法将其附加到内部 JSON 对象,以及用于读取收集的数据并返回 JSON 的方法。
  3. 然后你有一个挂钩到构建结束的插件(我认为有一个用于“构建密封”的插件,我已经使用过)。当到达那个钩子时,你知道 webpack 没有更多模块要加载,所以插件现在调用 'read' 方法json-collector,从中获取 JSON 对象并将其写入磁盘。

这个解决方案不适合 webpack 中的独立插件/独立加载器约定,但如果这不打扰你,它实际上非常简单,这三个部分中的每一个都有一个简单的工作要做。我已经多次使用这种模式,它对我有用。


推荐阅读