worker-injector-generator-plugin
Version:
A very simple webpack plugin to generate injection code for workers that share common code with the main web build.
86 lines (75 loc) • 3.48 kB
JavaScript
// Making it be ES5, no need for fancy typescript
// we just use a function
/**
* Options include
* @param options.name the name of the generated file
* @param options.publicPath (optional) a public path to use, otherwise output.publicPath will be used
* @param options.importScripts the scripts to import as an array of string
* @param options.isAsync whether to use async code execution, not good for debugging
*/
function WorkerInjectorGeneratorPlugin(options) {
this.options = options;
}
function getActualPathToIncludeCode(pathToInclude, hash) {
// for that we are mapping
var actualPathToInclude = pathToInclude;
// and we need to make sure there is no trailing slash because we already
// have it in the publicPathToUse
if (actualPathToInclude[0] === "/") {
actualPathToInclude = actualPathToInclude.substr(1);
}
// we replace the [hash] with the hash that is generated by the compiler
actualPathToInclude = actualPathToInclude.replace(/\[hash\]/g, hash);
// now we return that and join it with commas
return "base+" + JSON.stringify(actualPathToInclude);
}
// this is where the magic happens
WorkerInjectorGeneratorPlugin.prototype.apply = function (compiler) {
// we extract the info from the options
var name = this.options.name;
var publicPathByOptions = this.options.publicPath;
var pathsToInclude = this.options.importScripts;
var isAsync = this.options.isAsync;
// now we call tapAsync
compiler.hooks.emit.tapAsync(this.constructor.name, function (compilation, callback) {
// we get the compiler info via the outputOptions such as the public path
var publicPathByCompilation = compilation.outputOptions.publicPath;
// now we go in order of priority
var publicPathToUse = publicPathByOptions || publicPathByCompilation || "/";
// we need to add the slash if it's not there
if (publicPathToUse[publicPathToUse.length - 1] !== "/") {
publicPathToUse += "/";
}
// we get the hash that is used for this compilation step
var hash = compilation.hash;
// now we generate the file content, pretty standard, first build the base url that will be
// the protocol + hostname + port (if available)
var fileContent = 'var base=location.protocol+"//"+location.host+' +
JSON.stringify(publicPathToUse) + ';window=self;';
if (isAsync) {
fileContent += 'function h(r){return r.text()};function e(m){Function(m)()};'
// now we add the window self line and the import scripts line
fileContent += pathsToInclude.map(function (pathToInclude) {
return 'fetch(' + getActualPathToIncludeCode(pathToInclude, hash) +
').then(h).then(e)'
}).join(";") + ";";
} else {
// now we add the window self line and the import scripts line
fileContent += 'self.importScripts(' + pathsToInclude.map(function (pathToInclude) {
return getActualPathToIncludeCode(pathToInclude, hash);
}).join(",") + ");";
}
// now we need the actual name, with the hash as well
var actualName = name.replace(/\[hash\]/g, hash);
// and generate a buffer from the content to feed the compilation steps
var Buf = Buffer.from(fileContent, 'utf8');
compilation.assets[actualName] = {
source: function () { return Buf },
size: function () { return Buffer.byteLength(fileContent) }
}
// and we are done
callback();
});
}
// export it :D
module.exports = WorkerInjectorGeneratorPlugin;