Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack plugin to modify files after compilation

I am writing a Webpack plugin that should replace a part of the JS code with a list of Webpack's generated CSS files. Imaging this JS code:

ReactWebComponent.create(<App />, 'react-web-component', { injectReactWebComponent: true });

I want to replace the injectReactWebComponent: true part with

injectReactWebComponent: '<link href="static/css/main.cacbacc7.css" rel="stylesheet">'

While that link tag is a file generated by Webpack.

My (kind of working) code for this goes as follows:

ReactWebComponent.prototype.apply = function(compiler) {
  compiler.plugin('emit', function(compilation, callback) {
    const cssFiles = Object.keys(compilation.assets)
        .filter(fileName => /\.css$/.test(fileName));

    const jsFiles = Object.keys(compilation.assets)
        .filter(fileName => /\.js$/.test(fileName));

    const cssLinkTagsAsString = cssFiles
        .map(fileName => `<link href="${fileName}" rel="stylesheet">`)
        .join('');

    jsFiles.forEach(fileName => {
      compilation.assets[fileName].children.forEach(child => {
        if (child._value) {
          child._value = child._value.replace(/injectReactWebComponent\s*:\s*true/g, `injectReactWebComponent: \'${cssLinkTagsAsString}\'`);
        }
      });
    });

    callback();
  });
};

module.exports = ReactWebComponent;

See the line where I do

child._value = child._value.replace(...)

I am bluntly rewriting the sources.

But this does not seem right for me. It seems the code I am transforming has already been generated and not ought to be transformed anymore. I am also pretty sure I am breaking the source maps with this.

So I am wondering, what would be an appropriate way to achieve what I am doing?

I am guessing for the transformation part I should use a loader, but then loaders do not know about the generated file names, or do they?

Any help would be appreciated!

like image 921
Lukas Avatar asked Aug 11 '17 22:08

Lukas


People also ask

What is CopyWebpackPlugin?

Disclaimer: CopyWebpackPlugin is a third-party package maintained by community members, it potentially does not have the same support, security policy or license as webpack, and it is not maintained by webpack. Copies individual files or entire directories, which already exist, to the build directory.

What's the difference between webpack loaders and plugins?

Loaders work at the individual file level during or before the bundle is generated. Plugins: Plugins work at bundle or chunk level and usually work at the end of the bundle generation process. Plugins can also modify how the bundles themselves are created.

What is webpack bundling?

Webpack is an aggressive and powerful module bundler for JavaScript applications. It packages all the modules in your application into one or more bundles (often, just one) and serves it to the browser.

What is the use of plugins in webpack?

A webpack plugin is a JavaScript object that has an apply method. This apply method is called by the webpack compiler, giving access to the entire compilation lifecycle.


1 Answers

It appears this sort of thing is simple enough to be handled by loaders, of which there are multiple (some better than others):

https://www.npmjs.com/package/string-replace-loader

https://www.npmjs.com/package/regexp-replace-loader

https://www.npmjs.com/package/replace-loader

If you want to go about making your own plugin to do this (I just went through the process to do something a bit more sophisticated than just regex replacement), I was able to piece my solution together from basically these three pages:

https://github.com/webpack/webpack/blob/master/lib/BannerPlugin.js

https://webpack.js.org/api/plugins/compilation/#optimize-chunk-assets-chunks-chunk-async

https://github.com/webpack/webpack-sources

like image 92
Benjamin Riggs Avatar answered Dec 07 '22 01:12

Benjamin Riggs