Reputation: 3712
I'm writing a custom Webpack plugin that is supposed to modify some TypeScript source files and as a result, the dependencies between the files can change (e.g. an import to a file can be added or removed, as well as an import can be replaced by another import). I'm having issues with Webpack not picking up the new relationships between the files. The best I've got so far is that I can get it to pick up on some of the file changes, but it appears to be too late in the compilation's lifecycle and as a result the file content could be outdated. Here's a simplification of what I've got so far. I am confident that the logic that determines the newFiles
and hasDependencyOnFile
is correct:
class CustomWebpackPlugin {
apply(compiler) {
compiler.plugin('after-compile', (compilation, callback) => {
compilation.fileDependencies.push(...newFiles);
compilation.modules.forEach(module => {
if (hasDependencyOnFile(module.resource)) {
module.fileDependencies.push(...newFiles);
}
});
callback();
});
}
}
Is this the proper way to approach adding new entries to the dependency graph or does Webpack provide an API to do it correctly?
Upvotes: 1
Views: 1568
Reputation: 834
I have a similar problem to figure out recently. I tried injecting dependencies during compilation stage, but there are other dependencies and contexts I was not able to figure out soon. So instead I just update the source code by adding a new loader. In this loader, I use a JavaScript parser to get the information I need, then a prefix of import/require statements get created. This prefix gets added to the beginning of my legacy code, which doesn't have any of this kind of import/require dependencies.
Following is the sample code of the Webpack loader.
Using import statement will enforce strict mode in the compiled JavaScript. Using require will not enable strict mode, which is most likely helpful for legacy code.
module.exports = function(source) {
// parseDependencies is a function created to parse the source code and create the right import file path based on the file path level input parameter.
let filePath = this._module.userRequest;
let subPath = filePath.substring(process.cwd().length, filePath.length)
let level = (subPath.match(/\//g) || []).length - 5;
let importList = parseDependencies(source, level).map(f => {
...
});
return importList.join("\r\n") + source;
}
Upvotes: 1
Reputation: 35573
It is not enough to add a file as a dependency of other file, you need that the "other file" will require your added file, therefore, my suggestion is to use normal-module-loader
phase in order to add your custom loader that will add a require to you newFile
, then webpack will add that newFile
as a current dep.
Sample code:
compilation.plugin('normal-module-loader', (loaderContext, module) => {
// this will be called for every successfully built module, but before it's parsed and
// its dependencies are built. The built source is available as module._source.source()
if (...some condition on the module) {
module.loaders.push({loader: compiler.context+'/path/to/custom-loader.js'});
}
});
Upvotes: 0