threads-plugin
Version:
Webpack plugin to bundle threads.js workers automagically.
105 lines (91 loc) • 3.74 kB
JavaScript
/**
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import * as Types from '@babel/types';
import path from 'path';
let ParserHelpers;
try {
ParserHelpers = require('webpack/lib/javascript/JavascriptParserHelpers'); // Webpack 5
} catch (e) {}
ParserHelpers = ParserHelpers || require('webpack/lib/ParserHelpers'); // Webpack 4
import WORKER_PLUGIN_SYMBOL from './symbol';
const NAME = 'WorkerPlugin';
const JS_TYPES = ['auto', 'esm', 'dynamic'];
const workerLoader = path.resolve(__dirname, 'loader.js');
export default class WorkerPlugin {
constructor (options) {
this.options = options || {};
this[WORKER_PLUGIN_SYMBOL] = true;
}
apply (compiler) {
let workerId = 0;
compiler.hooks.normalModuleFactory.tap(NAME, factory => {
for (const type of JS_TYPES) {
factory.hooks.parser.for(`javascript/${type}`).tap(NAME, parser => {
parser.hooks.new.for('imported var').tap(NAME, expr => {
if (expr.callee.name !== 'Worker') return false
const dep = parser.evaluateExpression(expr.arguments[0]);
if (!dep.isString()) {
parser.state.module.warnings.push({
message: 'new Worker() will only be bundled if passed a String.'
});
return false;
}
if (/^(https?:)?\/\//i.test(dep.string)) {
// Ignore absolute URL workers
return false;
}
const optsExpr = expr.arguments[1];
let typeModuleExpr = Types.objectProperty(
Types.identifier("type"),
Types.stringLiteral("module")
)
typeModuleExpr.range=[0, 0]
let opts = {};
if (optsExpr) {
opts = {};
for (let i = optsExpr.properties.length; i--;) {
const prop = optsExpr.properties[i];
if (prop.type === 'Property' && !prop.computed && !prop.shorthand && !prop.method) {
opts[prop.key.name] = parser.evaluateExpression(prop.value).string;
if (prop.key.name === 'type') {
typeModuleExpr = prop;
}
}
}
}
const loaderOptions = { name: opts.name || workerId + '' };
const req = `require(${JSON.stringify(workerLoader + '?' + JSON.stringify(loaderOptions) + '!' + dep.string)})`;
const id = `__webpack__worker__${workerId++}`;
ParserHelpers.toConstantDependency(parser, id)(expr.arguments[0]);
ParserHelpers.addParsedVariableToModule(parser, id, req);
});
});
}
});
compiler.hooks.afterEmit.tap(NAME, compilation => {
if (workerId === 0) {
compilation.warnings.push({
message:
'No instantiations of threads.js workers found.\n' +
'Please check that:\n' +
' 1. You have configured Babel / TypeScript to not transpile ES modules\n' +
' 2. You import `Worker` from `threads` where you use it\n\n' +
'For more details see: https://github.com/andywer/threads-plugin\n'
})
}
})
}
}