How to generate a module from the webpack plugin and replace it

I am trying to write a webpack plugin for https://github.com/martinandert/babel-plugin-css-in-js with the following 2 requirements during development:

  • I do not want the file to be written to disk, but instead the webpack-dev-server placed the file in memory.
  • I want a hot reload to load the newly extracted CSS.

(Questions below.)


Do not burn to disk

I was able to do this with the code as shown below, but after reading many different examples. I still do not feel 100% sure that this is the right way.

compiler.plugin('emit', function(compilation, callback) { compilation.chunks.forEach(function(chunk) { chunk.modules.forEach(function(module) { if (module.resource) { var css = extractCSSFromFile(module.resource) if (css) { cache[module.resource] = css } } }) }) var source = Object.values(cache).join('') compilation.assets[bundleFile] = { source: function() { return source }, size: function() { return source.length }, } }) 

Hot reboot

My thinking is that whenever CSS changes, I would submit a new version of a tiny module that causes the stylesheet to reload. Then I would have web packages. Replacement Hot Module Replace has replaced this module, so they have an HMR for the extracted stylesheet. This reboot module looks like this:

 if (module.hot) { module.hot.accept() module.hot.dispose(function() { document.querySelectorAll('link[href="' + WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_PATH + '"]').forEach(link => { link.href = link.href.replace(/(\?\d+)?$/, '?' + WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_HASH) }) }) } 

And the webpack plugin code for generating a hash file of the latest CSS looks like this:

 compiler.plugin('emit', function(compilation, callback) { // All of the previous code to extract the CSS... var source = Object.values(cache).join('') var sourceHash = crypto.createHash('md5').update(source).digest('hex') var cssReloader = path.basename(bundleFile, '.css') + '_webpack-reloader.js' var childCompiler = compilation.createChildCompiler('babel-css-in-js', { filename: cssReloader, }) childCompiler.apply( new SingleEntryPlugin( compiler.context, path.join(__dirname, 'webpack-babel-css-in-js-client-template.js'), path.join(publicPath, cssReloader)) ) childCompiler.apply( new webpack.DefinePlugin({ WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_PATH: JSON.stringify(path.join(publicPath, bundleFile)), WEBPACK_BABEL_CSS_IN_JS_STYLESHEET_HASH: JSON.stringify(sourceHash), }) ) // Completely cargo-culted from http://stackoverflow.com/a/38284256 // It is supposedly required for HMR to work. childCompiler.plugin('compilation', (compilation) => { if (compilation.cache) { if (!compilation.cache[cssReloader]) { compilation.cache[cssReloader] = {} } compilation.cache = compilation.cache[cssReloader] } }) childCompiler.runAsChild(function(err) { if (err) { callback(err) } callback() }) }) 

The problem, however, is that my JS reboot module is not being restored, which, I think, is due to the fact that the original source does not change, it will only change during compilation.


My questions are basically these:

  • Am I approaching this correctly? And do you know about the right examples that I should look at?
  • Alternatively, is there a way to compile a file without using an external input file, but completely from the source? That way, I can just re-generate the source and embed the hash myself, after which the web package should notice the difference and the HMR, right?
+5
source share

Source: https://habr.com/ru/post/1262241/


All Articles