我正在开发一个webpack插件,无法弄清楚如何在构建期间修改模块。我想做什么:
目前我正在编译器上加入'this-compilation',然后在编译中加入'additional-chunk-assets'。抓住第一个块(目前唯一的一个,因为我还在开发中),遍历该块中的模块以找到我想要修改的块。然后:
看起来rebuildModule应该重新解析源代码,重新建立依赖关系等等,但它不会解析我的require语句并将它们更改为webpack需要。构建的文件包含我修改过的源代码,但require('...')语句未经修改。
如何让我修改的模块'更新',以便webpack将我添加的源视为与原始解析的源相同?除了rebuildModule()之外我还需要做些什么吗?我在构建过程中做得太晚了吗?或者我是以错误的方式去做的?
答案 0 :(得分:17)
我想出了如何以一种非常轻松的方式做到这一点。
我错了:
rebuildModule()
不是一个好主意,因为这会从头开始重新加载模块:文件的源被加载并传递给任何适用的加载器,以及{{1}的_source
属性该进程完成后,最终会重新分配对象。
module
实际上会很棒。然后我们就可以利用加载模块源时发生的sourceMap行为(见下文)我是如何运作的:
rebuildModule()
的'seal'插件,遍历编译的compilation
并找到你想要的那个module
重新解析模块:
module._source._value += extraCode;
解析来自NormalModule的module.parse.parse(module._source.source(), {
current: module,
module.module,
compilation: compilation,
options: compilation.options
});
方法,该方法在正常模块构建过程中加载源后会立即调用。
此实现将修改后的解析源转换为我的最终输出。由于NormalModuleMixin的build
方法中存在一些sourceMap内容,并且由于我在调用这些函数后添加到源代码,因此我假设sourceMap现在会搞乱。因此,下一步是让sourceMap反映代码添加。不确定是否尝试手动更新sourceMap或查看上面的想法,尝试动态应用加载器并调用rebuildModule()而不是解析。
如果您知道更好的方法,请告诉我们!
答案 1 :(得分:1)
我想到了另一个想法。如果在webpack编译之前做一些预处理怎么办?
此临时文件可以是虚拟文件。可以参考https://github.com/rmarscher/virtual-module-webpack-plugin/。
...如果您在构建时生成文件内容需要由源代码作为模块使用,但您不想将此文件写入磁盘。
答案 2 :(得分:1)
基于研究Webpack的官方插件(例如DefinePlugin
)如何修改模块代码的方法,我相信做到这一点的最佳方法是:
buildModule
,并以module.addDependency()
。compilation.dependencyTemplates.set()
注册依赖项模板。apply
方法中,使用source.replace()
或source.insert()
进行修改(其中source
是第二个参数)—请参阅ReplaceSource文档。就编译挂钩而言,模板在beforeChunkAssets之后立即被调用。以这种方式修改源将保留SourceMap。
const Dependency = require('webpack/lib/Dependency');
class MyDependency extends Dependency {
// Use the constructor to save any information you need for later
constructor(module) {
super();
this.module = module;
}
}
MyDependency.Template = class MyDependencyTemplate {
apply(dep, source) {
// dep is the MyDependency instance, so the module is dep.module
source.insert(0, 'console.log("Hello, plugin world!");');
}
};
module.exports = class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('MyPluginName', compilation => {
compilation.dependencyTemplates.set(
MyDependency,
new MyDependency.Template()
);
compilation.hooks.buildModule.tap('MyPluginName', module => {
module.addDependency(new MyDependency(module));
});
});
}
};