inline-worker-plugin.mjs
scripts/inline-worker-plugin.mjs · raw · all examples · site home
Exports: inlineWorkerPlugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
import esbuild from "esbuild";
import path from "node:path";
// `import Worker from "./file?worker&inline"` bundles file.ts as its own ESM
// bundle and exports a Worker subclass that runs it from a blob URL, so the
// page needs no separate worker files. `import code from "./file?module&inline"`
// bundles it the same way and exports its code as a string (for a blob URL
// that workers import). `define` is passed through to the bundle
// (RADIX_STATIC); `minify` for the production build.
export function inlineWorkerPlugin({ minify = false, define = {} } = {}) {
return {
name: "inline-worker",
setup(build) {
build.onResolve({ filter: /\?(worker|module)&inline$/ }, (args) => ({
path: path.resolve(args.resolveDir, args.path.replace(/\?(worker|module)&inline$/, "")),
namespace: "inline-worker",
pluginData: { kind: args.path.match(/\?(worker|module)&inline$/)[1] },
}));
build.onLoad({ filter: /.*/, namespace: "inline-worker" }, async (args) => {
const result = await esbuild.build({
entryPoints: [args.path],
bundle: true,
format: "esm",
platform: "browser",
minify,
define,
write: false,
metafile: true,
});
const code = result.outputFiles[0].text;
const watchFiles = Object.keys(result.metafile.inputs);
if (args.pluginData.kind === "module") {
return { contents: `export default ${JSON.stringify(code)};`, loader: "js", watchFiles };
}
return {
contents: [
`const workerCode = ${JSON.stringify(code)};`,
`const workerUrl = URL.createObjectURL(new Blob([workerCode], { type: "text/javascript" }));`,
"export default class InlineWorker extends Worker {",
" constructor(options = {}) {",
' super(workerUrl, { ...options, type: "module" });',
" }",
"}",
].join("\n"),
loader: "js",
watchFiles,
};
});
},
};
}