我正在编写一个应该可缓存的Webpack加载器。 documentation for this.cacheable
说:
当输入和依赖关系没有改变时,可缓存的加载器必须具有确定性结果。
现在我想知道:在这个意义上,加载器的选项是否算作“输入”?
假设我有一个Webpack构建,它在模块上使用带有选项{ foo: 1 }
的加载器。在下一次编译中,它在同一模块上使用相同的加载器,但使用选项{ foo: 2 }
。是否会重新使用第一个编译的输出,或者Webpack(正确)是否意识到加载器的选项已经改变,从而重新加载模块?
假设Webpack 比较options
个对象,它们如何比较?引用?使用深度比较?比较逻辑将决定我可以安全地使用什么类型的数据作为加载器选项。
答案 0 :(得分:1)
简短版:
Webpack通过其request
字符串标识模块。此字符串包含文件路径以及所有相关加载器的路径和选项。这实际上意味着更改一个加载器上的选项将导致不同的请求字符串,因此之前的加载结果将不会被重复使用。
长版:
请求字符串是"!" -separated,由this code创建。
考虑这个请求字符串:
"/Users/wolf/dev/webpack-test/test-loader.js!/Users/wolf/dev/webpack-test/patch-loader.js??ref--0-0!/Users/wolf/dev/webpack-test/src/foo.js"
这意味着(从右到左)首先使用带有选项/Users/wolf/dev/webpack-test/src/foo.js
的加载器/Users/wolf/dev/webpack-test/patch-loader.js
加载文件ref--0-0
,然后加载/Users/wolf/dev/webpack-test/test-loader.js
而不加任何选项
现在,相关问题是Webpack如何序列化加载器'创建请求字符串时的选项。答案可以找到in this code:
让loaderData
成为此形式的对象:
{
loader: string, // Path to loader
options: string | object | null | undefined,
ident: string | null | undefined
}
loaderData.options
是一个字符串,则按原样使用。loaderData.ident
是真实的,则使用此值。loaderData.options
使用JSON.stringify
进行字符串化。当加载程序specified statically时,Webpack知道他们的选项不会发生变化。因此,RuleSet.normalizeRule()
会为其分配固定的ident
属性。这就是上面示例中ref--0-0
发生的事情。
这里的一个关键见解是加载器选项应该是相当简单的对象,因此在它们上调用JSON.stringify
并不会丢失任何信息。否则,Webpack可能会无意中重新使用使用不同加载程序选项的缓存结果。或者,您可以将loaderData.ident
显式设置为唯一标识选项的字符串(例如哈希代码)。
答案 1 :(得分:0)
如果您更改了加载程序的输入,那么您实际上是在创建它的新实例,因此它不应该使用带有不同选项的加载程序中的缓存。
如果你看这里,它看起来只是设置一个标志,说明是否要求可缓存,并且由你来缓存结果。无论如何,它总是打电话给你的装载机。 https://github.com/webpack/loader-runner/blob/master/lib/LoaderRunner.js#L270