javascript - agrupar web workers como parte integral de un paquete npm con salida de archivo único de webpack
Estoy escribiendo un paquete npm que es un complemento para la popular biblioteca leafletjs. Estoy usando webpack para empaquetar el paquete. Quiero que este paquete pueda crear y destruir algunos web workers bajo demanda. El código del web worker es parte de mis archivos fuente. Pero quiero poder distribuir mi paquete tanto como un módulo npm, o a través de un CDN, lo que significa que debe ser compilado en un solo archivo que pueda ser incluido mediante un encabezado HTML. Estoy usando webpack para hacerlo. Así que digamos que tengo un archivo de worker:
// sample.worker.js
import { doSomeStuff } from './algorithm.js';
onmessage = function (e) {
const results = doSomeStuff(e.data)
postMessage({
id: e.data.id,
message: results',
});
};
Bastante simple, pero un punto importante aquí es que mi trabajador en realidad está importando algún código de un archivo de algoritmos, que a su vez está importando algunos módulos de node. Mi trabajador se usa en algún lugar del módulo principal, así:
// plugin.js
import SampleWorker from 'worker-loader!./workers/dem.worker.js';
export function plugin(){
// do some stuff
const worker = new SampleWorker()
worker.postMessage(someData);
worker.onmessage = (event) => {};
}
Mi configuración de webpack se ve así:
module.exports = {
entry: './src/index',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'my-plugin.js',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'],
},
module: {
rules: [
{
test: /\.worker\.js$/,
loader: 'worker-loader',
options: {
inline: 'fallback',
},
},
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
],
},
externals: { ... },
plugins: { ... }
};
Esto no funciona tal como está: webpack intenta empaquetar el paquete principal y cada archivo de script de trabajador bajo el mismo nombre. Cambiar a filename: '[name].js' bajo output soluciona este problema, pero me da muchos archivos: uno para el paquete principal y otro archivo para cada archivo de trabajador en mi código fuente.
Al leer las opciones de webpack, pensé que usar la opción inline: 'fallback' en realidad crearía un Blob para cada trabajador y lo incluiría en el archivo de salida principal. Eso no está sucediendo.
Hasta ahora, mi solución es escribir a mis trabajadores como blobs, así:
// workers.js
const workerblob = new Blob([`
// cannot import in a blob!
// have to put algorithm.js code here, copy in any external module code here
onmessage = function (e) {
const results = doSomeStuff(e.data)
postMessage({
id: e.data.id,
message: results,
});
};
`])
export const sampleWorker = URL.createObjectURL(workerblob);
// my-plugin.js
import { sampleWorker } from 'workers.js'
const worker = new Worker(sampleWorker)
Esto de hecho funciona: webpack ahora genera un único archivo que incluye el código del worker. Usando una versión modificada de esta respuesta, al menos puedo colocar mi código dentro de un formato function( ...code... ){}.toString(), así que al menos puedo obtener intellisense, resaltado de sintaxis, etc. Pero no puedo usar imports.
¿Cómo puedo usar webpack para agrupar mis workers de manera que todo el paquete termine en un solo archivo, incluyendo el código del worker?