Webpack child compiler configuration

I would like the build result of my webpack to be defined as a variable when compiling my worker.

I would like to use the functionality of child compilation to compile a service worker that fits in a different path. I need the output emitted from webpack compilation in order to properly compile a service worker.

My original game was to use the same strategy as the offline-plugin, where you create a child compiler, but I need to be able to change the output path for the worker. The work services path is important because it defines the scope.

I am wondering how to accomplish what I have below using a child API compiler to prevent such a side effect of my build (and hopefully this will give me support for webpack-dev-server.

var webpack = require('webpack'); function ServiceWorkerPlugin(options) { this.options = options; } ServiceWorkerPlugin.prototype.apply = function(compiler) { compiler.plugin('emit', (compilation, callback) => { const stats = compilation.getStats().toJson(); const child = webpack(this.options); child.apply( new webpack.DefinePlugin({ assets: stats.assets }) ); child.run((err, swStats) => { if (err) { callback(err); } const swStatsJson = swStats.toJson(); if(swStatsJson.errors.length > 0) { console.log(swStatsJson.errors); } if(swStatsJson.warnings.length > 0) { console.log(swStatsJson.warnings); } callback(); }); module.exports = ServiceWorkerPlugin; 
+5
source share
1 answer

First of all, everything you described is in the offline-plugin implementation, so now I will show you how I do it.

Things get a little more complicated in webpack when you need to use child compilation and compilation.assets in it. The problem is that the children’s compilation needs to be created in the complier.plugin('make') event, but compilation.assets are only available in the compiler.plugin('emit') event, which starts almost at the end of the compilation.

Here is a view of the template for implementing detailed compilation:

(note: the code is in ES2015 version)

 import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin'; export default class AwesomePlugin { constructor() { // Define compilation name and output name this.childCompilerName = 'awesome-plugin-compilation'; this.outputFileName = 'custom-file.js'; // To make child compiler work, you have to have a entry in the file system this.compilationEntry = 'entry-file.js'; } apply(compiler) { // Listen to `make` event compiler.plugin('make', (compilation, callback) => { // Creating child compiler with params const childCompiler = compilation.createChildCompiler(this.childCompilerName, { filename: this.outputFileName }); // Everyone plugin does this, I don't know why childCompiler.context = compiler.context; // Add SingleEntryPlugin to make all this work childCompiler.apply(new SingleEntryPlugin(compiler.context, this.compilationEntry, this.outputFileName)); // Needed for HMR. Even if your plugin don't support HMR, // this code seems to be always needed just in case to prevent possible errors childCompiler.plugin('compilation', (compilation) => { if (compilation.cache) { if (!compilation.cache[name]) { compilation.cache[name] = {}; } compilation.cache = compilation.cache[name]; } }); // Run child compilation childCompiler.runAsChild((err, entries, childCompilation) => { callback(err); }); }); } } 

This will make your record compiled into a separate file, which you can name as you like. Then you need to do some hacking manipulations with the compilation.assets on 'emit' event:

 compiler.plugin('emit', function(compilation, callback) { // Get our output asset const asset = compilation.assets[this.outputFileName]; // Delete delete our asset from output delete compilation.assets[this.outputFileName]; // Collect all output assets const assets = Object.keys(compilation.assets); // Combine collected assets and child compilation output into new source. // Note: `globalAssets` is global variable let source = ` var globalAssets = ${ JSON.stringify(assets) } ${ asset.source() } `; // Add out asset back to the output compilation.assets[this.outputFileName] = { source() { return source; }, size() { return Buffer.byteLength(source, 'utf8'); } }; }); 

EDIT: You may probably have some special place in the entry into which you want to insert the list of assets. But be careful if you use regular template syntax, then the JS loader will not be able to parse your file. So you can post something like this __INSERT_WEBPACK_ASSETS_DATA__ , and then use String#replace to replace it with actual data.

This is basically it. You should now be able to embed the variable with compilation.assets into the output file of your child compilation. Note that in offline-plugin I use the name of the fake compilation when I create it, and then rename it to the 'emit' event in the name of the real file. I don’t remember the exact reasons, but I remember that I had them. Thus, you may have to experiment with it yourself.

Here is the complete code for this template (with the events 'make' and 'emit' ): https://gist.github.com/NekR/f85d297fe4f1ea3c168827b305c13844

+6
source

All Articles